Remplir les trous dans OpenCV [dupliquer]

cette question a déjà une réponse ici:

  • remplir des trous à l'intérieur d'un objet binaire 7 réponses

j'ai une carte de bord extraite du module de détection de bord dans OpenCV (détection de bord canny). Ce que je veux, c'est combler les trous de la carte.

j'utilise c++ , et OpenCV bibliothèques. Dans OpenCV il y a une fonction cvFloodFill () , et il va remplir les trous avec une graine (avec un de l'emplacement pour commencer à inonder). Cependant, j'essaie de combler tous les trous intérieurs sans connaître les graines.(similaire à imfill () in MATLAB)

T1: comment trouver toutes les des graines, pour que je puisse appliquer 'cvFloodFill ()'?

Q2: comment mettre en œuvre un équivalent 'imfill ()'?

Newbie dans OpenCV, et tout conseil est le bienvenue.

32
demandé sur Amro 2009-11-11 19:19:04

9 réponses

selon la documentation de imfill dans MATLAB:

BW2 = imfill(BW,'holes');

remplit des trous dans l'image binaire BW . Un trou est un ensemble de pixels du fond qui ne peut être atteint par le remplissage d'arrière-plan à partir du bord de l'image.

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

exemple MATLAB:

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

34
répondu Amro 2017-05-19 21:48:55

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

voici un bref exemple cvDrawContours (IplImage, contours, color, color, -1, CV_FILLED, 8 );

Voici la documentation

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

je suppose que vous avez posté ceci un long il y a le temps, 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

12
répondu NotNamedDwayne 2012-11-03 14:21:48

j'ai cherché sur internet une fonction imfill (comme celle de Matlab) mais travaillant en C++ avec OpenCV. Après quelques explications, 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 ceci: image binaire originale

résultat: image binaire finale

le truc est dans le paramétrage des cvDrawContours fonction: cvDrawContours (dst, contour, white, white, 0, CV_FILLED);

  • dst = image de destination
  • contour = pointeur vers le premier contour
  • blanc = couleur utilisée pour remplir le contour
  • 0 = Niveau Maximal pour les contours tracés. Si 0, seul le contour est dessiné
  • CV_FILLED = Épaisseur des lignes, les contours sont dessinés avec de la. Si elle est négative (par exemple, = CV_FILLED), les intérieurs de contour sont dessinés.

plus d'informations dans la documentation openCV.

il y a probablement un moyen d'obtenir" dst " directement comme une image binaire, mais je n'ai pas pu trouver comment utiliser la fonction cvDrawContours avec des valeurs binaires.

7
répondu Jeremy.S 2017-08-09 12:14:37

j'ai fait une fonction simple qui est équivalente à imfill('trous') de matlab. Je n'ai pas testé de nombreux cas, mais il a fonctionné jusqu'à présent. Je l'utilise sur des images de bord mais il accepte tout type d'image binaire, comme une opération de battage.

un trou n'est rien de plus qu'un ensemble de pixels qui ne peut pas être "atteint" lorsque le fond est rempli ,donc

void fillEdgeImage(cv::Mat edgesIn, cv::Mat& filledEdgesOut) const
{
    cv::Mat edgesNeg = edgesIn.clone();

    cv::floodFill(edgesNeg, cv::Point(0,0), CV_RGB(255,255,255));
    bitwise_not(edgesNeg, edgesNeg);
    filledEdgesOut = (edgesNeg | edgesIn);

    return;
}

voici un exemple de résultat

enter image description here

6
répondu Pedro Batista 2014-03-05 16:34:20

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 autrement
  2. trouvez le premier 0 le long d'un côté de votre image de bord, et initiez un débordement de 1 à ce point sur une image vierge en utilisant votre image de bord comme masque. (Nous espérons ici que nous n'avons pas eu de malchance et semé ce premier remplissage à l'intérieur d'une forme qui est à moitié hors de l'écran)
  3. cette nouvelle image inondée est l '"arrière-plan". N'importe quel pixel ici qui a un 1 est le fond, et n'importe quel pixel qui a un 0 est le premier plan.
  4. boucle à travers l'image et trouver tous les pixels de premier plan. Ensemencez un tas de fumier sur ceux que vous trouverez.
  5. ou cette nouvelle image inondée avec votre image rusée de l'étape 1, et c'est fini.
4
répondu rcv 2010-01-26 18:41:30

Juste une annexe pour les Amro de réponse.

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;
    }
}
3
répondu Tae-Sung Shin 2017-05-23 12:10:40

avez-vous essayé de ContourFinding au-dessus de L'Image Cannyied?

cvFindContours crée une sorte d'arbre dans lequel les comtours extérieurs sont parents aux contours intérieurs ('trous'). Voir contours.py échantillon. Des contours on pouvait extraire des graines

2
répondu dnul 2009-11-22 16:07:52

récemment, je suis aussi en train de trouver la solution à ce problème. Ici, j'ai mis en œuvre Amro l 'idée comme suit:

#include <iostream>
using namespace std;
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
using namespace cv;

int main()
{
    IplImage *im = cvLoadImage("coin.png",CV_LOAD_IMAGE_ANYDEPTH);
    IplImage *hole = cvCreateImage(cvSize(im->width,im->height),8,1);
    cvShowImage("Original",im);

    cvCopyImage(im,hole);
    cvFloodFill(hole,cvPoint(0,0),cvScalar(255));
    cvShowImage("Hole",hole);
    cvSaveImage("hole.png",hole);

    cvNot(hole,hole);
    cvAdd(im,hole,im);
    cvShowImage("FillHole",im);
    cvSaveImage("fillHole.png",im);

    cvWaitKey(0);
    system("pause");
    return 0;
} 

J'espère que ce sera utile.

2
répondu Bill Xia 2017-05-23 12:10:40

si vous avez les points des bords, vous pouvez utiliser fillConvexPoly() ou fillPoly () (si poly non convexe).

une façon d'obtenir les points des bords est de faire findContours() -> approxPolyDP () .

0
répondu Rui Marques 2012-10-04 09:17:14