web-dev-qa-db-fra.com

Remplissage des trous dans un objet binaire

J'ai un problème avec les trous blancs dans les pièces noires pour ne pouvoir avoir que 0-255 images binaires avec des pièces noires remplies. J'ai utilisé un filtre médian pour y parvenir, mais dans ce cas, le pont de connexion entre les pièces croît et devient impossible de les reconnaître après plusieurs fois d'érosion ... J'ai donc besoin d'un simple floodFill, comme méthode in opencv

Voici mon image avec des trous:

enter image description here

EDIT: floodfill like function doit combler les trous dans les gros composants sans afficher les coordonnées X, Y sous forme de ...

EDIT: J'ai essayé d'utiliser la fonction cvDrawContours mais je ne remplis pas les contours à l'intérieur des plus gros.

Voici mon code:

        CvMemStorage mem = cvCreateMemStorage(0);
        CvSeq contours = new CvSeq();
        CvSeq ptr = new CvSeq();
        int sizeofCvContour = Loader.sizeof(CvContour.class);

        cvThreshold(gray, gray, 150, 255, CV_THRESH_BINARY_INV);

        int numOfContours = cvFindContours(gray, mem, contours, sizeofCvContour, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
        System.out.println("The num of contours: "+numOfContours); //prints 87, ok

        Random Rand = new Random();
        for (ptr = contours; ptr != null; ptr = ptr.h_next()) {
            Color randomColor = new Color(Rand.nextFloat(), Rand.nextFloat(), Rand.nextFloat());
            CvScalar color = CV_RGB( randomColor.getRed(), randomColor.getGreen(), randomColor.getBlue());
            cvDrawContours(gray, ptr, color, color, -1, CV_FILLED, 8);
        }
        CanvasFrame canvas6  = new CanvasFrame("drawContours");
        canvas6.showImage(gray);

Résultat: (vous pouvez voir des trous noirs à l'intérieur de chaque pièce)

enter image description here

27
Zaur Guliyev

Il existe deux méthodes pour cela:

1) Remplissage du contour:

Commencez par inverser l'image, recherchez des contours dans l'image, remplissez-la de noir et inversez en arrière.

des = cv2.bitwise_not(gray)
contour,hier = cv2.findContours(des,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_SIMPLE)

for cnt in contour:
    cv2.drawContours(des,[cnt],0,255,-1)

gray = cv2.bitwise_not(des)

Image résultante:

enter image description here

2) Ouverture de l'image:

kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,3))
res = cv2.morphologyEx(gray,cv2.MORPH_OPEN,kernel)

L'image résultante comme suit:

enter image description here

Vous pouvez voir, il n'y a pas beaucoup de différence dans les deux cas.

NB: grey - image en niveaux de gris, tous les codes sont en OpenCV-Python

40
Abid Rahman K

Un simple dilatage et érosion comblerait assez bien les lacunes, j'imagine. Je pense que c'est peut-être ce que vous cherchez.

Une solution plus robuste consisterait à effectuer une détection de bord sur l’ensemble de l’image, puis à effectuer une transformation approximative pour les cercles. Un rapide Google indique qu'il existe des exemples de code disponibles dans différentes langues pour la détection invariante de la taille des cercles à l'aide d'une transformation hough, donc j'espère que cela vous donnera quelque chose à ajouter.

L'avantage d'utiliser la transformation hough est que l'algorithme vous donnera une estimation de la taille et de l'emplacement de chaque cercle, ce qui vous permettra de reconstruire une image idéale en fonction de ce modèle. Les chevauchements doivent également être très robustes, surtout si l’on considère la qualité de l’image d’entrée ici (c’est-à-dire que vous craignez moins les faux positifs, vous pouvez donc abaisser le seuil de résultats).

5
Elias Vasylenko

Vous êtes peut-être à la recherche de la transformation Fillhole , une application de la reconstruction d'images morphologiques.

Cette transformation comblera les trous dans vos pièces, même si cela entraîne également le remplissage de tous les trous entre des groupes de pièces adjacentes. L'espace de Hough ou les solutions basées sur l'ouverture suggérées par les autres affiches vous donneront probablement de meilleurs résultats de reconnaissance de haut niveau.

4
thiton

J'ai cherché sur Internet pour trouver la fonction imfill appropriée (comme celle de Matlab), mais travaillant en C avec OpenCV. Après quelques recherches, j'ai finalement trouvé une solution: 

IplImage* imfill(IplImage* src)
{
    CvScalar white = CV_RGB( 255, 255, 255 );

    IplImage* dst = cvCreateImage( cvGetSize(src), 8, 3);
    CvMemStorage* storage = cvCreateMemStorage(0);
    CvSeq* contour = 0;

    cvFindContours(src, storage, &contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
    cvZero( dst );

    for( ; contour != 0; contour = contour->h_next )
    {
        cvDrawContours( dst, contour, white, white, 0, CV_FILLED);
    }

    IplImage* bin_imgFilled = cvCreateImage(cvGetSize(src), 8, 1);
    cvInRangeS(dst, white, white, bin_imgFilled);

    return bin_imgFilled;
}

Pour cela: Image binaire originale

Le résultat est: Image binaire finale

L'astuce consiste à définir les paramètres de la fonction cvDrawContours: CvDrawContours (dst, contour, white, white, 0, CV_FILLED);

  • dst = image de destination
  • contour = pointeur sur le premier contour
  • blanc = couleur utilisée pour remplir le contour
  • 0 = niveau maximal pour les contours dessinés. Si 0, seul le contour est dessiné
  • CV_FILLED = Epaisseur des lignes avec lesquelles les contours sont dessinés. S'il est négatif (par exemple, = CV_FILLED), les intérieurs de contour sont dessinés.

Plus d'informations dans la documentation openCV.

Il existe probablement un moyen d'obtenir "dst" directement sous forme d'image binaire, mais je n'ai pas trouvé comment utiliser la fonction cvDrawContours avec des valeurs binaires. 

1
Jeremy.S

Essayez d’utiliser cvFindContours () function. Vous pouvez l'utiliser pour trouver des composants connectés. Avec les bons paramètres, cette fonction renvoie une liste avec les contours de chaque composant connecté.

Trouvez les contours qui représentent un trou. Ensuite, utilisez cvDrawContours () pour remplir le contour sélectionné par la couleur de premier plan, fermant ainsi les trous.

1
bubble

Je pense que si les objets sont touchés ou encombrés, il y aura quelques problèmes d'utilisation des contours et de l'ouverture de la morophologie mathématique. Au lieu de cela, la solution simple suivante est trouvée et testée. Cela fonctionne très bien, et pas seulement pour ces images, mais aussi pour toute autre image.

voici les étapes (optimisées) comme indiqué dans http://blogs.mathworks.com/steve/2008/08/05/filling-small-holes/

laissez I: l'image d'entrée

1. filled_I = floodfill(I). // fill every hole in the image.
2. inverted_I = invert(I)`.   
3. holes_I = filled_I AND inverted_I. // finds all holes 
4. cc_list = connectedcomponent(holes_I) // list of all connected component in holes_I.
5. holes_I = remove(cc_list,holes_I, smallholes_threshold_size) // remove all holes from holes_I having size > smallholes_threshold_size.
6. out_I = I OR holes_I. // fill only the small holes.

En bref, l’algorithme consiste simplement à rechercher tous les trous, à supprimer les plus gros, puis à écrire les plus petits uniquement sur l’image originale.

1
Faroq Al-tam

Si quelqu'un recherche l'implémentation cpp - 

            std::vector<std::vector<cv::Point> > contours_vector;

            cv::findContours(input_image, contours_vector, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);

            cv::Mat contourImage(input_image.size(), CV_8UC1, cv::Scalar(0));
            for ( ushort contour_index = 0; contour_index < contours_vector.size(); contour_index++) {
                cv::drawContours(contourImage, contours_vector, contour_index, cv::Scalar(255), -1);
            }

            cv::imshow("con", contourImage);
            cv::waitKey(0);

 enter image description here

 enter image description here

0
infoclogged