填写OpenCV中的漏洞

Lil*_*ily 33 c++ matlab opencv image-processing flood-fill

我在OpenCV(canny边缘检测)中从边缘检测模块中提取了边缘图.我想要做的是填补边缘图中的孔.

我正在使用C++OpenCV库.在OpenCV中有一个cvFloodFill()函数,它将用种子(其中一个位置开始泛滥)填充漏洞.但是,我试图在不知道种子的情况下填充所有内部空洞.(类似于MATLAB中的imfill())

Q1:如何查找所有种子,以便我可以应用'cvFloodFill()'?
Q2:如何实现'imfill()'等效?

OpenCV中的新手,任何提示都很受欢迎.

Amr*_*mro 34

根据imfillMATLAB 的文档:

BW2 = imfill(BW,'holes');
Run Code Online (Sandbox Code Playgroud)

填充二进制图像中的孔BW.孔是一组背景像素,通过从图像边缘填充背景无法到达.

因此,要获得"孔"像素,请cvFloodFill使用图像的左角像素作为种子进行调用.通过补充在上一步中获得的图像来获得孔.

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)
Run Code Online (Sandbox Code Playgroud)

screenshot1 screenshot2


Not*_*yne 12

cvDrawContours函数有一个选项来填充您绘制的轮廓.

这是一个简短的例子cvDrawContours(IplImage,contours,color,color,-1,CV_FILLED,8);

这是文档

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

我猜你很久以前发过这个了,但我希望它对某人有所帮助.

这是源代码(在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);
Run Code Online (Sandbox Code Playgroud)

结果


Jer*_*y.S 7

我一直在互联网上寻找一个合适的imfill函数(如Matlab中的那个),但是在C++中使用OpenCV.经过一些研究,我终于想出了一个解决方案:

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;
}
Run Code Online (Sandbox Code Playgroud)

为此:原始二进制图像

结果是:最终二进制图像

诀窍在于cvDrawContours函数的参数设置:cvDrawContours(dst,contour,white,white,0,CV_FILLED);

  • dst =目的地图像
  • contour =指向第一个轮廓的指针
  • white =用于填充轮廓的颜色
  • 0 =绘制轮廓的最大级别.如果为0,则仅绘制轮廓
  • CV_FILLED =绘制轮廓的线条粗细.如果为负(例如,= CV_FILLED),则绘制轮廓内部.

openCV文档中的更多信息.

可能有一种方法可以直接将"dst"作为二进制图像,但我找不到如何将cvDrawContours函数与二进制值一起使用.

  • 确切地说,这不是使用C++ API,而是使用旧的C接口.此外,这与[NotNamedDwayne](http://stackoverflow.com/a/3374317/97160)在答案中的内容相同 (2认同)

Ped*_*sta 6

我做了一个简单的函数,相当于matlab的imfill('holes').我在很多情况下都没有对它进行测试,但到目前为止它已经有效了.我在边缘图像上使用它,但它接受任何类型的二进制图像,例如来自阈值操作.

一个洞不超过一组像素,当背景被填满时无法"到达",因此,

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;
}
Run Code Online (Sandbox Code Playgroud)

这是一个示例结果

在此输入图像描述