Como fotógrafo aficionado, siempre me he preguntado cómo Apple Photos, Lightroom y Photoshop implementan los ajustes de contraste de la imagen. Después de pasar un tiempo leyéndolo, vale la pena compartir el enfoque.
Empecemos con lo básico.
Un histograma es simplemente un gráfico de barras que representa [en este caso] diferentes frecuencias de colores en una imagen.
Aquí hay un histograma típico que puede ver:
Fuente: Histogramas para principiantes
Como paso preliminar, intentemos manipular el brillo de una imagen. Se prestará para hacer ajustes de contraste más adelante.
Dado un histograma, si desplazamos su contenido hacia la izquierda o hacia la derecha, podemos hacer que la imagen sea más oscura o más clara, respectivamente.
Supongamos que estamos tratando con un espacio de color RGB de 8 bits. Un lado del histograma sería (0, 0, 0) [negro] y el otro lado sería (255, 255, 255) [blanco].
A medida que movemos el histograma hacia la derecha, aumentamos la frecuencia de los valores más cercanos al blanco en la imagen, lo que ilumina la imagen. Por el contrario, desplazar el histograma hacia la izquierda mueve más valores hacia el negro, oscureciendo así la imagen.
Aquí hay un ejemplo de una función que puede cambiar el brillo de una imagen.
Imagen original
Brillo + 40%
Brillo - 40 %
El código anterior es demasiado simplista. Una implementación adecuada asignaría el espacio de color RGB a HSL. Luego, modificaría los valores de luminancia y luego convertiría la imagen nuevamente al espacio de color RGB. Sin embargo, modificar los valores RGB de esta manera aún ilustra el punto sin aumentar el alcance del artículo.
El contraste es realmente solo una medida de la diferencia entre las intensidades de píxeles máxima y mínima en una imagen. Entonces, para aumentar el contraste en una imagen, necesitamos aumentar la distancia entre las intensidades de píxeles máxima y mínima.
Echaremos un vistazo a algunos algoritmos de ajuste de contraste diferentes, comenzando con el estiramiento de contraste/histograma.
Estiramiento de contraste / Estiramiento de histograma
Como su nombre lo indica, esto es realmente solo el proceso de tomar los valores de intensidad existentes en la imagen y "estirarlos" para que se ajusten a todo el rango de valores potenciales: [0, 255].
Foto de Giancarlo Corti en Unsplash
Si observamos el histograma de la imagen, veremos que la mayoría de los valores de intensidad están sesgados hacia el lado izquierdo del gráfico y existen muy pocos valores en el rango de intensidad más alto.
Después de aplicar la ampliación del contraste a esta foto, los valores de intensidad del histograma deben distribuirse en todo este rango.
Como hemos aumentado la diferencia entre los valores de intensidad máxima y mínima, puede ver que hemos aumentado el contraste en la imagen.
También es importante tener en cuenta que la forma general del histograma se conserva con este enfoque. Este no será el caso con los futuros algoritmos que veremos.
Para implementar el estiramiento de contraste, primero debemos encontrar las intensidades de píxeles mínima y máxima. Luego, simplemente podemos aplicar la siguiente transformación en cada píxel para obtener el nuevo valor de intensidad para ese píxel en la imagen de salida.
Si quisiéramos aplicar este mismo enfoque a una imagen RGB, necesitaríamos convertir la imagen a un espacio de color de Tono, Saturación e Intensidad (HSI). Luego, realizaríamos el mismo cálculo anterior solo en el valor de Intensidad y luego asignaríamos el resultado al espacio de color RGB.
El resultado de este paso de normalización sería un valor entre 0 y 1,0 que luego multiplicaríamos por 255 para obtener el valor correcto del píxel.
Sin embargo, hay una trampa con este enfoque.
Teniendo en cuenta la fórmula anterior, podemos ver que si los valores mínimo y máximo son 0 y 255, la imagen no se ve afectada. Por lo tanto, la mayoría de las implementaciones de este algoritmo seleccionan valores del 5% de los bordes en lugar de estrictamente los valores de intensidad mínimos/máximos.
Siempre puede jugar con qué tan lejos se mueve desde los bordes para controlar cuánto contraste adicional se aplica a la imagen.
Antes
Después
Ecualización de histograma
Mientras que la ampliación del histograma modifica el rango de valores de intensidad para extenderse por todo el rango posible, la ecualización del histograma crea una distribución uniforme de los valores del histograma.
Crédito: Wikipedia
La ecualización del histograma de ninguna manera garantiza mejores resultados. Convertir los valores de intensidad en una distribución uniforme puede muy bien disminuir el contraste o introducir ruido adicional en la imagen.
pseudocódigo
El primer paso es contar las diversas frecuencias de intensidad en nuestra imagen de origen:
El código completo está disponible a continuación, pero aquí hay un extracto de la salida:
0, 3028
1, 1216
2, 1188
3, 1262
4, 1242
...
No debería sorprender que los valores del histograma estén muy sesgados hacia la izquierda, lo que indica que la imagen está en el lado oscuro.
Ahora que tenemos nuestra distribución de probabilidad, generemos nuestra función de distribución acumulativa [CDF]. Un CDF es una representación de cuántos valores menores que un cierto valor existen en nuestra imagen de entrada.
Por ejemplo, en el gráfico a continuación podemos ver que hay aprox. 150.000 píxeles que son menores o iguales a un nivel de intensidad de 65 (de 255).
Calcular todas estas frecuencias y probabilidades nos ayuda en la transformación del histograma en una distribución uniforme.
¡Excelente! Todo lo que necesitamos hacer es usar la información en el CDF para transformar los valores de intensidad en la imagen original.
Para realizar esta traducción, tomaremos un píxel de la imagen original, por ejemplo, el píxel en (10, 10), y encontraremos su valor de intensidad. Luego, usaremos ese valor de intensidad para indexar en nuestra matriz que almacena los resultados de la CDF para encontrar la nueva intensidad para el píxel de salida.
Si esto todavía es un poco confuso, el código debería aclarar las cosas.
Ahora, tenemos nuestra nueva imagen de salida:
Verifiquemos nuestro trabajo y observemos el histograma de esta nueva imagen:
me parece bastante uniforme :)
Código
Alternativas
Veamos rápidamente algunos otros enfoques.
Estiramiento no lineal
Cuando discutíamos el estiramiento del contraste, estábamos estirando todas las partes del histograma por igual. El estiramiento no lineal es esencialmente el mismo enfoque, pero usará alguna otra función para estirar selectivamente diferentes partes del histograma de manera diferente. Por ejemplo, una implementación podría usar una función logarítmica para estirar el histograma.
Especificación de histograma
Este enfoque está estrechamente relacionado con la ecualización de histogramas. En lugar de crear una distribución uniforme, la especificación de histogramas le permite transformar el histograma de una imagen para que coincida con algún otro histograma que especifique. Por lo tanto, la ecualización del histograma es solo una variante de este enfoque en el que el histograma proporcionado se distribuye uniformemente. En cambio, este enfoque le permite pasar cualquier histograma para que coincida.
Modificación adaptativa del histograma
Este enfoque implica la creación de varios histogramas, cada uno de los cuales corresponde a diferentes partes de la imagen de origen. Esto le permite tener ajustes de contraste mucho más granulares. Este enfoque se usa a menudo cuando desea proporcionar ajustes de contraste locales o, de manera más general, refinar los bordes de su imagen.
Si te gusta esta inmersión técnica en los algoritmos modernos, no dudes en seguirme en Twitter , o echa un vistazo a mi sitio personal para ver más publicaciones.
Fuentes
Publicado anteriormente en https://digitalbunker.dev/2021/01/09/understanding-contrast-algorithms/