Detection de tores sous OpenCV
Voulant faire une core memory (un ancêtre des mémoires actuelles), je cherche et achète des petits tores de ferrites (non sans mal car peu commun).

Chaque tore fait 3mm de diamètre, il est sensé y en avoir 1000. Sachant que je veux savoir la taille maximale que ma core memory fera, il me faut connaitre le nombre exact de tores. Ce qui n’est pas faisable facilement à la main.
Analyse par ordinateur
L’idée est donc de prendre une photographie des tores à plat, afin d’utiliser un système d’analyse d’image et automatiser le comptage. L’avantage d’un tel système est qu’il sera réutilisable, si jamais j’achète d’autres lots un jour.

Premiers essais
La première idée qui me vient a l’esprit pour detecter des cercles… est d’utiliser une transformation de hough (hough circles).
Le processus pour appliquer une hough transform est de commencer par faire une detection de contours, avec le filtre de canny. Résultat non concluant, le detecteur loupe quasiement tous les tores… Un des problèmes est l’ombre au centre des tores, qui déforme beaucoup trop les disques intérieurs.
J’essaye d’autres detections de contours et pre-processing de l’image pour essayer de corriger le problème, toujours convaincu que la hough transform est la solution, mais cela sans succès.
Detection de blobs
Après quelques recherches, il semblerait que le moyen le plus efficace de detecter ce genre de cercles intérieurs soit un detecteur de blobs. Un des gros avantages du detecteur de blobs d’OpenCV est qu’il est très fournis en paramètres. Cela permet d’ajuster rapidement la recherche, pour qu’elle colle au résultat attendu.
using namespace cv;
Mat im = imread("input.jpg", IMREAD_GRAYSCALE);
GaussianBlur(im, im, Size(3, 3), 0.6, 0.6);
SimpleBlobDetector::Params params;
params.thresholdStep = 1;
params.minThreshold = 50;
params.maxThreshold = 220;
params.minRepeatability = 2;
params.minDistBetweenBlobs = 10;
params.filterByColor = true;
params.blobColor = 255;
params.filterByArea = true;
params.minArea = 55;
params.maxArea = 200;
params.filterByCircularity = true;
params.minCircularity = 0.8f;
params.maxCircularity = std::numeric_limits<float>::max();
params.filterByInertia = false;
params.minInertiaRatio = 0.1f;
params.maxInertiaRatio = std::numeric_limits<float>::max();
params.filterByConvexity = true;
params.minConvexity = 0.95f;
params.maxConvexity = std::numeric_limits<float>::max();
cv::Ptr<cv::SimpleBlobDetector> detector
= cv::SimpleBlobDetector::create(params);
// Detect blobs.
std::vector<KeyPoint> keypoints_in, keypoints;
detector->detect(im, keypoints_in);
keypoints = keypoints_in;
// Draw detected blobs as red circles
Mat im_with_keypoints;
drawKeypoints(im, keypoints, im_with_keypoints, Scalar(0,0,255),
DrawMatchesFlags::DRAW_RICH_KEYPOINTS );
std::cout << keypoints.size() << std::endl;
imwrite("out.png", im_with_keypoints);
Résultat: le logiciel detecte 1082 cores. Ce qui va permettre de faire une core memory de 32x32.

La detection de blobs OpenCV.
On remarquera que deux tores n’ont pas été detectés.