Ask Your Question
2

Fill holes of a binary image

asked 2013-03-21 13:20:09 -0600

matteo gravatar image

hi, my goal is to fill with white colour the CLOSED black zones, not that ones that end on the image boundaries but aren't closed by white pixels (i hope i'm clear). i tried with opening (or closure) functions but the they causes the closure of the opened/connected black rectangular zones, thing that is highly unwanted. can someone help me? image description

edit retag flag offensive close merge delete

Comments

1

If erosion and dilation aren't what you're looking for, then my approach would be to apply a flood fill to areas connected to the borders to create a mask of just the closed off black boxes. Then apply that mask to the original image to mask out the black boxes.

HD_Mouse gravatar imageHD_Mouse ( 2013-03-21 14:59:45 -0600 )edit

3 answers

Sort by ยป oldest newest most voted
8

answered 2013-03-21 17:36:02 -0600

HD_Mouse gravatar image

updated 2013-03-21 19:27:17 -0600

I had some extra time at work so I whipped up a quick and dirty implementation of my comment above:

Code:

cv::Mat image = cv::imread("image.jpg", 0);

cv::Mat image_thresh;
cv::threshold(image, image_thresh, 125, 255, cv::THRESH_BINARY);

// Loop through the border pixels and if they're black, floodFill from there
cv::Mat mask;
image_thresh.copyTo(mask);
for (int i = 0; i < mask.cols; i++) {
    if (mask.at<char>(0, i) == 0) {
        cv::floodFill(mask, cv::Point(i, 0), 255, 0, 10, 10);
    }   
    if (mask.at<char>(mask.rows-1, i) == 0) {
        cv::floodFill(mask, cv::Point(i, mask.rows-1), 255, 0, 10, 10);
    }
}
for (int i = 0; i < mask.rows; i++) {
    if (mask.at<char>(i, 0) == 0) {
        cv::floodFill(mask, cv::Point(0, i), 255, 0, 10, 10);
    }
    if (mask.at<char>(i, mask.cols-1) == 0) {
        cv::floodFill(mask, cv::Point(mask.cols-1, i), 255, 0, 10, 10);
    }
}


// Compare mask with original.
cv::Mat newImage;
image.copyTo(newImage);
for (int row = 0; row < mask.rows; ++row) {
    for (int col = 0; col < mask.cols; ++col) {
        if (mask.at<char>(row, col) == 0) {
            newImage.at<char>(row, col) = 255;
        }           
    }
}
cv::imshow("filled image", mask);
cv::imshow("Final image", newImage);
cv::imwrite("final.jpg", newImage);
cv::waitKey(0);

return 0;

And the result: image description

edit flag offensive delete link more
0

answered 2013-07-08 01:57:35 -0600

use cvSegmentFGMask should help you

edit flag offensive delete link more
0

answered 2013-03-22 12:40:05 -0600

wuling gravatar image

HI, there is the other code which is used findContours. I don't know which one is more effictive.

Mat CV_EXPORTS FillHoles( Mat _src)
{
    CV_Assert(_src.type()==CV_8UC1);
    Mat dst;
    vector<vector<cv::Point>> contours;
    vector<Vec4i> hierarchy;

    findContours(_src,contours,hierarchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE,cv::Point(0,0));
    CvScalar color=cvScalar(255);
    dst=Mat::zeros(_src.size(),CV_8UC1);

    for(int i=0;i<contours.size();i++)
    {
        drawContours(dst,contours,i,color,-1,8,hierarchy,0,cv::Point());
    }
    return dst;
}
edit flag offensive delete link more

Comments

"not that ones that end on the image boundaries but aren't closed by white pixels (i hope i'm clear)." I think my method cannot finish it,so the best way is HD_Mouse's way.

wuling gravatar imagewuling ( 2013-03-22 23:03:35 -0600 )edit

Question Tools

Stats

Asked: 2013-03-21 13:20:09 -0600

Seen: 26,036 times

Last updated: Jul 08 '13