El ajuste de contraste es una operación por la cual se desea ensanchar el rango dinámico de una imagen de tal forma que las características que la componen sean mas fáciles de percibir para el observador.
Existen múltiples estrategias para ajustar el contraste de una imagen, sin embargo, una de las más comunes consiste en emplear el histograma de la imagen para expandir el rango de valores que emplea una imagen para presentarse.
Un ejemplo de esta operación puede observarse a continuación:
Imagen con bajo contraste
Imagen resultado
Histograma de la imagen de bajo contraste
Histograma de la imagen resultado
Para realizar esta operación solo es necesario generar la siguiente serie de pasos secuenciales:
Obtener el histograma de la imagen original
Obtener la función de probabilidad del histograma (suma acumulada normalizada del histograma)
Mediante un criterio, determinar un punto de expansión inicial y uno final (usualmente se considera 0.05 y 0.95 en la función de probabilidad)
Emplear la formula 4.32 para cada pixel de la imagen
SI p<l ENTONCES p=l
SI p>u ENTONCES p=u
p = (p-l)*(255-0)/(u-l)
Un ejemplo de dicha implementación se muestra para Python en el siguiente script
import cv2
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
def main():
# Se carga la imagen dañada
imagen = cv2.imread('Trolley damaged.png', 0)
# Se muestra la imagen dañada
plt.figure(dpi=300)
plt.tight_layout()
plt.axis('off')
plt.imshow(imagen, 'Greys_r', vmin=0, vmax=255)
plt.show()
# Se obtiene el histograma
hist = obtener_frecuencias_de_intensidad(imagen)
# Se plotea el histograma de la imagen dañada
sns.set_theme(style= 'darkgrid' )
plt.figure(figsize=(8, 6), dpi=300)
plt.stem(*hist)
plt.tight_layout()
plt.savefig('Histograma imagen dañada.png', dpi=300, bbox_inches='tight')
plt.show()
# Se obtine la funcion de probabilidad (histograma acumulado y normalizado)
fp = hist[1].cumsum()
fp = fp/fp[-1]
# Se plotea la funcion de probabilidad de la imagen da
plt.figure(figsize=(8, 6), dpi=300)
plt.plot(hist[0], fp)
plt.tight_layout()
plt.show()
# Se obtiene un punto de corte alto y uno bajo que conserve el n 90% de
# la informacion de la imagen
il = np.where(fp < 0.05)[0]
il = il[-1] + 1
print(il)
iu = np.where(fp > 0.95)[0]
iu = iu[0] - 1
# Se aplica la formula 4.32 a cada elemento de la imagen
resultado = imagen
i = np.where(resultado<il)
resultado[i]=il
i = np.where(resultado>iu)
resultado[i]=iu
resultado = (resultado-il)*((255-0)/(iu-il))
resultado = np.round(resultado).astype(int)
# Se muestra la imagen reparada
plt.figure(dpi=300)
plt.tight_layout()
plt.axis('off')
plt.imshow(resultado, 'Greys_r', vmin=0, vmax=255)
plt.show()
cv2.imwrite('Imagen reparada.png', resultado)
# Se obtiene el histograma de la imagen reparada
hist = obtener_frecuencias_de_intensidad(resultado)
# Se plotea el histograma de la imagen reparada
sns.set_theme(style= 'darkgrid' )
plt.figure(figsize=(8, 6), dpi=300)
plt.stem(*hist)
plt.tight_layout()
plt.savefig('Histograma imagen reparada.png', dpi=300, bbox_inches='tight')
plt.show()
def obtener_frecuencias_de_intensidad(imagen, bits=8):
# Se obtiene la cantidad de apariciones de cada valor
valores, frecuencias = np.unique(imagen, return_counts=True)
# Se genera un arreglo con los pares de valores y su frecuencia
conteo = np.zeros((2, 2**bits))
conteo[0] = np.arange(2**bits)
conteo = np.transpose(conteo).astype(int)
conteo[valores, 1] = frecuencias
conteo = np.transpose(conteo)
return conteo
if __name__=='__main__':
main()