33 votes

Remplissez les trous dans OpenCV

J'ai un avantage carte extraite de bord module de détection dans OpenCV (savant de détection de contours). Ce que je veux faire est de remplir les trous dans le bord de la carte.

Je suis à l'aide de C++, et OpenCV bibliothèques. Dans OpenCV il y a un cvFloodFill() de la fonction, et il permettra de combler les trous avec des semences (avec celui de l'emplacement de départ de l'inondation). Cependant, je suis en train de remplir tous les trous intérieurs sans savoir que les graines.(similaire à imfill() dans MATLAB)

Q1: comment trouver toutes les graines, afin que je puisse l'appliquer 'cvFloodFill()'?
Q2: comment mettre en place une " imfill()' équivalent?

Débutant dans la OpenCV, et tout conseil est le bienvenue.

34voto

Amro Points 72743

Selon la documentation de l' imfill dans MATLAB:

BW2 = imfill(BW,'holes');
%# fills holes in the binary image BW. A hole is a set
%# of background pixels that cannot be reached by filling in the background
%# from the edge of the image.

Par conséquent, pour obtenir les "trous" de pixels, faire un appel à l' cvFloodFill avec le coin gauche du pixel de l'image comme une graine. Vous obtenez les trous en complétant l'image obtenue à l'étape précédente.

MATLAB Exemple:

BW = im2bw( imread('coins.png') );
subplot(121), imshow(BW)

%# used here as if it was cvFloodFill
holes = imfill(BW, [1 1]);       %# [1 1] is the starting location point

BW(~holes) = 1;                  %# fill holes
subplot(122), imshow(BW)

screenshot1

screenshot2

12voto

NotNamedDwayne Points 405

le cvDrawContours fonction a une option pour remplir les contours que vous avez dessiné.

Voici un court exemple cvDrawContours( IplImage, des contours, des couleurs, des couleurs, -1, CV_FILLED, 8 );

Voici la documentation

http://opencv.willowgarage.com/documentation/drawing_functions.html?highlight=cvdrawcontours#cvDrawContours

Je suppose que vous avez posté il y a longtemps, mais j'espère que cela aide quelqu'un.

C'est le code source (en C#):

        Image<Gray, byte> image = new Image<Gray, byte>(@"D:\final.bmp");
        CvInvoke.cvShowImage("image 1", image);

        var contours = image.FindContours();
        while (contours != null)
        {
            CvInvoke.cvDrawContours(image, contours, new Gray(255).MCvScalar, new Gray (255).MCvScalar, 0, -1, Emgu.CV.CvEnum.LINE_TYPE.CV_AA, new DPoint(0, 0));
            contours = contours.HNext;
        }
        CvInvoke.cvShowImage("image 2", image);

Result

8voto

Jeremy.S Points 41

J'ai été la recherche autour de l'internet pour trouver un bon imfill fonction (comme celui de Matlab) mais travaillant en C++ avec OpenCV. Après quelques reaserches, 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: d'Origine de l'Image Binaire

Résultat: Finale de l'Image Binaire

Le truc, c'est le réglage des paramètres de la cvDrawContours fonction: cvDrawContours( dst, contour, blanc, blanc, 0, CV_FILLED);

  • dst = image de destination
  • contour = pointeur vers le premier contour
  • blanc = la couleur utilisée pour remplir le contour
  • 0 = niveau Maximal pour dessiner des contours. Si 0, seul le contour est dessiné
  • CV_FILLED = Épaisseur des lignes, les contours sont dessinés avec de la. S'il est négatif (Par exemple, =CV_FILLED), le contour intérieur est établi.

Plus d'infos dans la openCV documentation.

Il y a probablement un moyen d'obtenir "heure d'été" directement comme une image binaire, mais je ne pouvais pas trouver comment utiliser les cvDrawContours fonction avec des valeurs binaires.

4voto

Boatzart Points 1650

Voici une approche rapide et sale:

  1. Effectuer futé sur votre image d'entrée de sorte que la nouvelle image binaire a 1 sur les bords, et 0 sinon
  2. Trouver le premier 0 le long d'un côté de votre bord de l'image, et de lancer un diffuseur avec 1 est à ce point sur une image vide à l'aide de votre bord de l'image du masque. (Nous sommes ici en espérant que nous n'avons pas eu la malchance d'être de la graine de ce premier remplissage à l'intérieur d'une forme qui est à moitié hors de l'écran)
  3. Cette nouvelle floodfilled image est la "toile de fond". Tout pixel ici, qui a une 1 est l'arrière-plan, et un pixel qui a un 0 est au premier plan.
  4. Boucle au travers de l'image et de trouver tous les pixels d'avant-plan. Graine un diffuseur sur tout ce que vous avez à trouver.
  5. OU cette nouvelle floodfilled image avec votre Futés de l'image à partir de l'étape 1, et vous avez terminé.

3voto

david Points 1809

Juste une annexe pour la réponse d' Amro.

 void cvFillHoles(cv::Mat &input)
{
    //assume input is uint8 B & W (0 or 1)
    //this function imitates imfill(image,'hole')
    cv::Mat holes=input.clone();
    cv::floodFill(holes,cv::Point2i(0,0),cv::Scalar(1));
    for(int i=0;i<input.rows*input.cols;i++)
    {
        if(holes.data[i]==0)
            input.data[i]=1;
    }
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X