5.12. Umbralización binaria¶
Muchos procesos de procesamiento de imágenes se reducen a una pregunta sobre cada píxel: ¿está este brillo dentro del rango que significa «primer plano»? ¿Está este color lo bastante cerca del rojo como para ser el marcador que la aplicación está siguiendo? ¿Forma este píxel parte del conjunto candidato que debería examinar la siguiente etapa del proceso? La umbralización es la operación que convierte esas preguntas en una respuesta binaria en cada posición – encendido si el píxel coincide, apagado si no – y reduce toda la imagen a una máscara con la que puede trabajar el resto del proceso.
5.12.1. El método binary¶
El método binary() ejecuta esa clasificación sobre todos los píxeles en una sola llamada. Toma una lista de rangos de umbral – las condiciones que un píxel puede cumplir para contar como «encendido» – y reescribe la imagen de modo que cada píxel que coincidió con al menos uno de los rangos se fija al valor máximo del formato, y cada píxel que no coincidió se fija a cero. El resultado es la máscara binaria que el resto del proceso puede usar directamente.
En su forma más sencilla, la lista de umbrales tiene un único rango y la llamada devuelve una máscara de los píxeles dentro de ese rango:
img.binary([(120, 255)])
La forma de lista es lo que hace potente a binary. Un proceso que quiere seguir dos marcadores de color, o un rango de brillo más un pico aislado de saturación, pasa ambos rangos en la misma lista y obtiene una única máscara de salida que cubre todas las coincidencias.
La umbralización convierte una imagen de valores continuos en una máscara binaria: cada píxel dentro del rango de umbral pasa a ser el máximo del formato, y cada píxel fuera de él pasa a ser cero.¶
5.12.2. La tupla en escala de grises¶
Para una imagen en escala de grises, cada entrada de la lista de umbrales es una tupla de dos elementos (lo, hi) que describe un rango de brillo inclusivo. Los píxeles con valores entre lo y hi (ambos incluidos) coinciden; todo lo que está fuera de ese rango no coincide. Los patrones naturales son sencillos:
(0, 60)coincide con los píxeles oscuros – todo desde el negro hasta el gris profundo.(180, 255)coincide con los píxeles brillantes – todo desde el gris claro hasta el blanco.(100, 160)coincide con los píxeles de gris medio – una banda en el centro del rango de brillo.
El orden de los dos valores dentro de una tupla no importa; el método los intercambia internamente si lo es mayor que hi, de modo que (60, 0) funciona igual que (0, 60).
5.12.3. La tupla LAB para el color¶
Para una imagen RGB565, cada entrada es una tupla de seis elementos (l_lo, l_hi, a_lo, a_hi, b_lo, b_hi) que describe un rango inclusivo en el espacio de color LAB en lugar de directamente en rojo, verde y azul. Los umbrales son L (luminosidad), A (eje cromático de verde a rojo) y B (eje cromático de azul a amarillo), comparados cada uno con el valor del píxel en ese canal.
La razón para pasar por LAB en lugar de umbralizar RGB directamente es la propiedad en torno a la cual se diseñó el espacio de color LAB: LAB separa la luminosidad del croma. Dos píxeles que muestran el mismo color pero con brillos distintos acaban con valores de L diferentes pero con valores de A y B aproximadamente iguales. Esa separación permite que los rangos de umbral describan un color por su posición en los ejes A y B y dejen el rango de L bien abierto para aceptar ese color con cualquier brillo, desde la sombra hasta el realce. Un umbral basado en RGB no puede hacer eso – cualquier cambio en la iluminación mueve a la vez los tres valores R, G y B, y un rastreador construido sobre umbrales RGB se viene abajo la primera vez que una nube pasa por delante del sol.
El patrón práctico: elige los rangos de A y B que describen el color que la aplicación está siguiendo, y deja el rango de L amplio – a menudo (0, 100) para aceptar cualquier brillo – a menos que la aplicación quiera específicamente umbralizar tanto por brillo como por color.
Para las tuplas con menos de seis valores, los componentes que faltan toman por defecto el rango máximo (sin restricción en ese eje). Por tanto, una tupla de dos elementos (l_lo, l_hi) en una lista de umbrales RGB565 umbraliza solo por luminosidad y coincide con todos los colores.
Nota
Un rango de L verdaderamente abierto tiene una pega en su extremo inferior. A medida que la luminosidad cae hacia cero, todos los colores convergen hacia el negro, con los valores de A y B colapsando hacia cero y quedando dominados por el ruido – de modo que los píxeles oscuros pueden colarse en los rangos de A y B y ser rastreados como el color objetivo. Si las regiones negras de la escena aparecen como coincidencias, aumenta l_lo hasta que dejen de hacerlo.
5.12.4. Indicadores¶
Tres argumentos de palabra clave controlan la salida:
invert=Trueinvierte el resultado. Cada píxel que habría coincidido pasa a cero, y cada píxel que habría sido cero pasa al valor máximo. Útil cuando la forma natural de describir el primer plano es por lo que no es.zero=Truecambia el modo de operación: los píxeles coincidentes se ponen a cero y los píxeles no coincidentes conservan sus valores originales. Úsalo cuando el objetivo sea borrar los píxeles coincidentes de la imagen en lugar de reducir la imagen a una máscara binaria de ellos.to_bitmap=Truedevuelve el resultado como una imagenBINARYen lugar de sobrescribir el formato existente del origen. El resultado de un bit por píxel es lo que aceptan directamente los posteriores argumentos de máscara, y la conversión a menudo evita la presión de memoria de arrastrar una máscara de formato completo.
Mask y ROI siguen la misma convención que el resto de la interfaz: un rectángulo roi acota la operación a una subárea, y una imagen mask la acota a un patrón arbitrario de posiciones.
5.12.5. In situ por defecto¶
Al igual que las operaciones aritméticas, binary se ejecuta in situ por defecto: los píxeles de la imagen de origen se sobrescriben con la salida binaria, y los valores originales desaparecen tras la llamada. La forma to_bitmap=True es la alternativa cuando hay que preservar el origen y la salida debe ser una imagen BINARY recién reservada. También se acepta la forma copy=True para obtener un resultado del mismo formato en un búfer nuevo.