Umbralización adaptativa con OpenCV Python

En el tutorial previo hablamos sobre el proceso de umbralización, y cómo utilizar el mismo para separar los objetos del fondo de la imagen, en aquella ocasión usamos un valor de umbral fijo, pero que sucede si el color de fondo o la iluminación de la escena no es uniforme, resultaría difícil segmentar los objetos usando un umbral fijo, en ese caso debemos contemplar otras técnicas como umbralización adaptativa que procederemos a estudiar.

La umbralización adaptativa o variable nos permite establecer un valor de umbral que se calcula o varía en base a las características locales del entorno que se evalúa, esto nos permitirá segmentar imágenes que contengan fondos con distintos niveles de grises o iluminación no uniforme.

Función adaptiveThreshold de OpenCV

Esta es la función encargada de segmentar una imagen a escala de grises usando un umbral variable, la misma se define de la siguiente manera:

void cv::adaptiveThreshold(
        cv::InputArray src,  // Imagen de entrada
        cv::OutputArray dst, // Imagen de salida
        double maxValue,     // Valor que se asigna si se cumple con el umbral
        int adaptiveMethod,  // Método a utilizar (mean, Gaussian)
        int thresholdType,   // Tipo de umbralización
        int blockSize,       // Tamaño de bloque: 3, 5, 7, ...
        double C             // Constante
);

Los distintos métodos que podemos aplicar son: ADAPTIVE_THRESH_MEAN_C y ADAPTIVE_THRESH_GAUSSIAN_C, además debemos indicar el tipo de umbralización, puede ser: THRESH_BINARY o THRESH_BINARY_INV, estos tipos los explicamos en el tutorial de umbralización previo.

Veamos un código de ejemplo:

import numpy as np
import cv2

gray = cv2.imread('sudoku.png', cv2.IMREAD_GRAYSCALE)

cv2.imshow('tutorial umbral', gray)

# umbral fijo
_, dst1 = cv2.threshold(gray, 96, 255, cv2.THRESH_BINARY)

cv2.imshow('umbral fijo', dst1)

# umbral adaptable
gray = cv2.medianBlur(gray, 5)
dst2 = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)

cv2.imshow('umbral adaptable', dst2)

cv2.waitKey(0)

Que hemos hecho con este código:

1. Imagen original: /sudoku.png

gray = cv2.imread('sudoku.png', cv2.IMREAD_GRAYSCALE)

OpenCV Umbralización Adaptativo o Variable

2. Si aplicamos el umbral fijo a 96.0 obtenemos el siguiente resultado:

_, dst1 = cv2.threshold(gray, 96, 255, cv2.THRESH_BINARY)

Umbral fijo (cv::threshold)

Si bajamos el valor del umbral, a 45.0 por ejemplo, podremos obtener el área inferior izquierda pero perdemos detalles del área superior derecha, realiza los cambios y visualiza los resultados.

Cómo vemos, es difícil establecer un valor de umbral que nos devuelva los resultados correctos, incluso si utilizamos el método de Otsu los resultados no son lo esperado.

3. Aplicando umbralización adaptativa, resolvemos el problema previamente mencionado, veamos:

gray = cv2.medianBlur(gray, 5)
dst2 = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)

Umbral adaptativo (cv::adaptiveThreshold)

Antes de calcular el umbral aplicamos el filtro de mediana para reducir el ruido en la imagen, esto nos ayudará a obtener un resultado más claro, puedes probar con el otro método, variar los parámetros de la función y ver los diferentes resultados.

Por ahora llegamos hasta aquí, nos veremos en el siguiente tutorial.

Comentarios

Temas relacionados

Entradas populares de este blog

tkinter Grid

tkinter Canvas

Histogramas OpenCV Python

Python Binance API