2012-10-09 25 views
6

Estoy trabajando en un programa que trazará puntos en el centro de blobs binarios que se asemejan a piezas curvas de confeti. Más tarde ajustaré estos puntos con una spline cúbica que traza la curva.¿Cómo se muestra una línea en un blob en un ángulo perpendicular? (en Python/OpenCV a menos que sugiera cambiar a otra cosa)

Como parte del programa, I necesidad de:

- crear un vector 2D muestreo de una línea en ángulo a través de una imagen binaria,

- calcular el ángulo de utilizar en cada posición a lo largo de la gota de confeti.

Éstos son algunos ejemplos de las imágenes y bocetos de lo que los puntos trazados podría parecerse a:

enter image description here enter image description here enter image description here enter image description here enter image description here enter image description here

Encontrar el centro de una sección vertical de un confeti negro es sencillo. Siempre que esté en un píxel negro, encuentre el borde blanco izquierdo y derecho, el centro está a la mitad de la distancia entre estos. Hacer esto es fácil porque el vector 2d utilizado para hacer el cálculo anterior es solo una fila de la imagen.

this is a 10 pixel height segment of one of the confetti pieces

enter image description here

Pero las piezas de confeti no siempre se alinean con la espalda recta y vertical! Algunas veces son curvas o alineadas horizontalmente. Lo que se necesita aquí es un vector 2d que corta una sección a través del confeti en un ángulo. ¿Cuál es la manera más eficiente de muestrear este vector en ángulo de la imagen? Prácticamente, en una biblioteca de procesamiento de imágenes como Python PIL o OpenCV, ¿hay operaciones que puedan obtener vectores de líneas en ángulos a través de una imagen? Si hago uno, ¿cómo puedo asegurarme de que sea eficiente?

¿Cuál es la forma más eficiente de calcular el ángulo del vector necesario? Una forma de obtener el ángulo apropiado es encontrar el ángulo que da como resultado el segmento negro de ancho mínimo en el vector 2d devuelto. No necesito hacer esto de manera exhaustiva, solo recorrer 360 grados con incrementos de 30 grados Otra forma de obtener el ángulo apropiado podría ser encontrar la tangente de la curva de la pieza de confeti y usar la línea perpendicular a esa, pero eso podría ser más complicado.

Cualquier idea sobre cómo abordar mejor el problema sería muy útil. Cualquier sugerencia específica sobre cómo buscar una línea 2d a través de una imagen, y una forma eficiente de obtener el ángulo perpendicular también sería genial.

enter image description here

Respuesta

1

Esto parece adelgazamiento contorno o esqueleto. Eche un vistazo al that answer. Incluso hay un enlace a un paquete de Python.

+0

El adelgazamiento de contornos podría ser útil. Lo investigaré. Creo que la esqueletización va a ser demasiado costosa desde el punto de vista computacional, ya que eventualmente haré esto en video si no en tiempo real. Sin embargo, es una buena biblioteca de procesamiento de imágenes de Python. – user391339

4

Parece que le interesa el "ajuste del eje medial", junto con una estimación de la orientación (si tiene el eje, generalmente la tangente del eje en cualquier punto es suficiente).

Técnicamente, con OpenCV, usted podría considerar el uso de una transformada de distancia (cv.PointPolygonTest), usando celdas de Voronoi (cv.cvCalcSubdivVoronoi2D), o - como lo sugiere @remi adelgazamiento morfológica ...

Pero, si no lo hiciste No quiero usar el paquete scikits-image, y simplemente tuve que usar OpenCV - aquí hay un intento inicial usando algún código de esqueletización (based on a quick and easy technique).

simple first image skeletonenter image description hereenter image description here

A continuación, puede seguir este por algún ajuste a lo largo de los puntos descubiertos a resolver sus muestras y tangentes spline (pero esto requeriría un poco más de trabajo para descubrir los extremos y de quitar cualquier puntos perdidos/huecos ...)

import cv 

# get images 
orig = cv.LoadImage('o1Mlp.png') 

# create storage images 
grey = cv.CreateImage(cv.GetSize(orig), 8, 1) 
skel = cv.CreateImage(cv.GetSize(orig),8, 1) 
temp = cv.CreateImage(cv.GetSize(orig),8,1) 

# convert image to pure binary B&W based on threshold 
cv.CvtColor(orig, grey, cv.CV_RGB2GRAY) 
cv.Threshold(grey,grey,200,255,cv.CV_THRESH_BINARY_INV) 

# Create cross operator - good for skeletonization 
elem = cv.CreateStructuringElementEx(3,3,1,1,cv.CV_SHAPE_CROSS) 

# Loop until we have consumed all the values in the original image 
while True: 
    cv.MorphologyEx(grey,temp,None,elem,cv.CV_MOP_OPEN) # Shrink.. 
    cv.Not(temp,temp) # ...invert... 
    cv.And(grey,temp,temp) # ...intersect with original... 
    cv.Or(skel,temp,skel) # ... add to current skeleton... 
    cv.Erode(grey,grey,elem) # and reduce original ready for next. 

    (minVal,maxVal,minLoc,maxLoc)= cv.MinMaxLoc(grey) 
    if (maxVal==0): # Any pixels left? 
    break 

# show result 
cv.ShowImage("orig", orig) 
cv.ShowImage("skel", skel) 
cv.WaitKey(-1) 
+0

Muchas gracias. Voy a estudiar esto y ver si funciona. Tendré que quitar las ramas pequeñas del esqueleto principal, pero ciertamente hace un buen trabajo en el trazado. – user391339

2

En cuanto a la última parte del problema, encontrar las normales: uso mi propio algoritmo. Parece funcionar. Si encuentra una solución estándar o mejora la mía, ¡infórmenos!

/// <summary> 
    /// Returns absolute angle between points at offset length, or double.MinValue when not found. 
    /// </summary> 
    /// <param name="sequence">Ordered array of points (e.g., from OpenCV Contour)</param> 
    /// <param name="length">Number of points used to calculate angle</param> 
    /// /// <param name="increment">number of points between each angle calculation (e.g., 1 to attempt to determine angles for all points)</param> 
    /// <returns></returns> 
    public static double[] FindAbsoluteAngles(Point[] sequence, int length, int increment) 
    { 
     double[] angles = new double[sequence.Length]; 
     for (int i = 0; i < sequence.Length; i++) 
      angles[i] = double.MinValue; 

     double last = double.MinValue; 
     for (int i = length; i < sequence.Length; i += increment) 
     { 
      int i1 = i - length; 
      int i2 = i - ((int)length/2); 
      int i3 = i; 

      Point p1 = sequence[i1]; 
      Point p2 = sequence[i2]; 
      Point p3 = sequence[i3]; 

      if (p1.X != p3.X & p1.Y != p3.Y)//Is a diagonal 
      { 
       angles[i2] = 180 - Math.Atan(1.0 * (p1.X - p3.X)/(p1.Y - p3.Y)) * 180/Math.PI; 
      } 
      else if (last != double.MinValue) 
      { 
       //USe previous angle to determine non-diagonals (which can be: 0 or 180; 90 or 270) 
       double error; 
       if (p1.X == p3.X)//Is a vertical 
       { 
        error = Math.Abs(last - 180); 
        if (Math.Min(error, 180 - error) == error) 
         angles[i2] = 180; 
        else 
         angles[i2] = 0; 
       } 
       else if (p1.Y == p3.Y)//Is a horizontal 
       { 
        error = Math.Abs(last - 270); 
        if (Math.Min(error, 180 - error) == error) 
         angles[i2] = 270; 
        else 
         angles[i2] = 90; 
       } 
      } 

      last = angles[i2]; 
     } 

     return angles; 
    } 
Cuestiones relacionadas