填补emgu cv中的漏洞

Posted

技术标签:

【中文标题】填补emgu cv中的漏洞【英文标题】:Fill the holes in emgu cv 【发布时间】:2011-11-04 11:36:33 【问题描述】:

如何填补 emgu cv 中二进制图像中的漏洞? 在 Aforge.net 中使用 Fillholes 类很简单。

【问题讨论】:

【参考方案1】:

认为这个问题有点老了,我想为这个问题提供一个替代解决方案。

如果您使用以下方法,您可以获得与 Chris' 相同的结果而不会出现内存问题:

private Image<Gray,byte> FillHoles(Image<Gray,byte> image)
    
        var resultImage = image.CopyBlank();
        Gray gray = new Gray(255);
        using (var mem = new MemStorage())
        
            for (var contour = image.FindContours(
                CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE, 
                RETR_TYPE.CV_RETR_CCOMP, 
                mem); contour!= null; contour = contour.HNext)
            
                resultImage.Draw(contour, gray, -1);
            
        

        return resultImage;
    

上述方法的好处是您可以选择性地填充符合您标准的孔。例如,您可能想要填充像素数(blob 内的黑色像素数)低于 50 的孔,等等。

private Image<Gray,byte> FillHoles(Image<Gray,byte> image, int minArea, int maxArea)
    
        var resultImage = image.CopyBlank();
        Gray gray = new Gray(255);

        using (var mem = new MemStorage())
        
            for (var contour = image.FindContours(
                CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE, 
                RETR_TYPE.CV_RETR_CCOMP, 
                mem); contour!= null; contour = contour.HNext)
            
                if ( (contour.Area < maxArea) && (contour.Area > minArea) )
                    resultImage.Draw(contour, gray, -1);
            
        

        return resultImage;
    

【讨论】:

我认为这是最好的答案。 我也是。以前经常会导致 OutOfMemory 问题【参考方案2】:

是的,有一种方法,但它基于 cvFloodFill 操作有点混乱。现在,这个算法的设计目的是用一种颜色填充一个区域,直到它达到类似于区域增长算法的边缘。要有效地使用它,您需要使用一些创造性的编码,但我警告您,此代码只是为了让您入门,它可能需要重构以加快速度。就目前而言,循环遍历小于 255 的每个像素应用 cvFloodFill 检查该区域的大小,然后如果它在某个区域以下,则将其填充。

重要的是要注意,图像的副本是由原始图像制成的,以作为指针提供给 cvFloodFill 操作。如果提供了直接图像,那么您最终将得到一个白色图像。

OpenFileDialog OpenFile = new OpenFileDialog();

if (OpenFileDialog.ShowDialog() == DialogResult.OK)

    Image<Bgr, byte> image = new Image<Bgr, byte>(OpenFile.FileName);

            for (int i = 0; i < image.Width; i++)
            
                for (int j = 0; j < image.Height; j++)
                
                    if (image.Data[j, i, 0] != 255)
                    
                        Image<Bgr, byte> image_copy = image.Copy();
                        Image<Gray, byte> mask = new Image<Gray, byte>(image.Width + 2, image.Height + 2);
                        MCvConnectedComp comp = new MCvConnectedComp();
                        Point point1 = new Point(i, j);
                        //CvInvoke.cvFloodFill(
                        CvInvoke.cvFloodFill(image_copy.Ptr, point1, new MCvScalar(255, 255, 255, 255),
                        new MCvScalar(0, 0, 0),
                        new MCvScalar(0, 0, 0), out comp,
                        Emgu.CV.CvEnum.CONNECTIVITY.EIGHT_CONNECTED,
                        Emgu.CV.CvEnum.FLOODFILL_FLAG.DEFAULT, mask.Ptr);
                        if (comp.area < 10000)
                        
                            image = image_copy.Copy();
                        
                    
                
            

“new MCvScalar(0, 0, 0), new MCvScalar(0, 0, 0)”在这种情况下并不重要,因为您只是填写二进制图像的结果。您可以尝试使用其他设置,看看您可以实现什么结果。 "if (comp.area key 常量,要更改的是您要更改方法将填充的孔大小。

这些是您可以期待的结果:

原创

结果

这种方法的问题是它非常占用内存,它在 200x200 的图像上消耗了 6GB 的内存,当我尝试 200x300 时,它吃掉了我所有的 8GB 内存,并导致一切崩溃。除非你的大部分图像是白色的,并且你想填补微小的空白,否则你可以尽量减少应用我会避免的方法的位置。我建议您编写自己的类来检查不是 255 的每个像素并添加围绕它的像素数。然后,您可以记录不是 255 的每个像素的位置(在一个简单的列表中),如果您的计数低于阈值,则在您的图像中将这些位置设置为 255(通过迭代列表)。

如果您不想编写自己的 Aforge FillHoles 类,我会坚持使用它,因为它是为此目的而设计的。

干杯

克里斯

【讨论】:

【参考方案3】:

您可以使用 FillConvexPoly

image.FillConvexPoly(externalContours.ToArray(), new Gray(255));

【讨论】:

以上是关于填补emgu cv中的漏洞的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 C# 中的 Emgu CV 库在图像上绘制矩形。举个例子

使用 emgu cv 获取图像的像素

填补OpenCV中的漏洞[重复]

Emgu CV EigenObjectRecognizer 不工作

EMGU CV SURF 图像匹配

EMGU CV 2.4.9 人脸识别准确率问题