Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/matlab/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 填充OpenCV中的孔_C++_Matlab_Image Processing_Opencv_Flood Fill - Fatal编程技术网

C++ 填充OpenCV中的孔

C++ 填充OpenCV中的孔,c++,matlab,image-processing,opencv,flood-fill,C++,Matlab,Image Processing,Opencv,Flood Fill,我在(canny edge detection)中从边缘检测模块提取了一个边缘贴图。我想做的是填充边贴图中的洞 我正在使用C++和OpenCV库。在OpenCV中有一个函数,它将用种子填充孔(其中一个位置用于开始泛洪)。然而,我试图在不知道种子的情况下填充所有内部孔。(类似于MATLAB中的) Q1:如何找到所有种子,以便我可以应用“cvFloodFill()”? Q2:如何实现“imfill()”等价物 OpenCV中的新手,如有任何提示,我们将不胜感激。根据MATLAB中的文档: 填充二进制

我在(canny edge detection)中从边缘检测模块提取了一个边缘贴图。我想做的是填充边贴图中的洞

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

Q1:如何找到所有种子,以便我可以应用“cvFloodFill()”?
Q2:如何实现“imfill()”等价物


OpenCV中的新手,如有任何提示,我们将不胜感激。

根据MATLAB中的文档:

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

因此,要获得“孔”像素,请调用,将图像的左角像素作为种子。通过补充上一步中获得的图像,可以获得孔

MATLAB示例:
BW=im2bw(imread('coins.png');
子地块(121),imshow(BW)
%在这里使用,好像它是一个洪水填充
孔=imfill(BW,[1]);%[1]是起始位置点
BW(~孔)=1;%补洞
子地块(122),imshow(BW)

您是否尝试过在罐头图像上查找轮廓


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

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

  • 对输入图像执行canny,使新的二值图像的边缘为1,否则为0
  • 沿边缘图像的一侧找到第一个0,并使用边缘图像作为遮罩,在空白图像上的该点上用1开始泛光填充。(我们希望在这里我们没有运气不好,在屏幕一半的形状的内部播种第一次填充)
  • 这个新的泛光填充图像是“背景”。这里任何一个1的像素都是背景,任何一个0的像素都是前景
  • 循环浏览图像并找到任何前景像素。在你找到的任何东西上撒上种子
  • 或者这张新的泛光图像和你第一步的精明图像,你就完成了

  • cvDrawContours函数有一个选项,用于填充已绘制的轮廓

    下面是一个简短的例子 cvDrawContours(IplImage,contours,color,color,-1,CV_填充,8)

    这是文件

    我猜你很久以前就发布了这个,但我希望它能帮助别人

    这是源代码(C#):

    Image Image=新图像(@“D:\final.bmp”);
    CvInvoke.cvShowImage(“图像1”,图像);
    var等高线=image.FindContours();
    while(等高线!=null)
    {
    CvInvoke.cvDrawContours(图像,轮廓,新灰度(255).MCvScalar,新灰度(255).MCvScalar,0,-1,Emgu.CV.CvEnum.LINE_TYPE.CV_AA,新DPoint(0,0));
    等高线=等高线.HNext;
    }
    CvInvoke.cvShowImage(“图像2”,图像);
    

    如果有来自边的点,则可以使用FillConversionPoly()或fillPoly()(如果多边形不是凸的)

    从边获取点的一种方法是执行findContours()->approxPolyDP()

    只是一个附录

    void cvFillHoles(cv::Mat&input)
    {
    //假设输入为uint8黑白(0或1)
    //此函数模拟imfill(图像,'hole')
    cv::Mat holes=input.clone();
    cv::泛洪填充(孔,cv::Point2i(0,0),cv::Scalar(1));
    
    对于(int i=0;i)我一直在网上寻找合适的<强> imSuff<强>函数(如MATLAB中的一个),但是用OpenCV在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函数的参数设置: CVDraw轮廓(dst、轮廓、白色、白色、0、CV_填充)

    • dst=目标映像
    • 轮廓=指向第一个轮廓的指针
    • 白色=用于填充轮廓的颜色
    • 0=绘制轮廓的最大级别。如果为0,则仅绘制轮廓
    • CV_FILLED=绘制轮廓线的厚度。如果为负值(例如,=CV_FILLED),则绘制轮廓线内部
    更多信息请参见openCV文档


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

    我制作了一个简单的函数,相当于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;
    }
    
    下面是一个示例结果


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

    #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;
    } 
    
    #包括
    使用名称空间std;
    #包括
    #包括
    #包括
    使用名称空间cv;
    int main()
    {
    IplImage*im=cvLoadImage(“coin.png”,CV\u LOAD\u IMAGE\u ANYDEPTH);
    IplImage*hole=cvCreateImage(cvSize(im->width,im->height),8,1);
    cvShowImage(“原件”,im);
    cvCopyImage(im,孔);
    Cv洪水填充(孔、Cv点(0,0)、Cv标量(255));
    cvShowImage(“孔”,孔);
    cvSaveImage(“hole.png”,hole);
    cvNot(孔,孔);
    cvAdd(im,hole,im);
    cvShowImage(“填充孔”,im);
    cvSaveImage(“fillHole.png”,im);
    cvWaitKey(0);
    系统(“暂停”);
    返回0;
    } 
    

    希望这会有帮助。

    太棒了,Amro!谢谢!!!非常好。我正试图找出如何在不依赖
    imfill
    中的
    holes
    标志的情况下实现这一点。我想在OpenCV Python上实现这一点,您已经为我指明了方向。
    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;
    }
    
    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;
    }
    
    #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;
    }