detección de círculo robusta (invariante de color y tamaño) con opencv (basada en la transformación de Hough u otras características)


Escribí el siguiente código python muy simple para encontrar círculos en una imagen:

import cv
import numpy as np

WAITKEY_DELAY_MS = 10
STOP_KEY = 'q'

cv.NamedWindow("image - press 'q' to quit", cv.CV_WINDOW_AUTOSIZE);
cv.NamedWindow("post-process", cv.CV_WINDOW_AUTOSIZE);

key_pressed = False
while key_pressed != STOP_KEY:

    # grab image
    orig = cv.LoadImage('circles3.jpg')

    # create tmp images
    grey_scale = cv.CreateImage(cv.GetSize(orig), 8, 1)
    processed = cv.CreateImage(cv.GetSize(orig), 8, 1)


    cv.Smooth(orig, orig, cv.CV_GAUSSIAN, 3, 3)

    cv.CvtColor(orig, grey_scale, cv.CV_RGB2GRAY)

    # do some processing on the grey scale image
    cv.Erode(grey_scale, processed, None, 10)
    cv.Dilate(processed, processed, None, 10)
    cv.Canny(processed, processed, 5, 70, 3)
    cv.Smooth(processed, processed, cv.CV_GAUSSIAN, 15, 15)

    storage = cv.CreateMat(orig.width, 1, cv.CV_32FC3)

    # these parameters need to be adjusted for every single image
    HIGH = 50
    LOW = 140

    try: 
        # extract circles
        cv.HoughCircles(processed, storage, cv.CV_HOUGH_GRADIENT, 2, 32.0, HIGH, LOW)

        for i in range(0, len(np.asarray(storage))):
            print "circle #%d" %i
            Radius = int(np.asarray(storage)[i][0][2])
            x = int(np.asarray(storage)[i][0][0])
            y = int(np.asarray(storage)[i][0][1])
            center = (x, y)

            # green dot on center and red circle around
            cv.Circle(orig, center, 1, cv.CV_RGB(0, 255, 0), -1, 8, 0)
            cv.Circle(orig, center, Radius, cv.CV_RGB(255, 0, 0), 3, 8, 0)

            cv.Circle(processed, center, 1, cv.CV_RGB(0, 255, 0), -1, 8, 0)
            cv.Circle(processed, center, Radius, cv.CV_RGB(255, 0, 0), 3, 8, 0)

    except:
        print "nothing found"
        pass

    # show images
    cv.ShowImage("image - press 'q' to quit", orig)
    cv.ShowImage("post-process", processed)

    cv_key = cv.WaitKey(WAITKEY_DELAY_MS)
    key_pressed = chr(cv_key & 255)

Como se puede ver en los siguientes dos ejemplos, la' calidad de búsqueda del círculo ' varía bastante:

CASO1:

ingreso1detección1post-processed1

CASO2:

ingreso2detección2post-procesado2

Case1 y Case2 son básicamente la misma imagen, pero aún así el algoritmo detecta diferentes círculos. Si presento el algoritmo una imagen con círculos de diferente tamaño, el la detección del círculo podría incluso fallar por completo. Esto se debe principalmente a los parámetros HIGH y LOW que deben ajustarse individualmente para cada nueva imagen.

Por lo tanto mi pregunta: ¿cuáles son las diversas posibilidades de hacer este algoritmo más robusto? Debe ser invariante de tamaño y color para que se detecten diferentes círculos con diferentes colores y en diferentes tamaños. Tal vez el uso de la transformación de Hough no es la mejor manera de hacer las cosas? ¿Hay algo mejor ¿acercamientos?

Author: memyself, 2012-03-25

6 answers

Lo siguiente se basa en mi experiencia como investigador de la visión. A partir de su pregunta parece estar interesado en posibles algoritmos y métodos en lugar de solo una pieza de trabajo de código. Primero doy un script Python rápido y sucio para sus imágenes de muestra y se muestran algunos resultados para demostrar que podría resolver su problema. Después de sacarlos del camino, trato de responder a sus preguntas sobre algoritmos de detección robustos.

Resultados rápidos

Algunas imágenes de muestra (todas las imágenes aparte de la suya se descargan de flickr.com y tienen licencia CC) con los círculos detectados (sin cambiar/ajustar ningún parámetro, se utiliza exactamente el siguiente código para extraer los círculos en todas las imágenes): manchas detectadas en la imagen de muestra 1manchas detectadas en la imagen de muestra 2muchos círculosmanchas en la imagen de flickr 1

Código (basado en el Detector de Blob MSER)

Y aquí está el código:

import cv2
import math
import numpy as np

d_red = cv2.cv.RGB(150, 55, 65)
l_red = cv2.cv.RGB(250, 200, 200)

orig = cv2.imread("c.jpg")
img = orig.copy()
img2 = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

detector = cv2.FeatureDetector_create('MSER')
fs = detector.detect(img2)
fs.sort(key = lambda x: -x.size)

def supress(x):
        for f in fs:
                distx = f.pt[0] - x.pt[0]
                disty = f.pt[1] - x.pt[1]
                dist = math.sqrt(distx*distx + disty*disty)
                if (f.size > x.size) and (dist<f.size/2):
                        return True

sfs = [x for x in fs if not supress(x)]

for f in sfs:
        cv2.circle(img, (int(f.pt[0]), int(f.pt[1])), int(f.size/2), d_red, 2, cv2.CV_AA)
        cv2.circle(img, (int(f.pt[0]), int(f.pt[1])), int(f.size/2), l_red, 1, cv2.CV_AA)

h, w = orig.shape[:2]
vis = np.zeros((h, w*2+5), np.uint8)
vis = cv2.cvtColor(vis, cv2.COLOR_GRAY2BGR)
vis[:h, :w] = orig
vis[:h, w+5:w*2+5] = img

cv2.imshow("image", vis)
cv2.imwrite("c_o.jpg", vis)
cv2.waitKey()
cv2.destroyAllWindows()

Como puede ver, se basa en el detector de blob MSER. El código no preprocesa la imagen aparte de la simple asignación en escala de grises. Por lo tanto, se espera que falten esas manchas amarillas débiles en sus imágenes.

Teoría

En resumen: usted no nos dice lo que sabe sobre el problema, aparte de dar solo dos imágenes de muestra sin descripción de ellos. Aquí explico por qué en mi humilde opinión es importante tener más información sobre el problema antes de preguntar cuáles son los métodos eficientes para atacar el problema.

Volver a la pregunta principal: ¿cuál es el mejor método para este problema? Veamos esto es un problema de búsqueda. Para simplificar la discusión supongamos que estamos buscando círculos con un tamaño/radio dado. Por lo tanto, el problema se reduce a encontrar los centros. Cada píxel es un centro candidato, por lo tanto, el espacio de búsqueda contiene todos los píxeles.

P = {p1, ..., pn} 
P: search space
p1...pn: pixels

Para resolver este problema de búsqueda se deben definir otras dos funciones:

E(P) : enumerates the search space
V(p) : checks whether the item/pixel has the desirable properties, the items passing the check are added to the output list

Asumiendo que la complejidad del algoritmo no importa, se puede usar la búsqueda exhaustiva o de fuerza bruta en la que E toma cada píxel y pasa a V. En aplicaciones en tiempo real es importante reducir el espacio de búsqueda y optimizar la eficiencia computacional de V.

Nos estamos acercando a la pregunta principal. Cómo podríamos definir V, para ser más precisos qué propiedades de los candidatos deberían ser medidas y cómo debería hacer resolver el problema de la dicotomía de dividirlos en deseables e indeseables. El enfoque más común es encontrar algunas propiedades que se pueden utilizar para definir reglas de decisión simples basadas en medición de las propiedades. Esto es lo que estás haciendo por ensayo y error. Estás programando un clasificador aprendiendo de ejemplos positivos y negativos. Esto se debe a que los métodos que estás utilizando no tienen idea de lo que quieres hacer. Hay que ajustar / afinar los parámetros de la regla de decisión y/o preprocesar los datos de manera que se reduzca la variación en las propiedades (de los candidatos deseables) utilizadas por el método para el problema de la dicotomía. Podría usar un algoritmo de aprendizaje automático para encuentre los valores de parámetro óptimos para un conjunto dado de ejemplos. Hay una gran cantidad de algoritmos de aprendizaje desde árboles de decisión hasta programación genética que puedes usar para este problema. También puede usar un algoritmo de aprendizaje para encontrar los valores de parámetros óptimos para varios algoritmos de detección de círculos y ver cuál da una mejor precisión. Esto toma la carga principal en el algoritmo de aprendizaje que solo necesita para recopilar imágenes de muestra.

El otro enfoque para mejorar la robustez que es a menudo pasado por alto es utilizar información adicional disponible. Si conoce el color de los círculos con prácticamente cero esfuerzo adicional, podría mejorar significativamente la precisión del detector. Si conocía la posición de los círculos en el plano y quería detectar los círculos imaginados, debe recordar que la transformación entre estos dos conjuntos de posiciones se describe mediante una homografía 2D. Y la homografía puede ser estimada usando solo cuatro puntos. Entonces usted podría mejorar el robustez para tener un método sólido como una roca. A menudo se subestima el valor del conocimiento específico del dominio. Míralo de esta manera, en el primer enfoque tratamos de aproximar algunas reglas de decisión basadas en un número limitado de muestras. En el segundo enfoque conocemos las reglas de decisión y solo necesitamos encontrar una manera de utilizarlas de manera efectiva en un algoritmo.

Resumen

Para resumir, hay dos enfoques para mejorar la precisión / robustez de la solución:

  1. Basado en herramientas : encontrar un algoritmo más fácil de usar / con menos número de parámetros / ajustar el algoritmo / automatizar este proceso mediante el uso de algoritmos de aprendizaje automático
  2. Basado en la información: ¿está utilizando toda la información disponible? En la pregunta no mencionas lo que sabes sobre el problema.

Para estas dos imágenes que has compartido usaría un detector de blob no el método HT. Para antecedentes resta Sugeriría tratar de estimar el color del fondo ya que en las dos imágenes no está variando mientras que el color de los círculos varía. Y la mayor parte del área está desnuda.

 33
Author: fireant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-17 18:15:14

Este es un gran problema de modelado. Tengo las siguientes recomendaciones / ideas:

  1. Divida la imagen en RGB y luego procese.
  2. preprocesamiento.
  3. Búsqueda dinámica de parámetros.
  4. Agregue restricciones.
  5. Asegúrese de lo que está tratando de detectar.

En más detalle:

1: Como se señaló en otras respuestas, convertir directamente a escala de grises descarta demasiada información, cualquier círculo con un brillo similar al del fondo se perderá. Mucho mejor considerar los canales de color ya sea de forma aislada o en un espacio de color diferente. Hay más o menos dos maneras de ir aquí: realizar HoughCircles en cada canal preprocesado de forma aislada, luego combinar resultados, o, procesar los canales, luego combinarlos, luego operar HoughCircles. En mi intento a continuación, he intentado el segundo método, dividir en canales RGB, procesamiento, luego combinar. Tenga cuidado de sobre saturar la imagen al combinar, utilizo cv.And para evitar este problema (en este etapa mis círculos son siempre anillos negros / discos sobre fondo blanco).

2: El preprocesamiento es bastante complicado, y a menudo es mejor jugar con algo. He hecho uso de AdaptiveThreshold, que es un método de convolución realmente poderoso que puede mejorar los bordes de una imagen mediante la fijación de píxeles en función de su promedio local (procesos similares también ocurren en la ruta temprana del sistema visual de mamíferos). Esto también es útil, ya que reduce algo de ruido. He usado dilate/erode con una sola pasada. Y he mantuviste los otros parámetros como los tenías. Parece que usar Canny antes de HoughCircles ayuda mucho a encontrar 'círculos llenos', así que probablemente sea mejor mantenerlo. Este pre-procesamiento es bastante pesado y puede conducir a falsos positivos con algo más 'círculos blobby', pero en nuestro caso esto es quizás deseable?

3: Como usted ha señalado HoughCircles parámetro param2 (su parámetro LOW) necesita ser ajustado para cada imagen con el fin de obtener una solución óptima, de hecho de la docs :

Cuanto más pequeño es, más falsos círculos pueden ser detectados.

El problema es que el punto dulce va a ser diferente para cada imagen. Creo que el mejor enfoque aquí es establecer una condición y hacer una búsqueda a través de diferentes valores param2 hasta que se cumpla esta condición. Sus imágenes muestran círculos que no se superponen, y cuando param2 es demasiado bajo, normalmente obtenemos un montón de círculos superpuestos. Así que sugiero buscar el:

Máximo número de círculos no superpuestos y no contenidos

Así que seguimos llamando a HoughCircles con diferentes valores de param2 hasta que esto se cumpla. Hago esto en mi ejemplo a continuación, simplemente incrementando param2 hasta que alcanza la suposición de umbral. Sería mucho más rápido (y bastante fácil de hacer) si realiza una búsqueda binaria para encontrar cuando se cumple esto, pero debe tener cuidado con el manejo de excepciones, ya que opencv a menudo arroja errores para valores de aspecto inocente de param2 (al menos en mi instalación). Una condición diferente que sería muy útil para que coincida con sería el número de círculos.

4: ¿Hay más restricciones que podamos agregar al modelo? Cuantas más cosas podamos decirle a nuestro modelo, más fácil será la tarea de detectar círculos. Por ejemplo, ¿sabemos:

  • El número de círculos. - incluso un límite superior o inferior es útil.
  • Posibles colores de los círculos, o del fondo, o de 'no-círculos'.
  • Su Tamaño.
  • Donde pueden estar en una imagen.

5: ¡Algunas de las manchas en sus imágenes solo podrían llamarse círculos vagamente! Considere los dos 'blobs no circulares' en su segunda imagen, mi código no puede encontrarlos (¡bien!), pero... si los 'photoshop' para que sean más circulares, mi código puede encontrarlos... Tal vez si quieres detectar cosas que no son círculos, un enfoque diferente como Tim Lukins puede ser mejor.

Problemas

Haciendo pesado preprocesamiento AdaptiveThresholding y `Canny' puede haber mucha distorsión en las características de una imagen, lo que puede conducir a una detección de círculo falso o un informe de radio incorrecto. Por ejemplo, un disco sólido grande después del procesamiento puede aparecer como un anillo, por lo que HughesCircles puede encontrar el anillo interior. Además, incluso los documentos señalan que:

...por lo general, la función detecta bien los centros de los círculos, sin embargo, puede no encontrar los radios correctos.

Si necesita radios más precisos detection, I suggest the following approach (not implemented):

  • En la imagen original, traza de rayos desde el centro del círculo reportado, en una cruz en expansión (4 rayos: arriba/abajo/izquierda/derecha)
  • Haga esto por separado en cada canal RGB
  • Combine esta información para cada canal para cada rayo de una manera sensible (es decir. flip, offset, scale, etc. según sea necesario)
  • tome el promedio de los primeros píxeles en cada rayo, use esto para detectar donde una desviación significativa en el ray aparece.
  • Estos 4 puntos son estimaciones de puntos en la circunferencia.
  • Utilice estas cuatro estimaciones para determinar un radio más preciso, y la posición del centro(!).
  • Esto podría generalizarse mediante el uso de un anillo en expansión en lugar de cuatro rayos.

Resultados

El código al final hace bastante bien la mayor parte del tiempo, estos ejemplos se hicieron con el código como se muestra:

Detecta todos los círculos en su primera imagen:introduzca la descripción de la imagen aquí

Cómo se ve la imagen preprocesada antes de aplicar el filtro canny (los círculos de diferentes colores son muy visibles):introduzca la descripción de la imagen aquí

Detecta todos menos dos (blobs) en la segunda imagen: introduzca la descripción de la imagen aquí

Segunda imagen alterada (los blobs son circulares, y el óvalo grande se hace más circular, mejorando así la detección), todos detectados: introduzca la descripción de la imagen aquí

Hace bastante bien en la detección de centros en esta pintura de Kandinsky (no puedo encontrar anillos concéntricos debido a la condición de límite). introduzca la descripción de la imagen aquí

Código:

import cv
import numpy as np

output = cv.LoadImage('case1.jpg')
orig = cv.LoadImage('case1.jpg')

# create tmp images
rrr=cv.CreateImage((orig.width,orig.height), cv.IPL_DEPTH_8U, 1)
ggg=cv.CreateImage((orig.width,orig.height), cv.IPL_DEPTH_8U, 1)
bbb=cv.CreateImage((orig.width,orig.height), cv.IPL_DEPTH_8U, 1)
processed = cv.CreateImage((orig.width,orig.height), cv.IPL_DEPTH_8U, 1)
storage = cv.CreateMat(orig.width, 1, cv.CV_32FC3)

def channel_processing(channel):
    pass
    cv.AdaptiveThreshold(channel, channel, 255, adaptive_method=cv.CV_ADAPTIVE_THRESH_MEAN_C, thresholdType=cv.CV_THRESH_BINARY, blockSize=55, param1=7)
    #mop up the dirt
    cv.Dilate(channel, channel, None, 1)
    cv.Erode(channel, channel, None, 1)

def inter_centre_distance(x1,y1,x2,y2):
    return ((x1-x2)**2 + (y1-y2)**2)**0.5

def colliding_circles(circles):
    for index1, circle1 in enumerate(circles):
        for circle2 in circles[index1+1:]:
            x1, y1, Radius1 = circle1[0]
            x2, y2, Radius2 = circle2[0]
            #collision or containment:
            if inter_centre_distance(x1,y1,x2,y2) < Radius1 + Radius2:
                return True

def find_circles(processed, storage, LOW):
    try:
        cv.HoughCircles(processed, storage, cv.CV_HOUGH_GRADIENT, 2, 32.0, 30, LOW)#, 0, 100) great to add circle constraint sizes.
    except:
        LOW += 1
        print 'try'
        find_circles(processed, storage, LOW)
    circles = np.asarray(storage)
    print 'number of circles:', len(circles)
    if colliding_circles(circles):
        LOW += 1
        storage = find_circles(processed, storage, LOW)
    print 'c', LOW
    return storage

def draw_circles(storage, output):
    circles = np.asarray(storage)
    print len(circles), 'circles found'
    for circle in circles:
        Radius, x, y = int(circle[0][2]), int(circle[0][0]), int(circle[0][1])
        cv.Circle(output, (x, y), 1, cv.CV_RGB(0, 255, 0), -1, 8, 0)
        cv.Circle(output, (x, y), Radius, cv.CV_RGB(255, 0, 0), 3, 8, 0)

#split image into RGB components
cv.Split(orig,rrr,ggg,bbb,None)
#process each component
channel_processing(rrr)
channel_processing(ggg)
channel_processing(bbb)
#combine images using logical 'And' to avoid saturation
cv.And(rrr, ggg, rrr)
cv.And(rrr, bbb, processed)
cv.ShowImage('before canny', processed)
# cv.SaveImage('case3_processed.jpg',processed)
#use canny, as HoughCircles seems to prefer ring like circles to filled ones.
cv.Canny(processed, processed, 5, 70, 3)
#smooth to reduce noise a bit more
cv.Smooth(processed, processed, cv.CV_GAUSSIAN, 7, 7)
cv.ShowImage('processed', processed)
#find circles, with parameter search
storage = find_circles(processed, storage, 100)
draw_circles(storage, output)
# show images
cv.ShowImage("original with circles", output)
cv.SaveImage('case1.jpg',output)

cv.WaitKey(0)
 28
Author: fraxel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-13 17:12:41

Ah, sí the los antiguos invariantes de color/tamaño para el problema de los círculos (TAMBIÉN conocido como la transformada de Hough es demasiado específica y no robusta)...

En el pasado he confiado mucho más en las funciones de análisis estructural y de forma de OpenCV. Usted puede obtener una muy buena idea de la carpeta "muestras" de lo que es posible - en particular fitellipse.py y squares.py.

Para su aclaración, presento una versión híbrida de estos ejemplos y basada en su fuente original. Los contornos detectados están en verde y las elipses ajustadas en rojo.

introduzca la descripción de la imagen aquí

Todavía no está ahí:

  • Los pasos de preprocesamiento necesitan un poco de ajuste para detectar los círculos más débiles.
  • Puede probar el contorno más a fondo para determinar si es un círculo o no...

¡Buena suerte!

import cv
import numpy as np

# grab image
orig = cv.LoadImage('circles3.jpg')

# create tmp images
grey_scale = cv.CreateImage(cv.GetSize(orig), 8, 1)
processed = cv.CreateImage(cv.GetSize(orig), 8, 1)

cv.Smooth(orig, orig, cv.CV_GAUSSIAN, 3, 3)

cv.CvtColor(orig, grey_scale, cv.CV_RGB2GRAY)

# do some processing on the grey scale image
cv.Erode(grey_scale, processed, None, 10)
cv.Dilate(processed, processed, None, 10)
cv.Canny(processed, processed, 5, 70, 3)
cv.Smooth(processed, processed, cv.CV_GAUSSIAN, 15, 15)

#storage = cv.CreateMat(orig.width, 1, cv.CV_32FC3)
storage = cv.CreateMemStorage(0)

contours = cv.FindContours(processed, storage, cv.CV_RETR_EXTERNAL)
# N.B. 'processed' image is modified by this!

#contours = cv.ApproxPoly (contours, storage, cv.CV_POLY_APPROX_DP, 3, 1) 
# If you wanted to reduce the number of points...

cv.DrawContours (orig, contours, cv.RGB(0,255,0), cv.RGB(255,0,0), 2, 3, cv.CV_AA, (0, 0)) 

def contour_iterator(contour):
  while contour:
    yield contour
    contour = contour.h_next()

for c in contour_iterator(contours):
  # Number of points must be more than or equal to 6 for cv.FitEllipse2
  if len(c) >= 6:
    # Copy the contour into an array of (x,y)s
    PointArray2D32f = cv.CreateMat(1, len(c), cv.CV_32FC2)

    for (i, (x, y)) in enumerate(c):
      PointArray2D32f[0, i] = (x, y)

    # Fits ellipse to current contour.
    (center, size, angle) = cv.FitEllipse2(PointArray2D32f)

    # Convert ellipse data from float to integer representation.
    center = (cv.Round(center[0]), cv.Round(center[1]))
    size = (cv.Round(size[0] * 0.5), cv.Round(size[1] * 0.5))

    # Draw ellipse
    cv.Ellipse(orig, center, size, angle, 0, 360, cv.RGB(255,0,0), 2,cv.CV_AA, 0)

# show images
cv.ShowImage("image - press 'q' to quit", orig)
#cv.ShowImage("post-process", processed)
cv.WaitKey(-1)

EDITAR:

Solo una actualización para decir que creo que un tema importante para todas estas respuestas es que hay una serie de suposiciones y restricciones adicionales que se puede aplicar a lo que busca reconocer como circular . Mi propia respuesta no hace ninguna pretensión en esto-ni en el pre-procesamiento de bajo nivel o el ajuste geométrico de alto nivel. El hecho de que muchos de los círculos no son realmente tan redondos debido a la forma en que se dibujan o las transformaciones no afines/proyectivas de la imagen, y con las otras propiedades en la forma en que se representan/capturan (color, ruido, iluminación, grosor del borde), todo resulta en cualquier número de posibles círculos candidatos dentro de una sola imagen.

Hay técnicas mucho más sofisticadas. Pero te costarán. Personalmente me gusta @fraxel idea de utilizar el adaptativa umbral. Eso es rápido, confiable y razonablemente robusto. A continuación, puede probar más los contornos finales (por ejemplo, usar momentos Hu) o accesorios con una prueba de relación simple del eje elipse, por ejemplo, if ((min(size)/max(size))>0.7).

Como siempre con la Visión por Computadora existe la tensión entre el pragmatismo, el principio y la parsomonía. Como me gusta de decirle a la gente que piensa que CV es fácil, no lo es-es de hecho famoso un AI completo problema. Lo mejor que a menudo puede esperar fuera de esto es algo que funciona la mayor parte del tiempo.

 11
Author: tiluki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-17 10:26:24

Mirando a través de su código, me di cuenta de lo siguiente:

  • Conversión de escala de grises. Entiendo por qué lo estás haciendo, pero date cuenta de que estás lanzando información de distancia allí. Como puedes ver en las imágenes de "post-proceso", tus círculos amarillos son la misma intensidad que el fondo, solo que en un color diferente.

  • Detección de bordes después de la eliminación de ruido (erae / dilatar). Esto no debería ser necesario; Canny debería hacerse cargo de esto.

  • Detección de Canny edge. Los círculos "abiertos" tienen dos bordes, uno interno y otro externo. Dado que están bastante cerca, el filtro Canny Gauss podría sumarlos. Si no lo hace, tendrá dos bordes juntos. Es decir, antes de Canny, tienes círculos abiertos y llenos. Después, tienes 0/2 y 1 borde, respectivamente. Dado que Hough vuelve a llamar a Canny, en el primer caso los dos bordes podrían suavizarse juntos (dependiendo del ancho inicial), por lo que el algoritmo core Hough puede tratar los círculos abiertos y llenos igual.

Entonces, mi primera recomendación sería cambiar la asignación de escala de grises. No uses intensidad, sino tono / saturación / valor. Además, usa un enfoque diferencial: estás buscando bordes. Por lo tanto, calcular una transformación HSV, suavizar una copia, y luego tomar la diferencia entre la copia original y suavizado. Esto le dará dH, dS, dV valores (variación local en Tono, Saturación, Valor) para cada punto. Cuadrar y agregar para obtener una imagen unidimensional, con picos cerca de todos los bordes (interior y exterior).

Mi segunda recomendación sería la normalización local, pero no estoy seguro de si eso es siquiera necesario. La idea es que no te importa mucho el valor exacto de la señal de borde que saliste, realmente debería ser binaria de todos modos (borde o no). Por lo tanto, puede normalizar cada valor dividiendo por un promedio local (donde local está en el orden de magnitud del tamaño de su borde).

 8
Author: MSalters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-26 13:37:47

La transformación de Hough utiliza un "modelo" para encontrar ciertas características en una imagen (típicamente) detectada en los bordes, como puede saber. En el caso de HoughCircles ese modelo es un círculo perfecto. Esto significa que probablemente no existe una combinación de parámetros que lo harán detectar los círculos en forma de elipse y erráticamente en su imagen sin aumentar el número de falsos positivos. Por otro lado, debido al mecanismo de votación subyacente, un círculo perfecto no cerrado o un círculo perfecto con una "dent" podría aparecer constantemente. Así que dependiendo de su salida esperada puede o no querer usar este método.

Dicho esto, hay algunas cosas que veo que podrían ayudarte en tu camino con esta función:{[16]]}

  1. HoughCircles llama a Canny internamente, así que supongo que puedes dejar esa llamada.
  2. param1 (que se llama HIGH) se inicializa típicamente alrededor de un valor de 200. Se utiliza como parámetro para la llamada interna a Canny: cv.Canny(processed, cannied, HIGH, HIGH/2). Podría ayudar a ejecute Canny usted mismo para ver cómo la configuración HIGH afecta a la imagen con la que trabaja la transformación de Hough.
  3. param2 (que se llama LOW) se inicializa típicamente alrededor de un valor 100. Es el umbral de votación para los acumuladores de la transformada de Hough. Fijarlo más alto significa más falsos negativos, más bajos falsos positivos. Creo que este es el primero con el que quieres empezar a jugar.

Ref: http://docs.opencv.org/3.0-beta/modules/imgproc/doc/feature_detection.html#houghcircles

Update re: filled circles : Después de encontrar las formas de círculo con la transformación de Hough, puede probar si están llenas muestreando el color límite y comparándolo con uno o más puntos dentro del supuesto círculo. Alternativamente, puede comparar uno o más puntos dentro del supuesto círculo con un color de fondo dado. El círculo se llena si la comparación anterior tiene éxito, o en el caso de la comparación alternativa si falla.

 6
Author: Eric,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-09 09:22:51

Ok mirando las imágenes. Sugiero usar **Active Contours**

  • Contornos activos Lo bueno de los contornos activos es que casi encajan perfectamente en cualquier forma dada. Ya sean cuadrados o triángulos y en su caso son los candidatos perfectos.
  • Si eres capaz de extraer el centro de los círculos, eso es genial. Los contornos activos siempre necesitan un punto a partir del cual puedan crecer o encogerse para ajustarse. No es necesario que los centros estén siempre alineados al centro. Un poco de compensación todavía estará bien.
  • Y en su caso, si deja que los contornos crezcan desde el centro hacia afuera, descansarán en los límites del círculo.
  • Tenga en cuenta que los contornos activos que crecen o se contraen utilizan energía de globo lo que significa que puede establecer la dirección de los contornos, hacia adentro o hacia afuera.
  • Probablemente necesite usar la imagen degradada en escala de grises. Pero aún así puedes probar en color también. Si funciona!
  • Y si no proporciona los centros, echan en porciones de contornos activos, hacen entonces crecer / encoger. Los contornos que se asientan se mantienen, los inconstantes se desechan. Este es un enfoque de fuerza bruta. Será intensivo de CPU. Pero requerirá un trabajo más cuidadoso para asegurarse de dejar contornos correctos y tirar los malos.

Espero que así puedas resolver el problema.

 2
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-11 13:35:13