Filling holes inside a blob

I have a problem filling white holes inside black coins so that I can only have a 0-255 binary image with black coins filled .. I used a median filter to execute it, but in this case the connecting bridge between coins grows and it becomes impossible recognize them after eroding several times ... So I need a simple flood fill method in opencv

Here's my picture with holes:

enter image description here

EDIT: Fill fill function should fill holes with large components without asking for X, Y coordinates as seed ...

EDIT: I tried to use the cvDrawContours function, but I am not filling the contours inside the large ones.

Here is my 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);

      

Result: (you can see black holes inside each coin)

enter image description here

+24


source to share


6 answers


There are two ways to do this:

1) Filling the contours:

First, invert the image, find the outlines in the image, fill it with black, and invert back.

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)

      

Resulting image:

enter image description here



2) Opening an image:

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

      

The resulting image looks like this:

enter image description here

You can see that there is not much difference in both cases.

NB : gray-gray image, all codes are in OpenCV-Python

+36


source


I just think that simple branching and erosion closes the gaps well enough. I think maybe this is what you are looking for.

A more robust solution would be to do edge detection on the entire image and then convert the crunch for circles. A quick google shows that there are code examples available in different languages ​​for determining the size invariance of circles using the hough transformation, so hopefully this will give you something to continue.



The advantage of using the hough transform is that the algorithm will actually give you an estimate of the size and location of each circle, so you can reconstruct the perfect image based on that model. It should also overlap very reliably, especially considering the quality of the input image here (i.e. less worrying about false positives so the threshold for results can be lowered).

+5


source


You may be looking for Fillhole transform , a morphological image reconstruction application.

This transformation will fill the holes in your coins, albeit at the expense of the fact that they also fill all the holes between groups of adjacent coins. Spatial or open Hough solutions offered by other posters will probably give you better high-level recognition results.

+3


source


Try using the cvFindContours () function . You can use it to search for connected components. With the correct parameters, this function returns a list with the outlines of all connected components.

Find the outlines that represent the hole. Then use cvDrawContours () to fill the selected path with the foreground color, thereby covering the holes.

+1


source


I think if objects get touched or overflowed, there will be problems with using contours and discovering mathematical mphology. Instead, found and tested the following simple solution. It works really well, and not only for these images, but any other image as well.

Here are the steps (optimized) as shown at http://blogs.mathworks.com/steve/2008/08/05/filling-small-holes/

let I

: input image

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.

      

In short, the algorithm is only to find all the holes, remove the large ones, and then write the small ones only to the original image.

+1


source


I was browsing the internet to find the correct imfill function (like in Matlab) but working in C with OpenCV. After some re-fixing, I finally came up with a 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;
}

      

For this: Original binary image

Result: Final binary image

The trick is in the cvDrawContours function parameter settings: cvDrawContours (dst, outline, white, white, 0, CV_FILLED);

  • dst = destination image
  • contour = pointer to first contour
  • white = the color used to fill the outline
  • 0 = Maximum level for outlines. If 0, only the outline is displayed
  • CV_FILLED = The thickness of the lines on which the outlines are drawn. If it is negative (eg = CV_FILLED), contour interiors are drawn.

More information in the openCV documentation.

There is probably a way to get the "dst" directly as a binary image, but I couldn't find how to use the cvDrawContours function with binary values.

0


source







All Articles