2011-08-26 180 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));