Después de de esta extensa recopilación de información hemos podido solucionar este enigma que tienen algunos de nuestros lectores. Te compartimos la respuesta y esperamos servirte de mucha apoyo.
Solución:
Puede intentar ajustar automáticamente el brillo mediante la optimización del contraste con recorte de histograma. Puede aumentar el brillo de destino aumentando el porcentaje de recorte del histograma (clip_hist_percent
). Aquí está el resultado al 25% de recorte
Alfa y beta se calculan automáticamente
alfa 3.072289156626506
beta -144.3975903614458
Aquí hay una visualización del recorte. Azul (original), Naranja (después del ajuste automático).
Resultados con recorte al 35%
alfa 3.8059701492537314
beta -201.71641791044777
Otros métodos podrían utilizar Ecualización de histograma o CLAHE.
import cv2
import numpy as np
# from matplotlib import pyplot as plt
# Automatic brightness and contrast optimization with optional histogram clipping
def automatic_brightness_and_contrast(image, clip_hist_percent=25):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Calculate grayscale histogram
hist = cv2.calcHist([gray],[0],None,[256],[0,256])
hist_size = len(hist)
# Calculate cumulative distribution from the histogram
accumulator = []
accumulator.append(float(hist[0]))
for index in range(1, hist_size):
accumulator.append(accumulator[index -1] + float(hist[index]))
# Locate points to clip
maximum = accumulator[-1]
clip_hist_percent *= (maximum/100.0)
clip_hist_percent /= 2.0
# Locate left cut
minimum_gray = 0
while accumulator[minimum_gray] < clip_hist_percent:
minimum_gray += 1
# Locate right cut
maximum_gray = hist_size -1
while accumulator[maximum_gray] >= (maximum - clip_hist_percent):
maximum_gray -= 1
# Calculate alpha and beta values
alpha = 255 / (maximum_gray - minimum_gray)
beta = -minimum_gray * alpha
'''
# Calculate new histogram with desired range and show histogram
new_hist = cv2.calcHist([gray],[0],None,[256],[minimum_gray,maximum_gray])
plt.plot(hist)
plt.plot(new_hist)
plt.xlim([0,256])
plt.show()
'''
auto_result = cv2.convertScaleAbs(image, alpha=alpha, beta=beta)
return (auto_result, alpha, beta)
image = cv2.imread('1.png')
auto_result, alpha, beta = automatic_brightness_and_contrast(image)
print('alpha', alpha)
print('beta', beta)
cv2.imshow('auto_result', auto_result)
cv2.imwrite('auto_result.png', auto_result)
cv2.imshow('image', image)
cv2.waitKey()
Una versión alternativa es agregar sesgo y ganancia a una imagen usando aritmética de saturación en lugar de usar OpenCV. cv2.convertScaleAbs
. El método incorporado no toma un valor absoluto, lo que conduciría a resultados sin sentido (por ejemplo, un píxel en 44 con alfa = 3 y beta = -210 se convierte en 78 con OpenCV, cuando en realidad debería convertirse en 0).
import cv2
import numpy as np
# from matplotlib import pyplot as plt
def convertScale(img, alpha, beta):
"""Add bias and gain to an image with saturation arithmetics. Unlike
cv2.convertScaleAbs, it does not take an absolute value, which would lead to
nonsensical results (e.g., a pixel at 44 with alpha = 3 and beta = -210
becomes 78 with OpenCV, when in fact it should become 0).
"""
new_img = img * alpha + beta
new_img[new_img < 0] = 0
new_img[new_img > 255] = 255
return new_img.astype(np.uint8)
# Automatic brightness and contrast optimization with optional histogram clipping
def automatic_brightness_and_contrast(image, clip_hist_percent=25):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Calculate grayscale histogram
hist = cv2.calcHist([gray],[0],None,[256],[0,256])
hist_size = len(hist)
# Calculate cumulative distribution from the histogram
accumulator = []
accumulator.append(float(hist[0]))
for index in range(1, hist_size):
accumulator.append(accumulator[index -1] + float(hist[index]))
# Locate points to clip
maximum = accumulator[-1]
clip_hist_percent *= (maximum/100.0)
clip_hist_percent /= 2.0
# Locate left cut
minimum_gray = 0
while accumulator[minimum_gray] < clip_hist_percent:
minimum_gray += 1
# Locate right cut
maximum_gray = hist_size -1
while accumulator[maximum_gray] >= (maximum - clip_hist_percent):
maximum_gray -= 1
# Calculate alpha and beta values
alpha = 255 / (maximum_gray - minimum_gray)
beta = -minimum_gray * alpha
'''
# Calculate new histogram with desired range and show histogram
new_hist = cv2.calcHist([gray],[0],None,[256],[minimum_gray,maximum_gray])
plt.plot(hist)
plt.plot(new_hist)
plt.xlim([0,256])
plt.show()
'''
auto_result = convertScale(image, alpha=alpha, beta=beta)
return (auto_result, alpha, beta)
image = cv2.imread('1.jpg')
auto_result, alpha, beta = automatic_brightness_and_contrast(image)
print('alpha', alpha)
print('beta', beta)
cv2.imshow('auto_result', auto_result)
cv2.imwrite('auto_result.png', auto_result)
cv2.imshow('image', image)
cv2.waitKey()
Necesita modificar el contraste y el brillo.
No uso OpenCV, pero aquí hay una solución de un script bash (Unix) que construí para Imagemagick. Tenga en cuenta que la media controla el brillo y la estándar controla el contraste.
Originalmente, el guión estaba destinado a ajustar una imagen para que coincidiera con los colores / brillo / contraste de otra imagen. La comparación utiliza las desviaciones promedio y estándar de cada imagen de acuerdo con la ecuación: (I2-Mean2) / Std2 = (I1-Mean1) / Std1. Esta ecuación representa una intensidad normalizada tal que tiene media cero y aproximadamente el mismo rango de valores debido a la división por las desviaciones estándar. Resolvemos esta ecuación para formar una transformación lineal entre I1 e I2 de acuerdo con I2 = A x I1 + B, donde A = (Std2 / Std1) es la pendiente o ganancia y B = (Mean2 – A x Mean1) es la intersección de parcialidad. Si no se proporciona una segunda imagen y se proporciona un (conjunto de) medias y desviaciones estándar, el primer archivo se comparará con las medias y desviaciones estándar proporcionadas. La pendiente o la ganancia se correlacionan con el contraste y la intersección o el sesgo se correlacionan con el brillo.
Aporte:
matchimage -c rgb -m 0.6 -s 0.25 bunny.png result1.png
O un poco más de contraste:
matchimage -c rgb -m 0.6 -s 0.35 bunny.png result2.png
Los argumentos se normalizan en un rango de 0 a 1. Entonces mean = 0.6 es equivalente al 60%. Creo que el 66% puede ser demasiado brillante, pero puede cambiar los valores como desee.
En este caso, dado que su imagen era principalmente en escala de grises, utilizo el espacio de color RGB para procesar. El procesamiento se puede realizar en varios otros espacios de color.
Aquí hay una secuencia de comandos de Python similar, que solo hace coincidir una imagen con otra, pero haciéndolo en el espacio de color LAB. Sin embargo, debería ser bastante fácil cambiarlo para hacer coincidir una imagen con un conjunto de argumentos mean y std.
(Mis guiones están disponibles aquí)
Te invitamos a añadir valor a nuestra información participando con tu experiencia en las explicaciones.