2012-09-25 34 views
5

Dada una lista de coordenadas x, y una anchura & altura conocida cómo puede el NÚMERO de las zonas delimitadas por determinar (en C#)?dado un conjunto de puntos

Por ejemplo:

enter image description here

En esta imagen 5 áreas cerradas se definen:

  1. Face (1)
  2. Eyes (2)
  3. nariz (1)
  4. derecho de la cara (1)

La lista de puntos xey sería cualquier pixel de negro, incluyendo la boca.

+1

[comenzar con la fórmula para encontrar el área de un polígono] (http://en.wikipedia.org/wiki/Polygon#Area_and_centroid) – Servy

+2

pensar en píxeles que encierran sus regiones como de los polígonos a continuación, ver http://stackoverflow.com/questions/2034540/calculating-area-of-irregular-polygon-in-c-sharp sobre cómo obtener el área del polígono – m0s

+0

Lo siento, algo se perdió en la traducción ... Tengo que descubrir el número de Regiones (5) no el área de ellas. – user873432

Respuesta

2

Se puede usar esta simple algoritmo, basado en la idea de las inundaciones llenar de mapa de bits ayudante:

// backColor is an INT representation of color at fillPoint in the beginning. 
// result in pixels of enclosed shape. 
private int GetFillSize(Bitmap b, Point fillPoint) 
{ 
    int count = 0; 
    Point p; 
    Stack pixels = new Stack(); 
    var backColor = b.GetPixel(fillPoint.X, fillPoint.Y); 
    pixels.Push(fillPoint); 
    while (pixels.Count != 0) 
    { 
     count++; 

     p = (Point)pixels.Pop(); 
     b.SetPixel(p.X, p.Y, backColor); 

     if (b.GetPixel(p.X - 1, p.Y).ToArgb() == backColor) 
      pixels.Push(new Point(p.X - 1, p.Y)); 

     if (b.GetPixel(p.X, p.Y - 1).ToArgb() == backColor) 
      pixels.Push(new Point(p.X, p.Y - 1)); 

     if (b.GetPixel(p.X + 1, p.Y).ToArgb() == backColor) 
      pixels.Push(new Point(p.X + 1, p.Y)); 

     if (b.GetPixel(p.X, p.Y + 1).ToArgb() == backColor) 
      pixels.Push(new Point(p.X, p.Y + 1)); 
    } 

    return count; 
} 

ACTUALIZACIÓN

El código anterior sólo funciona esta áreas cerradas vinculados cuádruplemente. El siguiente código funciona con áreas cerradas vinculadas con octuply.

// offset points initialization. 
Point[] Offsets = new Point[] 
{ 
    new Point(-1, -1), 
    new Point(-0, -1), 
    new Point(+1, -1), 
    new Point(+1, -0), 
    new Point(+1, +1), 
    new Point(+0, +1), 
    new Point(-1, +1), 
    new Point(-1, +0), 
}; 

... 

private int Fill(Bitmap b, Point fillPoint) 
{ 
    int count = 0; 
    Point p; 
    Stack<Point> pixels = new Stack<Point>(); 
    var backColor = b.GetPixel(fillPoint.X, fillPoint.Y).ToArgb(); 
    pixels.Push(fillPoint); 
    while (pixels.Count != 0) 
    { 
     count++; 

     p = (Point)pixels.Pop(); 
     b.SetPixel(p.X, p.Y, Color.FromArgb(backColor)); 

     foreach (var offset in Offsets) 
      if (b.GetPixel(p.X + offset.X, p.Y + offset.Y).ToArgb() == backColor) 
       pixels.Push(new Point(p.X + offset.X, p.Y + offset.Y)); 
    } 

    return count; 
} 

La imagen siguiente demuestra claramente lo que quiero decir. También se podrían agregar más puntos lejanos para compensar la matriz con el fin de poder llenar áreas con espacios.

Connectedness

+0

Cool. Esto hace que mi vaga descripción sea explícita. Me gusta. –

+0

Agradable, útil para otra área en la que estaba trabajando, pero ¿alguna idea de cómo determinar el número de áreas cerradas? – user873432

+1

Puede usar mi algoritmo para cada pixel no de fondo (negro en su imagen de ejemplo) para detectar regiones. Después de cada llenado, estas regiones no se detectarán (debido a que se llenarán) y tendrás que aumentar la cantidad de regiones encontradas. Por supuesto, este método es adecuado para regiones vinculadas. Por lo tanto, para otros casos use OpenCV, cómo ha respondido @Jason Hermann. –

1

Hay un par de casos especiales en la imagen de muestra. Tendría que decidir cómo tratar con ellos.

Generalmente, comenzará convirtiendo la imagen ráster en una serie de polígonos. Entonces es una cuestión bastante trivial calcular el área (Ver el comentario de Servy)

Los casos especiales serían el lado de la cara y la boca. Ambas son formas abiertas, no cerradas. Necesitas descubrir cómo cerrarlos.

2

He tenido un gran éxito usando OpenCV. Hay una biblioteca de .NET llamada Emgu CV

Aquí está una pregunta que cubre alternativas para Emgu CV: .Net (dotNet) wrappers for OpenCV?

Esa biblioteca contiene funciones para la identificación de contornos y la búsqueda de propiedades acerca de ellos. Puede buscar cvContourArea para encontrar más información.

Si está buscando una solución rápida a este problema específico y desea escribir su propio código en lugar de reutilizar otros, no tengo un algoritmo que pueda dar que lo haga. Lo siento.

1

Creo que esto se reduce a contar el número de píxeles (no negros) en cada región. Si elige un píxel que no sea negro, agréguelo a HashSet<>, observe si los píxeles que están encima, debajo, a la izquierda ya la derecha del píxel elegido, tampoco son negros.

Cada vez que encuentre nuevo píxeles no negros (al subir/bajar/izquierda/derecha), agréguelos a su conjunto. Cuando los haya encontrado a todos, cuéntelos.

El área de su región es count/(pixelWidthOfTotalDrawing * pixelHeightOfTotalDrawing) multiplicada por el área del rectángulo completo (dependiendo de las unidades que desee).

Comentario: No creo que se vea como un polígono. Es por eso que tenía en mente la función "llenar de pintura" del software de dibujo simple.

Cuestiones relacionadas