在emgu cv中填充孔

Rez*_*hat 6 c# emgucv

我怎样才能在emgu cv中填充二进制图像中的孔?在Aforge.net中,使用Fillholes类很容易.

谢谢

小智 12

认为这个问题有点陈旧,我想为这个问题提供一个替代解决方案.

如果您使用以下内容,您可以获得与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;
    }
Run Code Online (Sandbox Code Playgroud)

上述方法的好处是您可以选择性地填充符合您标准的孔.例如,您可能想要填充其像素数(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;
    }
Run Code Online (Sandbox Code Playgroud)


Chr*_*ris 7

是的,有一种方法,但它有点混乱,因为它基于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();
                        }
                    }
                }
            }
}
Run Code Online (Sandbox Code Playgroud)

"新MCvScalar(0,0,0),新MCvScalar(0,0,0)"在这种情况下并不重要,因为您只填写二进制图像的结果.你可以使用其他设置来查看你可以实现的结果."if(comp.area <10000)"是要更改的关键常量,您想要更改方法将填充的大小.

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

原版的

原始图像

结果

结果图片

这种方法的问题在于内存非常密集,它在200x200图像上占用了6GB的内存,当我尝试200x300时,它吃掉了所有8GB的内存并使一切都停止了.除非您的大部分图像是白色的,并且您想要填补微小的间隙,或者您可以最小化应用方法的位置,我会避免它.我建议您编写自己的类来检查每个不是255的像素并添加它周围的像素数.然后,您可以记录每个不是255的像素的位置(在一个简单的列表中),如果您的计数低于阈值,则在图像中将这些位置设置为255(通过迭代列表).

如果你不想写自己的,我会坚持使用Aforge FillHoles课程,因为它是为此目的而设计的.

干杯

克里斯