使用OpenCV自动调整图像的亮度 [英] Automatically adjusting brightness of image with OpenCV

查看:265
本文介绍了使用OpenCV自动调整图像的亮度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在OpenCV中将图像的亮度调整为某个值.例如,考虑以下图片:

I want to adjust the brightness of an image to a certain value in OpenCV. For example, consider this image:

我用以下方法计算亮度:

I calculate the brightness with:

import cv2
img = cv2.imread(filepath)
cols, rows = img.shape
brightness = numpy.sum(img) / (255 * cols * rows)

,我的平均亮度为35%.例如,要将其提高到66%,我这样做:

and I get an average brightness of 35%. To bring it to 66%, for example, I do:

minimum_brightness = 0.66
alpha = brightness / minimum_brightness
bright_img = cv2.convertScaleAbs(img, alpha = alpha, beta = 255 * (1 - alpha))

我得到的图像似乎具有50%的透明面纱:

and I get an image that seems to have a 50% transparency veil:

我可以通过仅使用偏差来避免这种影响:

I can avoid this effect by using bias only:

bright_img = cv2.convertScaleAbs(img, alpha = 1, beta = 128)

并且图像似乎也带有面纱:

and the image also seems to have a veil:

如果我手动进行操作,例如在Photoshop中将亮度调整为150,则结果似乎还不错:

If I do it by hand, for example in Photoshop with a brightness adjustment at 150, the result seems alright:

但是,这不是自动的,不会给出目标亮度.

But, this is not automatic and does not give the target brightness.

我可以通过伽玛校正和/或直方图均衡来实现,以获得更自然的结果,但是除了反复试验外,我看不到一种简单的方法来获得目标亮度.

I could do it with either a gamma correction and/or histogram equalization for maybe a more natural result, but I don't see an easy way to get the target brightness other than trial-and-error.

有没有人成功将亮度自动调整为目标?

Has anyone succeeded in adjusting brightness automatically to a target?

假名建议:

bright_img = cv2.convertScaleAbs(img, alpha = 1, beta = 255 * (minimum_brightness - brightness))

结果更好,但仍然有面纱:

and the result is better but still has a veil:

Yves Daoust建议保持beta = 0,因此我调整了alpha = minimum_brightness / brightness以获得目标亮度:

Yves Daoust suggested keeping beta = 0, so I adjusted alpha = minimum_brightness / brightness to get the target brightness:

ratio = brightness / minimum_brightness
if ratio >= 1:
    print("Image already bright enough")
    return img

# Otherwise, adjust brightness to get the target brightness
return cv2.convertScaleAbs(img, alpha = 1 / ratio, beta = 0)

结果很好:

推荐答案

您可以尝试使用带有直方图裁剪的对比度优化来自动调整亮度.您可以通过增加直方图片段百分比(clip_hist_percent)来提高目标亮度.这是裁剪25%时的结果

You can try automatically adjusting the brightness using contrast optimization with histogram clipping. You can increase the target brightness by increasing the histogram clip percent (clip_hist_percent). Here's the result at 25% clipping

Alpha和Beta是自动计算的

Alpha and beta are automatically calculated

alpha 3.072289156626506

alpha 3.072289156626506

beta -144.3975903614458

beta -144.3975903614458

这是剪辑的可视化.蓝色(原始),橙色(自动调整后).

Here's a visualization of the clipping. Blue (original), Orange (after auto adjustment).

裁剪结果为35%

alpha 3.8059701492537314

alpha 3.8059701492537314

beta -201.71641791044777

beta -201.71641791044777

其他方法可以使用直方图均衡或CLAHE .

Other methods could be using Histogram Equalization or 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()

另一种版本是使用饱和度算法而不是使用OpenCV的cv2.convertScaleAbs为图像添加偏置和增益.内置方法没有取绝对值,这将导致无意义的结果(例如,在像素为44时,alpha = 3且beta = -210的像素在OpenCV中变为78,而实际上应该变为0).

An alternative version is to add bias and gain to an image using saturation arithmetics instead of using OpenCV's cv2.convertScaleAbs. The built-in method 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).

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()

这篇关于使用OpenCV自动调整图像的亮度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆