2011-08-26 26 views

Trả lời

6

Có một phương pháp nhưng hơi lộn xộn một chút dựa trên hoạt động cvFloodFill. Bây giờ tất cả các thuật toán này được thiết kế để làm là điền vào một khu vực với một màu sắc cho đến khi nó đạt đến một cạnh tương tự như một thuật toán phát triển khu vực. Để sử dụng hiệu quả, bạn cần phải sử dụng một chút sáng tạo mã hóa nhưng tôi cảnh báo bạn mã này chỉ để giúp bạn bắt đầu nó có thể yêu cầu tái factoring để tăng tốc độ những thứ lên. Vì nó là viết tắt của vòng lặp đi qua mỗi điểm ảnh của bạn mà ít hơn 255 sau đó áp dụng cvFloodFill kiểm tra kích thước khu vực là gì và sau đó nếu nó là theo một khu vực nhất định điền vào nó.

Điều quan trọng cần lưu ý là một bản sao hình ảnh được tạo thành từ hình ảnh gốc được cung cấp cho hoạt động cvFloodFill khi sử dụng con trỏ. Nếu hình ảnh trực tiếp được cung cấp thì bạn sẽ kết thúc với một hình ảnh màu trắng.

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(); 
         } 
        } 
       } 
      } 
} 

Các "MCvScalar mới (0, 0, 0), mới MCvScalar (0, 0, 0)," không phải là thực sự quan trọng trong trường hợp này là bạn chỉ được điền vào kết quả của một hình ảnh nhị phân. YOu có thể chơi xung quanh với các cài đặt khác để xem kết quả bạn có thể đạt được. "if (comp.area < 10000)" là khóa hằng số thay đổi là bạn muốn thay đổi kích thước lỗ mà phương thức sẽ điền.

Đây là những kết quả mà bạn có thể mong đợi:

gốc

Original Image

Kết quả

The Resultant Image

Vấn đề với phương pháp này i Đó là bộ nhớ cực kỳ chuyên sâu và nó quản lý để ăn lên 6 GB ram trên một hình ảnh 200x200 và khi tôi đã cố gắng 200x300 nó ăn tất cả 8GB RAM của tôi và mang lại cho tất cả mọi thứ để dừng tạm dừng. Trừ khi phần lớn hình ảnh của bạn có màu trắng và bạn muốn lấp đầy khoảng trống nhỏ hoặc bạn có thể giảm thiểu nơi bạn áp dụng phương pháp tôi sẽ tránh nó. Tôi khuyên bạn nên viết cho bạn lớp riêng để kiểm tra từng pixel không phải là 255 và thêm số pixel xung quanh nó. Sau đó bạn có thể ghi lại vị trí của mỗi điểm ảnh không phải là 255 (trong một danh sách đơn giản) và nếu số đếm của bạn dưới ngưỡng đặt các vị trí này thành 255 trong ảnh của bạn (bằng cách lặp lại danh sách).

Tôi sẽ gắn bó với lớp Lớp đệm Fillorge nếu bạn không muốn viết của riêng mình vì nó được thiết kế cho mục đích này.

Cheers

Chris

+0

rất cảm ơn chris ! đúng rồi !!! –

12

Nghĩ câu hỏi là một chút cũ, tôi muốn đóng góp một giải pháp thay thế cho các vấn đề.

Bạn có thể lấy kết quả tương tự như Chris' mà không vấn đề bộ nhớ nếu bạn sử dụng như sau:

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

Những điều tốt về các phương pháp trên là bạn có chọn lọc có thể lấp đầy lỗ hổng đáp ứng tiêu chí của bạn.Ví dụ, bạn có thể muốn để lấp đầy lỗ mà điểm ảnh count (đếm pixel đen bên trong blob) là dưới 50 vv

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

Tôi nghĩ đây là câu trả lời hay nhất. – Rick2047

+0

Tôi cũng thế. Trước đây thường gây ra các vấn đề OutOfMemory –

1

bạn có thể sử dụng FillConvexPoly

image.FillConvexPoly(externalContours.ToArray(), new Gray(255)); 
Các vấn đề liên quan