Esta página es para la versión anterior. La página correspondiente en inglés se eliminó en la versión actual.

Detectar y medir objetos circulares en una imagen

En este ejemplo se muestra cómo utilizar imfindcircles para detectar automáticamente círculos o objetos circulares en una imagen. También muestra el uso de viscircles para visualizar los círculos detectados.

Paso 1: Cargar imagen

Este ejemplo utiliza una imagen de virutas redondas de plástico de varios colores.

rgb = imread('coloredChips.png'); imshow(rgb)

Además de tener un montón de círculos para detectar, hay algunas cosas interesantes sucediendo en esta imagen desde un punto de vista de detección de círculo:

  1. Hay fichas de diferentes colores, que tienen diferentes contrastes con respecto al fondo. En un extremo, los azules y los rojos tienen un fuerte contraste en este fondo. En el otro extremo, algunos de los chips amarillos no contrastan bien con el fondo.

  2. Observe cómo algunos chips son uno encima del otro y algunos otros que están cerca juntos y casi tocándose. Los límites de objeto superpuestos y la oclusión de objetos suelen ser escenarios desafiantes para la detección de objetos.

Paso 2: Determinar el rango de radio para los círculos de búsqueda

imfindcircles necesita un rango de radio para buscar los círculos. Una manera rápida de encontrar el rango de radio adecuado es utilizar la herramienta interactiva imdistline para obtener una estimación aproximada de los radios de varios objetos.

d = imdistline;

imdistline crea una herramienta arrastrable que se puede mover para encajar a través de un chip y los números se pueden leer para obtener una estimación aproximada de su radio. La mayoría de los chips tienen radio en el rango de 21-23 píxeles. Utilice un rango de radio ligeramente más grande de 20-25 píxeles sólo para estar seguro. Antes de quitar la herramienta imdistline.

delete(d)

Paso 3: Intento inicial de encontrar círculos

Llame a imfindcircles en esta imagen con el radio de búsqueda de [20 25] píxeles. Antes de eso, es una buena práctica preguntar si los objetos son más brillantes o más oscuros que el fondo. Para responder a esa pregunta, mire la versión en escala de grises de esta imagen.

gray_image = rgb2gray(rgb); imshow(gray_image)

El fondo es bastante brillante y la mayoría de las fichas son más oscuras que el fondo. Pero, de forma predeterminada, imfindcircles encuentra objetos circulares que son más brillantes que el fondo. Por lo tanto, establezca el parámetro ' ObjectPolarity ' en ' Dark ' en imfindcircles para buscar círculos oscuros.

[centers,radii] = imfindcircles(rgb,[20 25],'ObjectPolarity','dark')
centers =       []   radii =       [] 

Tenga en cuenta que las salidas centers y radii están vacías, lo que significa que no se encontraron círculos. Esto sucede con frecuencia porque imfindcircles es un círculo detector, y similar a la mayoría de los detectores, imfindcircles tiene un umbral de detección interno que determina su sensibilidad. En términos simples significa que la confianza del detector en una cierta detección (del círculo) tiene que ser mayor que un cierto nivel antes de que se considere una detección del válido. imfindcircles tiene un parámetro ' SENSITIVITY ' que puede ser usado para controlar este umbral interno, y consecuentemente, la sensibilidad del algoritmo. Un valor más alto de la "sensibilidad" fija el umbral de detección más bajo y conduce a detectar más círculos. Esto es similar al control de sensibilidad en los detectores de movimiento utilizados en los sistemas de seguridad del hogar.

Paso 4: Aumente la sensibilidad de detección

Volviendo a la imagen de chip, es posible que en el nivel de sensibilidad por defecto todos los círculos son más bajos que el umbral interno, por lo que no se detectaron círculos. De forma predeterminada, ' sensibilidad ', que es un número entre 0 y 1, se establece en 0,85. Aumente la "sensibilidad" a 0,9.

[centers,radii] = imfindcircles(rgb,[20 25],'ObjectPolarity','dark', ...     'Sensitivity',0.9)
centers = 8×2

  146.1895  198.5824
  328.8132  135.5883
  130.3134   43.8039
  175.2698  297.0583
  312.2831  192.3709
  327.1316  297.0077
  243.9893  166.4538
  271.5873  280.8920

radii = 8×1

   23.1604
   22.5710
   22.9576
   23.7356
   22.9551
   22.9995
   22.9055
   23.0298

Esta vez imfindcircles encontró algunos círculos-ocho para ser precisos. centers contiene las localizaciones de los centros del círculo y radii contiene los radios estimados de esos círculos.

Paso 5: Dibujar los círculos en la imagen

La función viscircles se puede utilizar para dibujar círculos en la imagen. Las variables de salida centers y radii de imfindcircles se pueden pasar directamente a viscircles.

imshow(rgb) h = viscircles(centers,radii);

Los centros Circle parecen estar correctamente posicionados y sus radios correspondientes parecen coincidir bien con los chips reales. Pero aún así un buen número de fichas se perdió. Intente aumentar la ' sensibilidad ' aún más, a 0,92.

[centers,radii] = imfindcircles(rgb,[20 25],'ObjectPolarity','dark', ...     'Sensitivity',0.92);  length(centers)
ans = 16 

Así que el aumento de la "sensibilidad" nos da aún más círculos. Trazar estos círculos en la imagen de nuevo.

delete(h)  % Delete previously drawn circles h = viscircles(centers,radii);

Paso 6: Utilizar el segundo método (de dos etapas) para encontrar círculos

Este resultado se ve mejor. imfindcircles tiene dos métodos diferentes para encontrar círculos. Hasta el momento, el método predeterminado, denominado método codificación de fase, se usó para detectar círculos. Hay otro método, popularmente llamado método dos etapas, que está disponible en imfindcircles. Utilice el método de dos etapas y muestre los resultados.

[centers,radii] = imfindcircles(rgb,[20 25],'ObjectPolarity','dark', ...           'Sensitivity',0.92,'Method','twostage');  delete(h) h = viscircles(centers,radii);

El método de dos etapas está detectando más círculos, en la sensibilidad de 0,92. En general, estos dos métodos son complementarios en que tienen diferentes puntos fuertes. El método de codificación de fase es típicamente más rápido y ligeramente más robusto que el método de dos etapas. Pero también puede necesitar niveles más altos de "sensibilidad" para obtener el mismo número de detecciones que el método de dos etapas. Por ejemplo, el método de codificación de fase también encuentra las mismas fichas si el nivel de "sensibilidad" se eleva más alto, digamos a 0,95.

[centers,radii] = imfindcircles(rgb,[20 25],'ObjectPolarity','dark', ...           'Sensitivity',0.95);  delete(h) viscircles(centers,radii);

Tenga en cuenta que tanto los métodos en imfindcircles encuentran los centros y radios de las fichas parcialmente visibles (ocluidas) con precisión.

Paso 7: ¿por qué algunos círculos siguen siendo perdidos?

Mirando el último resultado, es curioso que imfindcircles no encuentre las fichas amarillas en la imagen. Los chips amarillos no tienen un fuerte contraste con el fondo. De hecho, parecen tener intensidades muy parecidas a las de fondo. ¿es posible que los chips amarillos no son realmente ' más oscuro ' que el fondo como se asumió? Para confirmar, vuelva a mostrar la versión en escala de grises de esta imagen.

imshow(gray_image)

Paso 8: Encontrar círculos ' luminosos ' en la imagen

Los chips amarillos son casi la misma intensidad, tal vez incluso más brillante, en comparación con el fondo. Por lo tanto, para detectar las fichas amarillas, cambie ' ObjectPolarity ' a ' Bright '.

[centersBright,radiiBright] = imfindcircles(rgb,[20 25], ...     'ObjectPolarity','bright','Sensitivity',0.92);

Paso 9: Dibujar círculos ' brillantes ' con diferentes colores

Dibuje los círculos brillante en un color diferente, cambiando el parámetro ' color ' en viscircles.

imshow(rgb)  hBright = viscircles(centersBright, radiiBright,'Color','b');

Note que se encontraron tres de los chips amarillos perdidos, pero todavía falta un chip amarillo. Estas virutas amarillas son difíciles de encontrar porque no destacan tan bien como otras en este fondo.

Paso 10: Bajar el valor de ' EdgeThreshold '

Hay otro parámetro en imfindcircles que puede ser útil aquí, a saber ' EdgeThreshold '. Para encontrar círculos, imfindcircles utiliza sólo los píxeles de borde de la imagen. Estos píxeles de borde son esencialmente píxeles con alto valor de gradiente. El parámetro ' EdgeThreshold ' controla cómo alta el valor de degradado en un píxel debe ser antes de que se considere un píxel de borde e incluido en el cálculo. Un valor alto (más cercano a 1) para este parámetro permitirá que sólo se incluyan los bordes fuertes (valores de gradiente más altos), mientras que un valor bajo (más cercano a 0) es más permisivo e incluye incluso los bordes más débiles (valores de gradiente más bajos) en el cómputo. En el caso de la viruta amarilla ausente, puesto que el contraste es bajo, algunos de los pixeles del límite (en la circunferencia del viruta) se esperan tener valores bajos del gradiente. Por lo tanto, baje el parámetro ' EdgeThreshold ' para asegurarse de que la mayor parte de los píxeles de borde para el chip amarillo se incluyen en el cálculo.

[centersBright,radiiBright,metricBright] = imfindcircles(rgb,[20 25], ...     'ObjectPolarity','bright','Sensitivity',0.92,'EdgeThreshold',0.1);  delete(hBright) hBright = viscircles(centersBright, radiiBright,'Color','b');

Paso 11: Dibujar ' Dark ' y ' Bright ' círculos juntos

Ahora imfindcircles encuentra todos los amarillos, y uno verde también. Dibuje estas virutas en azul, junto con las otras virutas que fueron encontradas antes (con ' ObjectPolarity ' fijado a "obscuridad"), en rojo.

h = viscircles(centers,radii);

Todos los círculos son detectados. Una última palabra-debe tenerse en cuenta que el cambio de los parámetros para ser más agresivos en la detección puede encontrar más círculos, pero también aumenta la probabilidad de detectar círculos falsos. Hay un intercambio entre el número de círculos verdaderos que se pueden encontrar (tasa de detección) y el número de círculos falsos que se encuentran con ellos (velocidad de alarma falsa).

¡ Happy Circle Hunting!