填补OpenCV中的漏洞[重复]
c++
image-processing
matlab
opencv
6
0

我有一个从OpenCV的边缘检测模块中提取的边缘贴图(Canny边缘检测)。我要做的是填补边缘贴图中的孔。

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

问题1:如何查找所有种子,以便我可以应用“ cvFloodFill()”?
问题2:如何实现“ imfill()”等效项?

OpenCV中的新手,任何提示都值得赞赏。

参考资料:
Stack Overflow
收藏
评论
共 8 个回答
高赞 时间 活跃

我做了一个简单的函数,等效于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;
}

这是一个示例结果

在此处输入图片说明

收藏
评论

根据MATLAB中imfill的文档:

BW2 = imfill(BW,'holes');

填充二进制图像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)

屏幕截图1 屏幕截图2

收藏
评论

我一直在互联网上寻找合适的填充功能(如Matlab中的功能),但是在Open ++中使用C ++进行工作。经过一番重新研究之后,我终于想出了一个解决方案:

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;
}

为此: 原始二进制图像

结果是: 最终二进制图像

技巧是在cvDrawContours函数的参数设置中:cvDrawContours(dst,轮廓,白色,白色,0,CV_FILLED);

  • dst =目标图像
  • 轮廓=指向第一个轮廓的指针
  • 白色=用于填充轮廓的颜色
  • 0 =绘制轮廓的最大水平。如果为0,则仅绘制轮廓
  • CV_FILLED =绘制轮廓的线的粗细。如果为负(例如= CV_FILLED),则绘制轮廓内部。

更多信息请参见openCV文档。

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

收藏
评论

这是一种快速而肮脏的方法:

  1. 在您的输入图像上执行canny,以便新的二进制图像的边缘有1,否则为0。
  2. 在边缘图像的一侧找到第一个0,然后使用边缘图像作为蒙版在空白图像上的该点处以1填充填充。 (我们希望在这里,我们不会倒霉,并且将第一个填充内容播种到半屏的形状内部)
  3. 这个新的充满图像是“背景”。此处具有1的任何像素是背景,而具有0的任何像素是前景。
  4. 循环浏览图像并找到任何前景像素。在您发现的任何东西上填充洪水。
  5. 或将此新充斥的图像与步骤1中的Canny图像一起使用,就可以完成。
收藏
评论

cvDrawContours函数有一个选项可以填充您绘制的轮廓。

这是一个简短的示例cvDrawContours(IplImage,轮廓,颜色,颜色,-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);

结果

收藏
评论

只是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;
    }
}
收藏
评论

最近,我也在寻找该问题的解决方案。在这里,我实现了Amro的想法,如下所示:

#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;
} 

希望这会有所帮助。

收藏
评论

您是否尝试过对Cannyied图像进行ContourFinding?

cvFindContours创建了一种树,其中外部物体是内部轮廓(“孔”)的父级。请参见contours.py示例。从轮廓中您可以提取种子

收藏
评论
新手导航
  • 社区规范
  • 提出问题
  • 进行投票
  • 个人资料
  • 优化问题
  • 回答问题

关于我们

常见问题

内容许可

联系我们

@2020 AskGo
京ICP备20001863号