Détection d'un cercle dans les données d'images bruyantes

17

J'ai une image qui ressemble à celle ci-dessous: entrez la description de l'image ici

J'essaie de trouver le rayon (ou le diamètre) du cercle. J'ai essayé d'utiliser la transformation circulaire de Hough (via matlab imfindcircles(bw,[rmin rmax],'ObjectPolarity','bright')), et en s'adaptant à un cercle ou une ellipse (fonction maison qui fonctionne plutôt bien pour des données moins bruyantes, voir ci-dessous).

J'ai également essayé un traitement d'image pour obtenir un cercle plus clair, par exemple, voir ci-dessous:

se = strel('disk', 2);
bw = imdilate(bw, se);
bw = bwareaopen(bw,100000); 
bw =  edge(bw); 

entrez la description de l'image ici

Cependant, lorsque j'alimente l'image traitée à l'une ou l'autre des techniques (ajustement de Hough et cercle \ ellipse), aucune d'entre elles ne parvient à détecter le cercle de manière décente.

Voici un extrait de code du chercheur de cercle que j'ai écrit (matlab) [row col] = find (bw); contour = bwtraceboundary (bw, ligne (1), col (1)], 'N', connectivité, num_points);

    x = contour(:,2);
    y = contour(:,1);

    % solve for parameters a, b, and c in the least-squares sense by
    % using the backslash operator
    abc = [x y ones(length(x),1)] \ -(x.^2+y.^2);
    a = abc(1); b = abc(2); c = abc(3);

    % calculate the location of the center and the radius
    xc = -a/2;
    yc = -b/2;
    radius  =  sqrt((xc^2+yc^2)-c);

Des approches alternatives seront appréciées ...

bla
la source
Hough transform recherche un cercle, pas un disque rempli. vous devez d'abord effectuer une détection des bords pour convertir le disque rempli en un cercle vide. quelles sont les propriétés de vos cercles? la taille est-elle constante? peuvent-ils être des ellipses? les points peuvent-ils être distribués différemment?
endolith
J'ai essayé (voir l'exemple édité), c'est trop bruyant ou pas assez circulaire? De plus, la taille est constante et elle peut présenter une ellipticité infime (bien qu'en réalité il s'agit d'une fenêtre parfaitement circulaire) en raison d'une erreur d'angle de caméra.
bla
si la taille et la forme sont constantes, vous pouvez essayer quelque chose comme la corrélation croisée d'un modèle de disque rempli avec l'image de point d'origine
endolith
À côté de ma réponse, je pense que vous essayez peut-être de le faire à un stade trop avancé de votre traitement d'image. Pourriez-vous nous en dire plus sur le problème et montrer quelques étapes précédentes?
Andrey Rubshtein

Réponses:

13

Voici ma solution, elle est proche de l'idée de @ Yoda, mais j'ai changé quelques étapes.

  • Marquez tous les pixels de sorte qu'il y ait au moins 6 pixels dans leur voisinage 7x7
  • Supprimez tous les blobs, mais le plus gros
  • Remplissez les trous
  • Appliquer la détection des bords
  • Rechercher un cercle à l'aide de la transformation de Hough

entrez la description de l'image ici entrez la description de l'image ici entrez la description de l'image ici entrez la description de l'image ici entrez la description de l'image ici

Voici le code Matlab pertinent. J'utilise Hough transform pour les cercles .m fichier dans mon code.

function FindCircle()
    close all;
    im = imread('C:\circle.png');
    im = im(:,:,2);

    ims = conv2(double(im), ones(7,7),'same');
    imbw = ims>6;
    figure;imshow(imbw);title('All pixels that there are at least 6 white pixels in their hood');

    props = regionprops(imbw,'Area','PixelIdxList','MajorAxisLength','MinorAxisLength');
    [~,indexOfMax] = max([props.Area]);
    approximateRadius =  props(indexOfMax).MajorAxisLength/2;

    largestBlobIndexes  = props(indexOfMax).PixelIdxList;
    bw = false(size(im));
    bw(largestBlobIndexes) = 1;
    bw = imfill(bw,'holes');
    figure;imshow(bw);title('Leaving only largest blob and filling holes');
    figure;imshow(edge(bw));title('Edge detection');

    radiuses = round ( (approximateRadius-5):0.5:(approximateRadius+5) );
    h = circle_hough(edge(bw), radiuses,'same');
    [~,maxIndex] = max(h(:));
    [i,j,k] = ind2sub(size(h), maxIndex);
    radius = radiuses(k);
    center.x = j;
    center.y = i;

    figure;imshow(edge(bw));imellipse(gca,[center.x-radius  center.y-radius 2*radius 2*radius]);
    title('Final solution (Shown on edge image)');

    figure;imshow(im);imellipse(gca,[center.x-radius  center.y-radius 2*radius 2*radius]);
    title('Final solution (Shown on initial image)');

end
Andrey Rubshtein
la source
1
Que fait ici la transformation de Hough qui la fait résoudre et trouver le cercle bleu? Projette-t-il de nombreux cercles de rayons différents à différentes positions sur l'image et trouve-t-il celui qui correspond le mieux?
Spacey
@Mohammad, c'est le détecteur de cercle habituel. Il utilise le binning et le vote.
Andrey Rubshtein
Vous pouvez également utiliser Fast Radial Symmetry Transform (FRST) après la première étape de cette réponse.
Geniedesalpages
10

Il est assez simple de le faire en utilisant le traitement d'image. Ce qui suit est une preuve de concept dans Mathematica . Vous devrez le traduire dans MATLAB.

  • Commencez par découper les axes et n'en conserver que la partie image. J'appelle cette variableimg .
  • Binarisez l'image et dilatez-la, suivie d'une transformation de remplissage. Je supprime également les petits composants parasites qui ne sont pas connectés au blob principal. Cela devrait vous donner quelque chose comme ceci:

    filled = Binarize@img ~Dilation~ 3 // FillingTransform // DeleteSmallComponents
    

  • Ensuite, trouvez le centroïde de ce blob et le rayon de disque équivalent du blob (openCV, MATLAB ont tous des commandes équivalentes pour le faire)

    {center, radius} = 1 /. ComponentMeasurements[filled, {"Centroid", "EquivalentDiskRadius"}]
    
  • C'est ça! Tracez maintenant l'image d'origine et un cercle avec le centre et le rayon ci-dessus pour voir comment elle s'adapte:

    Show[img, Graphics[{Red, Circle[center, radius]}]]
    

Lorem Ipsum
la source
Réponse géniale! Pouvez-vous développer la transformation de dilatation et de remplissage?
Spacey
@Mohammad Dilatation est une opération de base et serait facilement expliquée par l'article wiki. La transformation de remplissage remplit des "trous" ou en d'autres termes, des ensembles de pixels qui sont entourés de pixels de valeur supérieure. Voir la section "Plus d'informations" ici
Lorem Ipsum
Ah désolé, j'ai mal tapé. Je suis un peu familier avec la transformation de dilatation, je me demandais en fait si vous pouviez développer la "transformation de remplissage". Quel ensemble de règles utilise-t-il exactement? Je n'arrive pas à trouver des informations à ce sujet. Peut-être qu'il porte un autre nom?
Spacey
@yoda, merci pour la réponse, mais si vous lisez la question, vous remarquerez que j'ai essayé la dilatation et l'ajustement. L'image produite avant de détecter les bords est similaire à la vôtre. Je m'entraîne, ce n'est pas exact. La même chose est pour votre ajustement, vous pouvez voir que la partie supérieure du cercle ajusté est trop grande, probablement parce que vous prenez en compte le point bruyant sur la partie supérieure au-dessus du cercle. J'ai également essayé d'ajuster une ellipse (comme indiqué dans la question), le problème est que l'ajustement n'est pas assez bon. Je pense que la meilleure façon serait d'utiliser la meilleure partie du cercle (un arc) pour faire l'ajustement.
bla
@nate, je ne comprends pas ce que vous entendez par "partie supérieure du cercle ajusté" et "meilleure partie du cercle". Vous pouvez utiliser différentes métriques ... boîte englobante, longueur du grand axe, longueur du petit axe, distance moyenne du centroïde, distance médiane du centroïde, etc. Tout dépend de ce que vous voulez.
Lorem Ipsum