2011-08-26 178 views

回答

6

是有一种方法,但它是一个有点乱作为其基于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(); 
         } 
        } 
       } 
      } 
} 

“新MCvScalar(0,0,0),新MCvScalar(0,0,0),” 不是在这种情况下,真正重要的,因为你只是在一个二进制图像的结果填充。 YOu可以与其他设置一起玩,看看你能达到什么效果。 “如果(comp.area < 10000)”是不断更改是您要更改该方法将填充的大小洞。

这些是可以预期的结果:

原始

Original Image

结果

The Resultant Image

这种方法的问题,我它的内存密集程度非常高,它能够在200x200的图像上吞噬6GB的内存,当我尝试200x300时,它会吞噬所有8GB的内存,并将所有内容都瘫痪。除非你的图像的大部分是白色的,你想填补微小的空白,或者你可以尽量减少你应用的方法,我会避免它。我会建议编写自己的类来检查每个不是255的像素,并添加围绕它的像素数。然后,您可以记录不是255的每个像素的位置(在简单列表中),并且如果您的计数低于阈值,则将图像中的这些位置设置为255(通过迭代列表)。

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

干杯

克里斯

+0

非常感谢克里斯!那就对了 !!! –

12

想到的问题是有点老了,我想贡献一个替代解决问题的办法。

可以得到相同的结果,克里斯没有记忆的问题,如果您使用以下命令:

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

我认为这是最好的答案。 – Rick2047

+0

我也是。以前经常会导致OutOfMemory问题 –

1

可以使用FillConvexPoly

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