Para extraer las características de una imagen basado en descriptores de forma, previamente es necesario llevar a cavo una técnica de segmentación, para delimitar la región de interés que se desea analizar.

La idea de los algoritmos de segmentación es dividir la imagen en diferentes segmentos(objetos) para posteriormente facilitar la comprensión del contenido. Lo que hacen es asignar una etiqueta a cada pixel, por lo que los pixeles con la misma etiqueta comparten características similares.

Detección de objetos
Segmentación semántica
Segmentación de instancia

Estos algoritmos de segmentación son muy usados en diferentes ámbitos, estamos rodeados por sistemas que dependen de recursos gráficos:

  • Reconocimiento de objetos en cámaras
  • Análisis de imágenes medicas
  • Reconocimiento aéreo(drones)
  • Reconocimiento de patrones
  • Conducción autónoma

Algunas de las técnicas de segmentación son:

  • Métodos de umbralización(thresholding)
  • Métodos basados en espacio de color
  • Detección de bordes
  • Crecimiento de regiones(region growing)
  • Métodos de agrupación(clustering)
  • Watershed
  • Autoencoders(redes neuronales convolucionales)

En este post solo vamos a trabajar con los métodos mas sencillos.

Thresholding

  1. Necesitamos generar una mascara, y el primer paso es pasar nuestra imagen a escala de grises; esto nos ayudara a separar las formas del fondo.
  2. Vamos a visualizar el histograma que nos indica el numero de pixeles y su intensidad.
  3. A partir de los valores que visualizamos en el histogramas generamos la mascara final.

Esta imagen tiene una particularidad y es que el fondo es blanco y las formas son muy fáciles de reconocer, en este caso utilizamos THRESH_BINARY_INV y en la segunda alternativa para sacar la mascara utilizamos la condición mask<t, de esta manera le indicamos que todos los pixeles menor al umbral son los que queremos destacar. En una imagen con color de fondo lo mas probable es que necesitemos usar las operaciones opuestas, es decir, THRESH_BINARY y mask>t, pero esto también depende de los colores y que tan fáciles sean de separar. Recordemos que esta es una de las técnicas mas básicas de segmentación.

Ahora, vemos en el anterior ejemplo que el umbral lo sacamos manualmente, utilizando el histograma vemos la distribución de pixeles y su intensidad y decidimos que en este caso 180 era el umbral indicado. Esto obviamente no es posible cuando tenemos grandes cantidades de datos, la idea es que el umbral se pueda seleccionar de manera automática. La librería de OpenCV nos provee un método para hacer esto, usando la técnica de OTSU, este algoritmo consta de los siguientes pasos:

  1. Crear dos clases, una con los valores de intensidad de 0 hasta el t(umbral), y la otra clase desde t hasta la intensidad máxima encontrada en la escala. Entonces se itera sobre cada pixel se obtiene la intensidad de gris y se almacena en un vector que corresponde a cada clase.
    c_1=[0,1,2,\cdots ,t]
    c_1=[t+1,t+2,\cdots ,L]
  2. Se define la probabilidad del nivel de gris i
    p_i=\frac{f_i}{N}, siendo f_i la frecuencia de repetición del nivel de gris i
  3. Se calculan las medias para cada una de las clases
    \mu_1=\sum_{i=0}^{t}\frac{i\cdot p_i}{\omega_1(t)}; \omega_1(t)=\sum_{i=0}^{t}p_i
    \mu_2=\sum_{i=t+1}^{L}\frac{i\cdot p_i}{\omega_2(t)}; \omega_2(t)=\sum_{i=t+1}^{L}p_i
  4. Obtener la intensidad media total de la imagen
    \mu_r=\omega_1\cdot\mu_1+\omega_2\cdot\mu_2
  5. Calcular la varianza entre clases
    \sigma^2=\omega_1(\mu_1-\mu_r)^2+\omega_2(\mu_2-\mu_r)^2
  6. Se selecciona el umbral optimo, es aquel que maximiza la varianza, es decir vamos iterando sobre los anteriores pasos y donde la varianza sea máxima será nuestro umbral.
    t'=Max(\sigma^2(t))

En el siguiente ejemplo implementamos esta técnica, todos los pasos ya están integrados en la librería de OpenCV, lo que vamos a hacer es sumarle a THRESH_BINARY_INV el THRESH_OTSU, esto lo hacemos justamente por que nuestra imagen tiene el fondo blanco, si fuese a color utilizaríamos directamente THRESH_OTSU.

Espacios de color

Vamos a obtener las figuras amarillas, para esto vamos a tener que utilizar las transformaciones de color para destacar justamente el canal amarillo y luego utilizamos los mismos pasos que en la segmentación anterior. En el caso de la mascara le resto un poco al máximo ya que el color en las formas no es un amarillo homogéneo.

Detección de bordes

En este caso vamos a obtener nuestra imagen y aplicaremos un filtro gaussiano(blur) para reducir el ruido, no es necesario pero se suele recomendar. Luego aplicaremos el método de Canny, rellenar y así obtenemos la mascara.

Es importante conocer que hace internamente el método de Canny para así entender los resultados.

  1. Detectar bordes con Sobel: calcula la primera derivada para obtener el gradiente de intensidad en cada pixel, es decir que mide los cambios de intensidad en la imagen: esto lo hace con dos mascaras de convoluciones con kernels de 3×3, uno para los cambios horizontales y el otro para los cambios verticales. Se obtiene G_x y G_y que representan las aproximaciones de las derivadas de intensidades.
    Operador Sobel

    En cada pixel se combinan las aproximaciones de las derivadas para obtener la magnitud G
    G=\sqrt{G_{x}^{2}+G_{y}^{2}}

    Y con esto podemos calcular la dirección del gradiente: La dirección puede ser en estos ángulos(0, 45, 90 o 135)
    \Theta=arctan(\frac{G_y}{G_x})

  2. Filtrado de bordes mediante la supresión non-máximum: permite adelgazar los bordes basándose en el gradiente, elimina los pixeles que no corresponden a un borde. Esto lo hace comparando el valor de intensidad de cada pixel con los pixeles vecinos en la dirección del gradiente.
  3. Umbralización por histéresis: establece dos umbrales(máximo y mínimo):
    • Si el valor del pixel es mayor que el umbral máximo, el pixel se considera parte del borde.
    • Si el valor del pixel es menor que el umbral mínimo, el pixel no se considera parte del borde.
    • Si el valor del pixel esta entre el umbral mínimo y el máximo, el pixel se considera parte del borde si esta conectado a otro pixel que es borde.

En el ejemplo vamos a ver que una de las figuras(estrella) no se resalta y eso es por que el borde esta abierto. Eso lo podemos solucionar probando con el filtro gaussiano, por ahora el que mejor me funciono fue 5 x 5. También aplique al método Canny la dilatación de bordes para solventar el problema.

Crecimiento de regiones

Este método esta implementado de manera muy sencillita. Consiste en coger un punto como semilla y a partir de este ir coloreando, en este caso el punto 0,0 sabemos que esta vacío, por lo que iremos rellenando con negro, nos quedara un fondo negro con formas a color, para completar la mascara simplemente hacemos una transformación de color y listo.