2011-08-26 12 views

Respuesta

6

sí, hay un método, pero es un poco desordenado como su funcionamiento basado en cvFloodFill. Ahora todo lo que este algoritmo está diseñado para hacer es llenar un área con un color hasta que llegue a un borde similar al algoritmo de crecimiento de una región. Para usar esto de manera efectiva, debes usar una pequeña codificación ingeniosa, pero te advierto que este código es solo para que comiences, ya que puede ser necesario volver a factorizar para acelerar las cosas. Tal como está, el ciclo pasa por cada uno de tus píxeles que son inferiores a 255 aplica cvFloodFill verifica el tamaño del área y luego, si está debajo de un área determinada, la completa.

Es importante tener en cuenta que una copia de la imagen está hecha de la imagen original que se suministrará a la operación cvFloodFill cuando se utiliza un puntero. Si se suministra la imagen directa, terminará con una imagen blanca.

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

La "nueva MCvScalar (0, 0, 0), nuevo MCvScalar (0, 0, 0)," no son realmente importante en este caso, ya que sólo está llenando en los resultados de una imagen binaria. Podrías jugar con otras configuraciones para ver qué resultados puedes lograr. "if (comp.area < 10000)" es la key constante para cambiar es que desea cambiar el tamaño del agujero que el método llenará.

Estos son los resultados que se pueden esperar:

originales

Original Image

Resultados

The Resultant Image

El problema con este método i s es extremadamente intensivo en memoria y se las arregló para comer hasta 6 GB de ram en una imagen de 200 x 200 y cuando probé 200x300 se comió todos los 8 GB de mi RAM y detuvo todo. A menos que la mayoría de tu imagen sea blanca y quieras llenar pequeños espacios o puedes minimizar el lugar donde aplicas el método, lo evitaría. Sugeriría que escribas tu propia clase para examinar cada píxel que no sea 255 y agregar el número de píxeles que lo rodean. A continuación, puede registrar la posición de cada píxel que no era 255 (en una lista simple) y si su recuento estaba por debajo de un umbral establezca estas posiciones en 255 en sus imágenes (iterando a través de la lista).

Me quedaría con la clase Aforge FillHoles si no desea escribir la suya ya que está diseñada para este propósito.

Saludos

Chris

+0

mismo gracias Chris ! está bien !!! –

12

pensó que la pregunta es un poco viejo, me gustaría aportar una solución alternativa al problema.

puede obtener el mismo resultado que Chris y sin problema de memoria si utiliza los siguientes:

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

Lo bueno del método anterior es que se puede llenar selectivamente agujeros que se ajuste a sus criterios.Por ejemplo, es posible que desee llenar los agujeros cuyo recuento de píxeles (recuento de píxeles negros dentro de la burbuja) está por debajo de 50, etc.

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

Creo que esta es la mejor respuesta. – Rick2047

+0

Yo también. Lo anterior a menudo causa problemas OutOfMemory –

1

puede utilizar FillConvexPoly

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