El etiquetado de componentes conectados ( CCL ), el análisis de componentes conectados ( CCA ), la extracción de blobs , el etiquetado de regiones , el descubrimiento de blobs o la extracción de regiones es una aplicación algorítmica de la teoría de grafos , donde los subconjuntos de componentes conectados se etiquetan de forma única en función de una heurística determinada . El etiquetado de componentes conectados no debe confundirse con la segmentación .
El etiquetado de componentes conectados se utiliza en visión artificial para detectar regiones conectadas en imágenes digitales binarias , aunque también se pueden procesar imágenes en color y datos con mayor dimensionalidad. [1] [2] Cuando se integra en un sistema de reconocimiento de imágenes o una interfaz de interacción hombre-computadora , el etiquetado de componentes conectados puede operar sobre una variedad de información. [3] [4] La extracción de blobs generalmente se realiza en la imagen binaria resultante de un paso de umbralización, pero también se puede aplicar a imágenes en escala de grises y en color. Los blobs se pueden contar, filtrar y rastrear.
La extracción de blobs está relacionada con la detección de blobs, pero es distinta .
Un gráfico, que contiene vértices y aristas de conexión , se construye a partir de datos de entrada relevantes. Los vértices contienen información requerida por la heurística de comparación, mientras que las aristas indican "vecinos" conectados. Un algoritmo recorre el gráfico, etiquetando los vértices en función de la conectividad y los valores relativos de sus vecinos. La conectividad está determinada por el medio; los gráficos de imágenes, por ejemplo, pueden ser de vecindad 4-conectada o de vecindad 8-conectada . [5]
Después de la etapa de etiquetado, el gráfico se puede dividir en subconjuntos, después de lo cual se puede recuperar y procesar la información original.
El uso del término etiquetado de componentes conectados (CCL) y su definición es bastante consistente en la literatura académica, mientras que el análisis de componentes conectados (CCA) varía en términos tanto de terminología como de definición del problema.
Rosenfeld et al. [6] definen el etiquetado de componentes conectados como la “creación de una imagen etiquetada en la que las posiciones asociadas con el mismo componente conectado de la imagen de entrada binaria tienen una etiqueta única”. Shapiro et al. [7] definen CCL como un operador cuya “entrada es una imagen binaria y [...] la salida es una imagen simbólica en la que la etiqueta asignada a cada píxel es un número entero que identifica de forma única el componente conectado al que pertenece ese píxel”. [8]
No existe consenso sobre la definición de CCA en la literatura académica. A menudo se utiliza indistintamente con CCL. [9] [10] Shapiro et al. ofrecen una definición más amplia: [7] “El análisis de componentes conectados consiste en el etiquetado de componentes conectados de los píxeles negros seguido de la medición de propiedades de las regiones componentes y la toma de decisiones”. La definición de análisis de componentes conectados que se presenta aquí es más general y tiene en cuenta las ideas expresadas en [7] [9] [10] .
Los algoritmos analizados pueden generalizarse a dimensiones arbitrarias, aunque con mayor complejidad temporal y espacial.
Este es un método rápido y muy sencillo de implementar y comprender. Se basa en los métodos de recorrido de grafos de la teoría de grafos. En resumen, una vez que se encuentra el primer píxel de un componente conectado, se etiquetan todos los píxeles conectados de ese componente conectado antes de pasar al siguiente píxel de la imagen. Este algoritmo es parte del algoritmo de segmentación de cuencas hidrográficas de Vincent y Soille [11] , también existen otras implementaciones. [12]
Para ello, se forma una lista enlazada que mantendrá los índices de los píxeles que están conectados entre sí, pasos (2) y (3) a continuación. El método de definición de la lista enlazada especifica el uso de una búsqueda en profundidad o en amplitud . Para esta aplicación en particular, no hay diferencia en qué estrategia utilizar. El tipo más simple de cola de último en entrar, primero en salir implementada como una lista enlazada simple dará como resultado una estrategia de búsqueda en profundidad.
Se supone que la imagen de entrada es una imagen binaria , con píxeles de fondo o de primer plano y que se desean los componentes conectados en los píxeles de primer plano. Los pasos del algoritmo se pueden escribir de la siguiente manera:
Tenga en cuenta que los píxeles se etiquetan antes de colocarlos en la cola. La cola solo conservará un píxel para verificar sus vecinos y agregarlos a la cola si es necesario. Este algoritmo solo necesita verificar los vecinos de cada píxel de primer plano una vez y no verifica los vecinos de los píxeles de fondo.
El pseudocódigo es:
algoritmo OneComponentAtATime(data) entrada : imageData[xDim][yDim] inicialización : etiqueta = 0, labelArray[xDim][yDim] = 0, statusArray[xDim][yDim] = falso, cola1, cola2; para i = 0 a xDim hacer para j = 0 a yDim hacer si imageData[i][j] no ha sido procesado hacer si imageData[i][j] es un píxel de primer plano hacer Compruébalo cuatro vecinos (norte, sur, este, oeste): Si el vecino no se procesa, haz lo siguiente: si el vecino es un píxel de primer plano, haz lo siguiente: añadirlo a la cola1 demás Actualizar su estado como procesado terminar si labelArray[i][j] = etiqueta (dar etiqueta) statusArray[i][j] = true (estado de actualización) mientras queue1 no esté vacía Para cada píxel de la cola, haga lo siguiente: Compruébalo, cuatro vecinos Si el vecino no se procesa, haz lo siguiente: si el vecino es un píxel de primer plano, haz lo siguiente: añadirlo a la cola2 demás Actualizar su estado como procesado terminar si Dale la etiqueta actual Actualizar su estado como procesado eliminar el elemento actual de la cola1 Copiar cola2 en cola1 Fin Mientras aumentar la etiqueta termina si no Actualizar su estado como procesado fin si fin si fin si fin para fin para
Relativamente simple de implementar y comprender, el algoritmo de dos pasadas [13] (también conocido como algoritmo Hoshen–Kopelman ) itera a través de datos binarios bidimensionales. El algoritmo realiza dos pasadas sobre la imagen: la primera pasada para asignar etiquetas temporales y equivalencias de registros, y la segunda pasada para reemplazar cada etiqueta temporal por la etiqueta más pequeña de su clase de equivalencia.
Los datos de entrada se pueden modificar in situ (lo que conlleva el riesgo de corrupción de datos ) o la información de etiquetado se puede mantener en una estructura de datos adicional.
Las comprobaciones de conectividad se llevan a cabo comprobando las etiquetas de los píxeles vecinos (los elementos vecinos cuyas etiquetas aún no están asignadas se ignoran), o, por ejemplo, el noreste, el norte, el noroeste y el oeste del píxel actual (suponiendo una conectividad de 8). La conectividad de 4 utiliza solo los vecinos del norte y el oeste del píxel actual. Se comprueban las siguientes condiciones para determinar el valor de la etiqueta que se asignará al píxel actual (se supone una conectividad de 4):
Condiciones a comprobar:
El algoritmo continúa de esta manera y crea nuevas etiquetas de región cuando sea necesario. Sin embargo, la clave para un algoritmo rápido es cómo se realiza esta fusión. Este algoritmo utiliza la estructura de datos union-find que proporciona un excelente rendimiento para realizar un seguimiento de las relaciones de equivalencia. [14] Union-find almacena esencialmente etiquetas que corresponden al mismo blob en una estructura de datos de conjunto disjunto , lo que facilita recordar la equivalencia de dos etiquetas mediante el uso de un método de interfaz. Por ejemplo: findSet(l). findSet(l) devuelve el valor de etiqueta mínimo que es equivalente al argumento de función 'l'.
Una vez completado el etiquetado inicial y el registro de equivalencia, la segunda pasada simplemente reemplaza cada etiqueta de píxel con su elemento representativo del conjunto disjunto equivalente.
A continuación se presenta un algoritmo de escaneo más rápido para la extracción de regiones conectadas. [15]
En la primera pasada:
En la segunda pasada:
Aquí, el fondo es una clasificación específica de los datos que se utiliza para distinguir los elementos salientes del primer plano . Si se omite la variable de fondo, el algoritmo de dos pasadas tratará el fondo como otra región.
1. La matriz de la que se extraerán las regiones conectadas se muestra a continuación (basada en 8 conectividades).
Primero asignamos diferentes valores binarios a los elementos del gráfico. Los valores "0~1" en el centro de cada uno de los elementos del gráfico siguiente son los valores de los elementos, mientras que los valores "1,2,...,7" en los dos gráficos siguientes son las etiquetas de los elementos. No deben confundirse los dos conceptos.
2. Después de la primera pasada, se generan las siguientes etiquetas:
Se generan un total de 7 etiquetas de acuerdo con las condiciones resaltadas anteriormente.
Las relaciones de equivalencia de etiquetas generadas son,
3. Se genera la matriz después de realizar la fusión de etiquetas. Aquí, el valor de etiqueta que era el más pequeño para una región dada se "inunda" por toda la región conectada y da dos etiquetas distintas y, por lo tanto, dos etiquetas distintas.
4. Resultado final en color para ver claramente dos regiones diferentes que se han encontrado en la matriz.
El pseudocódigo es:
El algoritmo TwoPass(datos) es vinculado = [] etiquetas = estructura con dimensiones de datos, inicializada con el valor de Fondo SiguienteEtiqueta = 0 Primer pase para la fila de datos, hacer para la columna de la fila, hacer si datos[fila][columna] no es Fondo, entonces vecinos = elementos conectados con el valor del elemento actual Si los vecinos están vacíos, entonces linked[NextLabel] = conjunto que contiene NextLabel etiquetas[fila][columna] = NextLabel Etiqueta siguiente += 1 demás Encuentra la etiqueta más pequeña L = etiquetas de vecinos etiquetas[fila][columna] = min (L) para etiqueta en L hacer vinculado[etiqueta] = unión (vinculado[etiqueta], L) Segundo pase para fila en datos hacer para columna en fila hacer si datos[fila][columna] no es Fondo entonces etiquetas[fila][columna] = find (etiquetas[fila][columna]) etiquetas de devolución
Los algoritmos de búsqueda y unión se implementan como se describe en unión búsqueda .
Crear un contador de regiones
Escanee la imagen (en el siguiente ejemplo, se supone que el escaneo se realiza de izquierda a derecha y de arriba a abajo):
Algunos de los pasos presentes en el algoritmo de dos pasadas se pueden fusionar para lograr mayor eficiencia, lo que permite realizar un único barrido de la imagen. También existen algoritmos de múltiples pasadas, algunos de los cuales se ejecutan en tiempo lineal en relación con la cantidad de píxeles de la imagen. [16]
A principios de la década de 1990, hubo un interés considerable en paralelizar algoritmos de componentes conectados en aplicaciones de análisis de imágenes , debido al cuello de botella del procesamiento secuencial de cada píxel. [17]
El interés por el algoritmo surge nuevamente con un uso extensivo de CUDA.
Algoritmo:
Un componente a la vez ( imagen ) [M, N] := tamaño( imagen ) conectado := ceros(M, N) marca := valor diferencia := incremento desplazamientos := [-1; M; 1; -M] índice := [] no_of_objects := 0 para i: 1:M hacer para j: 1:N hacer si ( imagen (i, j) == 1) entonces no_de_objetos := no_de_objetos + 1 índice := [((j-1) × M + i)] conectado ( índice ) := marca mientras ~isempty( índice ) hacer imagen ( índice ) := 0 vecinos := bsxfun(@plus, índice , desplazamientos ) vecinos := únicos( vecinos (:)) índice := vecinos (find( imagen ( vecinos ))) conectado ( índice ) := marca fin mientras marca := marca + diferencia fin si fin para fin para
El tiempo de ejecución del algoritmo depende del tamaño de la imagen y de la cantidad de primer plano. La complejidad temporal es comparable a la del algoritmo de dos pasadas si el primer plano cubre una parte significativa de la imagen. De lo contrario, la complejidad temporal es menor. Sin embargo, el acceso a la memoria está menos estructurado que en el algoritmo de dos pasadas, lo que tiende a aumentar el tiempo de ejecución en la práctica.
En las últimas dos décadas se han propuesto muchos enfoques novedosos para el etiquetado de componentes conectados, pero casi ninguno de ellos ha sido sometido a una evaluación comparativa de rendimiento utilizando el mismo conjunto de datos. YACCLAB [18] [19] (acrónimo de Yet Another Connected Components Labeling Benchmark) es un ejemplo de un marco de código abierto C++ que recopila, ejecuta y prueba algoritmos de etiquetado de componentes conectados.
La aparición de FPGAs con capacidad suficiente para realizar tareas complejas de procesamiento de imágenes también dio lugar a arquitecturas de alto rendimiento para el etiquetado de componentes conectados. [20] [21] La mayoría de estas arquitecturas utilizan la variante de paso único de este algoritmo, debido a los recursos de memoria limitados disponibles en un FPGA . Estos tipos de arquitecturas de etiquetado de componentes conectados pueden procesar varios píxeles de imagen en paralelo, logrando así un alto rendimiento y una baja latencia de procesamiento.