Saltar al contenido

Ajustar automáticamente el brillo de la imagen con OpenCV

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

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

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%

ingrese la descripción de la imagen aquíingrese la descripción de la imagen aquí

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:

ingrese la descripción de la imagen aquí

matchimage -c rgb -m 0.6 -s 0.25 bunny.png result1.png

ingrese la descripción de la imagen aquí

O un poco más de contraste:

matchimage -c rgb -m 0.6 -s 0.35 bunny.png result2.png

ingrese la descripción de la imagen aquí

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.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *