Python OpenCV: etiquetado y análisis de componentes conectados

En este artículo, aprenderemos a implementar el etiquetado y el análisis de componentes conectados mediante OpenCV en Python.

Etiquetado de componentes conectados

El etiquetado de componentes consiste básicamente en extraer una región de la imagen original, excepto que tratamos de encontrar solo los componentes que están «conectados», lo que está determinado por la aplicación de la teoría de grafos.

OpenCV nos proporciona las siguientes 4 funciones para esta tarea:

  • cv2.componentes conectados
  • cv2.componentes conectados con estadísticas
  • cv2.componentesconectadosConAlgoritmo
  • cv2.componentesconectadosConEstadísticasConAlgoritmo

Los dos últimos son más eficientes y rápidos, pero solo se ejecutan si tiene habilitado el preprocesamiento paralelo con OpenCV; de lo contrario, es más inteligente ceñirse a los dos primeros. Tanto el primer como el segundo método son iguales, excepto que en el segundo método, como sugiere el nombre, obtenemos estadísticas para cada uno de los componentes y usaremos el segundo método porque en la mayoría de los casos necesitará esas estadísticas. .

En este programa, vamos a usar una imagen de banner para extraer los componentes de texto, la siguiente imagen muestra el resultado final de nuestro programa:

Instalación de dependencias

Comencemos instalando los paquetes necesarios:

$ pip install opencv-contrib-python

Paso 1: Carga y preprocesamiento de imágenes

Primero carguemos nuestra imagen y convirtámosla en una imagen en escala de grises, esto hace que el algoritmo sea mucho más eficiente y preciso. Después de esto, también aplicaremos un desenfoque gaussiano de 7 × 7, esto ayuda a eliminar los bordes no deseados y ayuda a una segmentación mucho más clara, lo que haremos en el siguiente paso.

Python3

# Applying threshold
threshold = cv2.threshold(blurred, 0, 255,
cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]

Paso 2: Umbral

La umbralización es una técnica de segmentación de imágenes muy básica que nos ayuda a separar el fondo y los objetos de primer plano que nos interesan. Después de aplicar el desenfoque, usaremos la función cv2.threshold para segmentar la imagen.

Python3

# Applying threshold
threshold = cv2.threshold(blurred, 0, 255,
cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]

Paso 3: Aplicación del método de análisis de componentes

Primero aplicamos cv2.connectedComponentsWithStats y luego desempaquetamos los valores que devuelve en diferentes variables que usaremos en los siguientes pasos, y también creemos una nueva array para almacenar todos los componentes que encontremos.

Python3

# Apply the Component analysis function
analysis = cv2.connectedComponentsWithStats(threshold,
                                            4,
                                            cv2.CV_32S)
(totalLabels, label_ids, values, centroid) = analysis
 
# Initialize a new image to
# store all the output components
output = np.zeros(gray_img.shape, dtype="uint8")

Ahora que tenemos nuestros componentes y análisis, repasemos cada uno de los componentes y filtremos los componentes útiles.

Paso 4: filtrar los componentes útiles

Recorramos cada uno de los componentes y usemos las estadísticas que obtuvimos en el último paso para filtrar los componentes útiles. Por ejemplo, aquí he usado el valor de Área para filtrar solo los caracteres de la imagen. Y después de filtrar los componentes, usaremos la variable label_ids para crear una máscara para el componente que estamos recorriendo y usaremos la operación bitwise_or en la máscara para generar nuestro resultado final. Suena difícil, pero lo entenderá mejor después de implementar el código usted mismo.

Python3

# Loop through each component
for i in range(1, totalLabels):
    area = values[i, cv2.CC_STAT_AREA] 
 
    if (area > 140) and (area < 400):
       
        # Labels stores all the IDs of the components on the each pixel
        # It has the same dimension as the threshold
        # So we'll check the component
        # then convert it to 255 value to mark it white
        componentMask = (label_ids == i).astype("uint8") * 255
         
        # Creating the Final output mask
        output = cv2.bitwise_or(output, componentMask)

¿Cómo seleccionar el valor de Área (o cualquier otra condición como ancho o alto) para filtrar?

Agregue una declaración de impresión para imprimir el valor de la estadística que desea usar como condición y luego, para los componentes útiles, anote el rango de valores y utilícelos para crear la condición de filtro.

Paso 5: Visualice el resultado final

Ahora nuestro paso final es simplemente mostrar nuestra imagen original y la máscara final que obtuvimos.

Python3

cv2.imshow("Image", img)
cv2.imshow("Filtered Components", output)
cv2.waitKey(0)

A continuación se muestra la implementación:

Python3

import cv2
import numpy as np
 
 
# Loading the image
img = cv2.imread('Images/img5.png')
 
# preprocess the image
gray_img = cv2.cvtColor(img , cv2.COLOR_BGR2GRAY)
 
# Applying 7x7 Gaussian Blur
blurred = cv2.GaussianBlur(gray_img, (7, 7), 0)
 
# Applying threshold
threshold = cv2.threshold(blurred, 0, 255,
    cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
 
# Apply the Component analysis function
analysis = cv2.connectedComponentsWithStats(threshold,
                                            4,
                                            cv2.CV_32S)
(totalLabels, label_ids, values, centroid) = analysis
 
# Initialize a new image to store
# all the output components
output = np.zeros(gray_img.shape, dtype="uint8")
 
# Loop through each component
for i in range(1, totalLabels):
   
      # Area of the component
    area = values[i, cv2.CC_STAT_AREA]
     
    if (area > 140) and (area < 400):
        componentMask = (label_ids == i).astype("uint8") * 255
        output = cv2.bitwise_or(output, componentMask)
 
 
cv2.imshow("Image", img)
cv2.imshow("Filtered Components", output)
cv2.waitKey(0)

Producción:

esta es la máscara de salida y la imagen original

Nota: Ejecute el programa en una cantidad de imágenes grandes y pequeñas para que vea que la salida consistió en mucho «ruido». Por lo tanto, aplicamos el «filtro» en la última ejecución, el resultado final que obtuvimos solo tenía los caracteres de texto que queríamos.

Etiquetado y análisis de componentes conectados de OpenCV: 

Aquí hay otra implementación donde he demostrado todo el proceso para cada componente para que sea más fácil de visualizar: 

Python3

import cv2
import numpy as np
 
 
# Loading the image
img = cv2.imread('Images/img5.png')
 
# preprocess the image
gray_img = cv2.cvtColor(img ,
                        cv2.COLOR_BGR2GRAY)
 
# Applying 7x7 Gaussian Blur
blurred = cv2.GaussianBlur(gray_img, (7, 7), 0)
 
# Applying threshold
threshold = cv2.threshold(blurred, 0, 255,
    cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
 
# Apply the Component analysis function
analysis = cv2.connectedComponentsWithStats(threshold,
                                            4,
                                            cv2.CV_32S)
(totalLabels, label_ids, values, centroid) = analysis
 
# Initialize a new image to
# store all the output components
output = np.zeros(gray_img.shape, dtype="uint8")
 
# Loop through each component
for i in range(1, totalLabels):
   
      # Area of the component
    area = values[i, cv2.CC_STAT_AREA]
     
    if (area > 140) and (area < 400):
        # Create a new image for bounding boxes
        new_img=img.copy()
         
        # Now extract the coordinate points
        x1 = values[i, cv2.CC_STAT_LEFT]
        y1 = values[i, cv2.CC_STAT_TOP]
        w = values[i, cv2.CC_STAT_WIDTH]
        h = values[i, cv2.CC_STAT_HEIGHT]
         
        # Coordinate of the bounding box
        pt1 = (x1, y1)
        pt2 = (x1+ w, y1+ h)
        (X, Y) = centroid[i]
         
        # Bounding boxes for each component
        cv2.rectangle(new_img,pt1,pt2,
                      (0, 255, 0), 3)
        cv2.circle(new_img, (int(X),
                             int(Y)),
                   4, (0, 0, 255), -1)
 
        # Create a new array to show individual component
        component = np.zeros(gray_img.shape, dtype="uint8")
        componentMask = (label_ids == i).astype("uint8") * 255
 
        # Apply the mask using the bitwise operator
        component = cv2.bitwise_or(component,componentMask)
        output = cv2.bitwise_or(output, componentMask)
         
        # Show the final images
        cv2.imshow("Image", new_img)
        cv2.imshow("Individual Component", component)
        cv2.imshow("Filtered Components", output)
        cv2.waitKey(0)

Producción:

 

Publicación traducida automáticamente

Artículo escrito por bobde_yagyesh y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *