() translation by (you can also view the original English article)
¿Recuerdas cuando viste esa imagen de baja calidad y te sentiste un poco decepcionado? No era lo suficientemente clara, y los detalles eran un poco borrosos. ¿Y si pudieras mejorar esa imagen a una versión mejor? ¿No sería grandioso? Afortunadamente, ¡hay una manera de hacer eso usando Python!
Uno de los métodos que puedes usar para mejorar una imagen es ecualización de histograma, la cuál en particular mejora el contraste de la imagen. Casi todos los sistemas de cámara usan de hecho ecualización de histograma para hacer lucir mejor nuestras fotos, y al final del tutorial descubrirás por qué.
En la siguiente sección, me adentraré más profundo en el significado de ecualización de histograma y qué sucede a la imagen cuando se aplica el método, y después veremos cómo podemos implementar el método en Python. ¿Listo?
Ecualización de Histograma
Digamos que tienes la imagen pout.jpg (ve y descárgala). Esta es una imagen de demostración usada en MATLAB, de donde la obtuve, pero la usaremos en nuestro tutorial. La imagen se ve como sigue:



Echemos un vistazo a cómo podemos acceder a los valores de pixel de la imagen, conocido como intensidades. Escribí este pequeño script de Python que podemos usar para hacer justo eso (nota que estoy usando la librería OpenCV):
1 |
import cv2 |
2 |
|
3 |
img = cv2.imread('pout.jpg') |
4 |
img_shape = img.shape |
5 |
height = img_shape[0] |
6 |
width = img_shape[1] |
7 |
|
8 |
for row in range(width): |
9 |
for column in range(height): |
10 |
print (img[column][row]) |
Lo que estoy haciendo aquí es leer nuestra imagen (pout.jpg) , y después investigar la forma (tamaño) de la imagen. img_shape
devolverá: (1031, 850, 3)
. Esto significa que nuestra imagen es de altura (número de columnas) 1031
, y de ancho (número de filas) 850
, y tiene 3
canales (RGB). Nota que el primer parámetro en el resultado es la altura, y el segundo parámetro es la anchura. Finalmente, ciclamos a través de las filas y columnas e imprimimos los diferentes valores de pixeles (intensidades) en cada par de fila/columna.
Nuestra muestra de la salida es [137 137 137]
.Sí, lo sé, estabas esperando un valor como resultado para la intensidad de pixel. De hecho tenemos el valor de intensidad de pixel aquí, pero lo que la salida nos está mostrando son los resultados de los canales rojo, verde y azul (RGB
). Por favor ten en cuenta, sin embargo, que en OpenCV el orden es BGR
, ya que así es como carga la imagen OpenCV. Así pues, el resultado de muestra de arriba contiene el valor 137
para cada canal, en el orden de B
, G
, y R
, respectivamente.
La razón para la introducción es que la ecualización de histograma es de hecho sobre la modificación de intensidades de pixel por el bien de mejorar el contraste de la imagen. De ahí, nuestro trabajo principal aquí será en el nivel de intensidad de pixel.
En este punto, te estarás preguntando qué es un histograma. Aunque algunas veces el término podría ser un poco confuso, es de hecho un concepto muy simple. El histograma es simplemente un diagrama que representa el número de pixeles en una imagen en cada valor de intensidad encontrado en esa imagen.
Ya que nuestros pixeles tienen tres valores, uno por cada uno de los canales BGR, una manera de dibujar un histograma es tener tres histogramas, uno para cada canal, en donde el eje x tendrá los distintos valores de pixel (intensidades), y el eje y mostrará cuántas veces (frecuencia) que ha aparecido ese pixel en particular entre los diferentes valores de pixel.
Por ejemplo, el histograma del canal rojo puede tener un valor de pixel de 137
sobre el eje x, y el eje y puede mostrar cuántos pixeles tuvieron este valor para el canal rojo---digamos, por ejemplo, 86
. Así que la manera en que leemos eso es simplemente diciendo que el valor de pixel para el canal rojo de 137
apareció en 86
pixeles, o se repitió 86
veces en nuestra imagen.
Usando el código de este artículo de Histograma de Imagen para dibujar el histograma de nuestra imagen, obtenemos lo siguiente:



El histograma es realmente para los canales rojo, verde y azul. Tomemos una pequeña muestra de la salida que obtendrías del código anterior, como se muestra abajo. Esto muestra que los valores de canal parecen siempre ser los mismos, y las tres líneas diferentes dibujadas tienen por lo tanto los mismos valores y serán dibujadas encima de cada una, apareciendo como solo una línea.
1 |
[94 94 94]
|
2 |
[95 95 95]
|
3 |
[97 97 97]
|
4 |
[99 99 99]
|
5 |
[100 100 100]
|
6 |
[101 101 101]
|
7 |
[101 101 101]
|
8 |
[101 101 101]
|
9 |
[100 100 100]
|
10 |
[98 98 98]
|
11 |
[95 95 95]
|
12 |
[93 93 93]
|
Lo que el método de ecualización de histograma hará por el histograma de arriba es que transformará los valores de intensidad en una manera en la que hará lucir más plano al histograma en la imagen resultante. En otras palabras, la ecualización de histograma es un método que ajusta las intensidades de imagen para poder mejorar el contraste de la imagen.
El histograma de arriba luce un poco más concentrado hacia la mitad de la figura, y lo que hará la ecualización de histograma es distribuir los valores de intensidad de pixel más allá para obtener un histograma mas aplanado.
Creo que eso es suficiente sobre ecualización de histograma para discutir aquí, ya que no queremos ser más matemáticos en este tutorial, especialmente ya que se trata más de la implementación del método en Python. Sin embargo, puedes revisar estas notas que muestran las diferentes fórmulas involucradas en el método: ecualización de histograma. ¡Así que vayamos a la implementación!
Ecualización de Histograma en Python
En esta sección, te mostraré cómo implementar el método de ecualización de histograma en Python. Usaremos la imagen de arriba (pout.jpg) en nuestros experimentos. Recorramos el proceso paso a paso. Lo primero que tenemos que hacer es importar las librerías OpenCV y NumPy, como sigue:
1 |
import cv2 |
2 |
import numpy |
Después de eso, simplemente necesitamos leer nuestra imagen, pout.jpg:
1 |
img = cv2.imread('pout.jpg') |
La buena noticia es que OpenCV nos proporciona una función a través de la cuál podemos simplemente aplicar ecualización de histograma sobre una imagen, llamada equilizeHist(). Es sencilla de aplicar a una imagen en escala de grises ya que el método realmente ecualiza el histograma de una imagen en escala de grises, pero en nuestro caso tenemos tres canales (RGB) para cada pixel y no podemos simplemente aplicar ecualización de histograma sobre tres canales de manera separada.
Una buena solución con la que me encontré en el libro Python: Real World Machine Learning es convertir nuestra imagen al espacio de color YUV, ecualizar el canal Y
, y finalmente convertir el resultado a RGB. Así que la primera cosa que hacemos es convertir nuestra imagen a YUV
. Esto puede hacerse usando el método cvtColor(), el cuál convierte la imagen de un espacio de color a otro, como sigue:
1 |
img_to_yuv = cv2.cvtColor(img,cv2.COLOR_BGR2YUV) |
Nota que usamos BGR
en lugar de RGB
aquí, ya que OpenCV (como se mencionó antes) carga las imágenes en formato BGR
.
Ahora aplicamos el método de ecualización de histograma sobre el canal Y
usando el método equalizeHist():
1 |
img_to_yuv[:,:,0] = cv2.equalizeHist(img_to_yuv[:,:,0]) |
Finalmente, convertimos el canal Y
a RGB
(BGR
en OpenCV), como sigue:
1 |
hist_equalization_result = cv2.cvtColor(img_to_yuv, cv2.COLOR_YUV2BGR) |
¡Felicidades! Ahora has aplicado ecualización de histograma a la imagen. En la siguiente sub-sección, pondré todo el código junto y te mostraré cómo lucirá nuestra imagen después de aplicar ecualización de histograma.
Juntándolo Todo
Juntemos todo lo que hemos aprendido. El script Python para aplicar ecualización de histograma sobre pout.jpg
luce como sigue:
1 |
import cv2 |
2 |
import numpy |
3 |
|
4 |
img = cv2.imread('pout.jpg') |
5 |
img_to_yuv = cv2.cvtColor(img,cv2.COLOR_BGR2YUV) |
6 |
img_to_yuv[:,:,0] = cv2.equalizeHist(img_to_yuv[:,:,0]) |
7 |
hist_equalization_result = cv2.cvtColor(img_to_yuv, cv2.COLOR_YUV2BGR) |
8 |
|
9 |
cv2.imwrite('result.jpg',hist_equalization_result) |
La salida del código de arriba es la siguiente imagen:



Para notar mejor la diferencia, pondré las dos imágenes lado a lado (izquierda: imagen original; derecha: resultado de ecualización de histograma):



¿Notaste la diferencia? La imagen de la derecha luce mucho más clara que la imagen original. ¡No cabe duda de por qué casi todos los sistema de imagen realizan ecualización de histograma!
Antes de que terminemos, veamos cómo luce el histograma de nuestro resultado:



Si comparas el histograma de la imagen resultante con el histograma de la imagen original, notarás que el histograma de la imagen resultante es más plano que el histograma de la imagen original, y esto es exactamente lo que hace el método de ecualización de histograma.
Conclusión
En este tutorial, vimos cómo podemos mejorar el contraste de una imagen usando un método llamado ecualización de histograma, y lo fácil que es de implementar usando Python y OpenCV.
El resultado fue muy interesante ya que fue mucho más claro que la imagen original, y el histograma del resultado fue más plano que el histograma de la imagen original, mostrando una mejor distribución de valores de intensidad de pixel a lo largo de la imagen.
Finalmente, no dudes en ver lo que tenemos disponible a la venta y para estudio en el Mercado Envato, y por favor haz cualquier pregunta y proporciona tu valiosa retroalimentación usando la sección de abajo.