?‍? JERARQUÍA de CONTORNOS – OpenCV y Python

Por Administrador

En el post anterior toqué el tema de como encontrar contornos en una imagen y como dibujarlos. Vimos algunos de los argumentos que cv2.findContours toma como entrada para encontrar los contornos de una imagen binaria. Recordemos:

Figura 1: Función cv2.findContours. Hoy veremos como afecta en ‘hierarchy’, los 4 opciones del argumento mode.

Sin embargo faltaba explicar qué valores se obtenía en «hierarchy», cuando se usa: cv2.RETR_EXTERNAL, cv2.RETR_LIST, cv2.RETR_CCOMP y cv2.RETR_TREE. Esto es precisamente lo que veremos hoy, para ello usaremos la imagen ejemplo del post anterior. ¡Empecemos!

Jerarquía de contornos

La jerarquía de contornos hace referencia a la relación entre contornos, como relación padre e hijo. Pero para ilustrar mejor como se relacionan, observemos la siguiente imagen:

Figura 2: Izq. Jerarquía padre e hijo. Der. Mismo nivel de jerarquía.

Como ves, para la explicación he usado emojis, esto nos ayudará (según yo) a distinguir entre jerarquías. En la figura 1 a la izquierda, muestra una imagen binaria que tiene un contorno externo y uno interno. La relación que tendrían es que el externo (que está en verde) es padre, mientras el interno (que se encuentra en azul) su hijo.

Otro aspecto que debemos tener en claro es, cuando los contornos se encuentran a un mismo nivel de jerarquía, esto lo vemos en la imagen derecha en la figura 1, con los tres contornos (que están de verde, azul y naranja). Aquí ninguno esta dentro de otro, por lo tanto poseen el mismo nivel de jerarquía.

¿Cómo se representa la JERARQUÍA DE CONTORNOS en OpenCV?

Cada contorno va a almacenar información acerca de su jerarquía, así pues de cada contorno se obtendrá un array con:

  • Next, hace referencia al siguiente contorno en el mismo nivel de jerarquía.
  • Previous, hace referencia al contorno anterior en el mismo nivel de jerarquía.
  • First_Child, hace referencia al primer hijo del contorno.
  • Parent, por último indica el padre contorno.

Jerarquía de contornos aplicando cv2.RETR_EXTERNAL

Debemos recordar que al usar cv2.RETR_EXTERNAL, recupera los contornos externos, solo los más antiguos de la familia, no el resto. Entonces volvamos a la imagen usada el post anterior, allí vimos como dibujar cada contorno mientras presionábamos una tecla, (aquí puedes ver el orden en el que aparece cada contorno).

Una vez que sabemos el orden en el que van apareciendo los contornos, procedemos al análisis de los arrays obtenemos en ‘hierarchy’.

Figura 3: Jerarquía de contornos usando cv2.RETR_EXTERNAL.

La figura 3, es una captura del video que he hecho sobre jerarquía de contornos. Puedes revisarlo, creo que te podría ayudar de mejor manera ya que se puede apreciar la relación de los contornos mediante emojis.

NOTA: Dado que cv2.RETR_EXTERNAL únicamente toma a los más antiguos de la familia, se tendrá un solo nivel de jerarquía, esto hay que tenerlo en cuenta.

Vamos a analizar los contornos en la posición 0, 1 y 2:

  • Contorno 0: el siguiente contorno (next) es 1, tanto el contorno anterior (previous) como el primer hijo (first_child) y padre (parent) se les asigna -1, de aquí en adelante, cuando no exista contorno se asignará -1.
  • Contorno 1: El siguiente contorno es 2, el anterior 0, para el contorno primer hijo y padre -1.
  • Contorno 2: No hay contorno siguiente, por lo tanto se asigna -1, el contorno anterior 1, y contorno primer hijo y padre -1.

Jerarquía de contornos aplicando cv2.RETR_LIST

cv2.RETR_LIST, recupera todos los contornos sin establecer jerarquía (ninguna relación padre e hijo). Aquí puedes ver el orden en el que aparece cada contorno.

Ahora que tenemos el orden en el que van saliendo los contornos, analicemos ‘hierarchy’.

Figura 4: Jerarquía de contornos usando cv2.RETR_LIST.

Los contornos que vamos a analizar son los siguientes:

  • Contorno 0: el siguiente contorno (next) es 1, tanto el contorno anterior (previous) como el primer hijo (first_child) y padre (parent) se les asigna -1, ya que no existen.
  • Contorno 1: El contorno siguiente en el mismo nivel sería el 2, mientras que el contorno anterior en el mismo nivel de jerarquía 0. Igualmente, para el contorno del primer hijo, como para contorno padre se asigna -1.
  • Contorno 2: El siguiente contorno sería 3, mientras que el anterior 1, tanto first_child como para parent -1.

Este procedimiento sigue para el resto de contornos.

Jerarquía de contornos aplicando cv2.RETR_CCOMP

Organiza los contornos en jerarquía de dos niveles. Es decir que si tenemos un contorno externo tendrá jerarquía 1, y uno interno jerarquía 2. Si este a su vez tiene otro contorno tendrá jerarquía 1. Esto lo veremos de mejor manera en esta imagen:

Figura 5: Imagen binaria en donde se ha representado la jerarquía de 2 niveles en amarillo y azul.

En la imagen de la figura 5 podemos encontrar contornos dentro de otros contornos, por ejemplo el primer contorno externo en amarillo se le va a asignar una jerarquía de 1, lo que podemos ver entre paréntesis, mientras el contorno interno a este tomará jerarquía 2 ya que es el hijo.

Luego nos encontramos con un nuevo contorno, este tendrá jerarquía 1 nuevamente, mientras que el interno a este 2. Por último tenemos un círculo, el contorno de este tendrá jerarquía 1. Si hubiera más contornos anidados se seguiría con el mismo procedimiento.

Procedemos a analizar la imagen que hemos estado usando a lo largo del video. (Aquí puedes ver el orden en el que aparece cada contorno)

Si analizamos los contornos con su jerarquía con lo que vimos recientemente y además indicamos el orden de aparición de los mismos al usar cv2.RETR_CCOMP obtendremos lo siguiente:

Figura 6: Jerarquía de contornos usando cv2.RETR_CCOMP.

Con estos dos ingredientes, tanto las jerarquías como el orden de cada uno de ellos podemos proceder a analizar cada contorno.

  • Contorno 0: El contorno siguiente en el mismo nivel de jerarquía sería 1, el contorno anterior no existe y pondremos -1. Este contorno no posee ni un primer hijo ni padre, por ello se colocará -1.
  • Contorno 1: El siguiente contorno en el mismo nivel es 2, el anterior 0, ya que ambos tienen poseen el mismo nivel de jerarquía (Recordemos que estamos usando la información que tenemos en los paréntesis), estamos analizando el contorno 1, ahora este no posee primer hijo ni padre por ello colocamos -1.
  • Contorno 2: El siguiente contorno es 3, mientras el anterior 1, para primer hijo como para padre colocamos -1.
  • Contorno 3: El siguiente contorno es 4, el anterior es 2, primer hijo y padre -1.

En los contornos 1, 2 y 3 puede recaer ciertas dudas, ya que decimos que no poseen padre y claramente están dentro de otro contorno. Esto se debe al uso de cv2.RETR_CCOMP, ya que como estos pasan a tener jerarquía 1, ya no tiene importancia si están o no dentro de otro contorno.

  • Contorno 4: El contorno siguiente es 6, el anterior 3, su primer hijo es 5, mientras que no posee padre por lo tanto colocamos -1.
  • Contorno 5: Este es hijo de 4. No posee ni siguiente contorno y anterior, tampoco primer hijo, por ello ponemos -1, mientras que su padre es 4.
  • Contorno 6: El siguiente contorno es 8, el anterior es 4, su primer hijo es 7, y en padre -1.
  • Contorno 7: Este posee jerarquía 2, ya que es hijo del contorno 6, de este modo el siguiente contorno en su mismo nivel, como el anterior y primer hijo pondremos -1 ya que no existen. Mientras que para padre el contorno 6.

Este análisis lo realizamos con el resto de contornos.

Jerarquía de contornos aplicando cv2.RETR_TREE

Por último veremos cv2.RETR_TREE que recupera todos los contornos con sus jerarquías. (Aquí puedes ver el orden en el que aparece cada contorno)

Ahora vamor por ‘hierarchy’.

Figura 7: Jerarquía de contornos usando cv2.RETR_TREE.

Es hora de analizar cada contorno.

  • Contorno 0: El siguiente contorno es 1, en el contorno anterior -1, no posee primer hijo ni padre por lo que también pondremos -1.
  • Contorno 1: El siguiente contorno en la misma jerarquía es 6, el anterior en la misma jerarquía es 0, su primer hijo es el contorno 2, mientras que no posee padre por lo tanto pondremos -1.
  • Contorno 2: El contorno siguiente como anterior en el mismo nivel de jerarquía no existen por lo tanto pondremos -1, su primer hijo es 3, mientras que su padre es 1.
  • Contorno 3: El siguiente contorno en su misma jerarquía es 4, no existe contorno anterior ni primer hijo por lo tanto ponemos -1, mientras que su padre es 2.
  • Contorno 4: El siguiente contorno en su mismo nivel de jerarquía es 5, el anterior 3, no tiene primer hijo, y su padre es 2.
  • Contorno 5: El siguiente contorno en el mismo nivel de jerarquía no existe por lo que se asigna -1, el contorno anterior es 4, el contorno primer hijo -1 mientras que el contorno padre es 2.

Seguimos el mismo procedimiento para los contornos restantes.

Referencias

  • https://docs.opencv.org/3.4.3/d9/d8b/tutorial_py_contours_hierarchy.html

#infoOmes