我想在OpenCV中将图像的亮度调整为某个值。例如,考虑以下图片:
我用以下方法计算亮度:
import cv2
img = cv2.imread(filepath)
cols, rows = img.shape
brightness = numpy.sum(img) / (255 * cols * rows)
,我的平均亮度为35%。例如,将其提高到66%,
minimum_brightness = 0.66
alpha = brightness / minimum_brightness
bright_img = cv2.convertScaleAbs(img, alpha = alpha, beta = 255 * (1 - alpha))
我得到的图像似乎具有50%的透明度:
我只能通过使用偏倚来避免这种影响:
bright_img = cv2.convertScaleAbs(img, alpha = 1, beta = 128)
并且图像似乎也带有面纱:
如果我手动进行操作,例如在Photoshop中将亮度调整为150,则结果似乎还不错:
但是,这不是自动的,不会提供目标亮度。
我可以通过伽马校正和/或直方图均衡来实现,以获得更自然的结果,但是除了反复试验外,我没有一种简单的方法来获得目标亮度。
有人成功地将亮度自动调整为目标吗?
假名建议:
bright_img = cv2.convertScaleAbs(img, alpha = 1, beta = 255 * (minimum_brightness - brightness))
结果更好,但仍然有面纱:
Yves Daoust建议保持beta = 0
,因此我调整了alpha = minimum_brightness / 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)
结果很好:
答案 0 :(得分:3)
您可以尝试使用带有直方图裁剪的对比度优化来自动调整亮度。您可以通过增加直方图片段百分比(clip_hist_percent
)来提高目标亮度。这是裁剪25%时的结果
Alpha和Beta是自动计算的
alpha 3.072289156626506
beta -144.3975903614458
这是剪辑的可视化。蓝色(原始),橙色(自动调整后)。
裁剪结果为35%
alpha 3.8059701492537314
beta -201.71641791044777
其他方法可能正在使用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()
答案 1 :(得分:2)
您需要修改对比度和亮度。
我不使用OpenCV,但这是我为Imagemagick构建的(Unix)bash脚本的一种解决方案。 请注意,平均值控制亮度,而标准差则控制对比度。
该脚本最初旨在调整一个图像以匹配另一图像的颜色/亮度/对比度。匹配根据以下公式使用每个图像的平均值和标准偏差:(I2-Mean2)/ Std2 =(I1-Mean1)/ Std1。该方程式表示归一化强度,由于归因于标准偏差,因此它具有零均值和近似相同的值范围。我们根据I2 = A x I1 + B求解该方程以在I1和I2之间形成线性变换,其中A =(Std2 / Std1)是斜率或增益,而B =(Mean2-A x Mean1)是偏压。如果没有提供第二张图像,并且提供了(一组)均值和标准差,则第一个文件将与提供的均值和标准差匹配。 斜率或增益与对比度相关,截距或偏差与亮度相关。
输入:
matchimage -c rgb -m 0.6 -s 0.25 bunny.png result1.png
或更强的对比度:
matchimage -c rgb -m 0.6 -s 0.35 bunny.png result2.png
参数归一化为0到1范围。因此平均值= 0.6等于60%。我认为66%可能太亮了,但是您可以根据需要更改值。
在这种情况下,由于您的图像主要是灰度图像,因此我使用色彩空间RGB进行处理。可以在其他几种颜色空间中进行处理。
有一个类似的Python脚本here,该脚本只将一个图像与另一个图像匹配,但是在LAB颜色空间中进行了匹配。但是,更改它以将一个图像与一组均值和标准参数相匹配应该足够容易。
(我的脚本可用here)
答案 2 :(得分:0)
一种解决方案是调整图像的灰度系数。在下面的代码中,我首先在范围的顶部和底部将图像饱和到一定百分比,然后调整伽玛校正,直到达到所需的亮度。
import cv2
import numpy as np
def saturate(img, percentile):
"""Changes the scale of the image so that half of percentile at the low range
becomes 0, half of percentile at the top range becomes 255.
"""
if 2 != len(img.shape):
raise ValueError("Expected an image with only one channel")
# copy values
channel = img[:, :].copy()
flat = channel.ravel()
# copy values and sort them
sorted_values = np.sort(flat)
# find points to clip
max_index = len(sorted_values) - 1
half_percent = percentile / 200
low_value = sorted_values[math.floor(max_index * half_percent)]
high_value = sorted_values[math.ceil(max_index * (1 - half_percent))]
# saturate
channel[channel < low_value] = low_value
channel[channel > high_value] = high_value
# scale the channel
channel_norm = channel.copy()
cv2.normalize(channel, channel_norm, 0, 255, cv2.NORM_MINMAX)
return channel_norm
def adjust_gamma(img, gamma):
"""Build a lookup table mapping the pixel values [0, 255] to
their adjusted gamma values.
"""
# code from
# https://www.pyimagesearch.com/2015/10/05/opencv-gamma-correction/
invGamma = 1.0 / gamma
table = np.array([((i / 255.0) ** invGamma) * 255 for i in np.arange(0, 256)]).astype("uint8")
# apply gamma correction using the lookup table
return cv2.LUT(img, table)
def adjust_brightness_with_gamma(gray_img, minimum_brightness, gamma_step = GAMMA_STEP):
"""Adjusts the brightness of an image by saturating the bottom and top
percentiles, and changing the gamma until reaching the required brightness.
"""
if 3 <= len(gray_img.shape):
raise ValueError("Expected a grayscale image, color channels found")
cols, rows = gray_img.shape
changed = False
old_brightness = np.sum(gray_img) / (255 * cols * rows)
new_img = gray_img
gamma = 1
while True:
brightness = np.sum(new_img) / (255 * cols * rows)
if brightness >= minimum_brightness:
break
gamma += gamma_step
new_img = adjust_gamma(gray_img, gamma = gamma)
changed = True
if changed:
print("Old brightness: %3.3f, new brightness: %3.3f " %(old_brightness, brightness))
else:
print("Maintaining brightness at %3.3f" % old_brightness)
return new_img
def main(filepath):
img = cv2.imread(filepath)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
saturated = saturate(gray, 1)
bright = adjust_brightness_with_gamma(saturated, minimum_brightness = 0.66)
结果在这里,不及被接受的答案:
根据图像,我可以在接受的答案中使用alpha-beta调整,或者使用gamma来避免剪切过多的高光。每个步骤的大小(剪裁为百分位数,校正为伽玛)确定每次调整的权重。
PERCENTILE_STEP = 1
GAMMA_STEP = 0.01
def adjust_brightness_alpha_beta_gamma(gray_img, minimum_brightness, percentile_step = PERCENTILE_STEP, gamma_step = GAMMA_STEP):
"""Adjusts brightness with histogram clipping by trial and error.
"""
if 3 <= len(gray_img.shape):
raise ValueError("Expected a grayscale image, color channels found")
new_img = gray_img
percentile = percentile_step
gamma = 1
brightness_changed = False
while True:
cols, rows = new_img.shape
brightness = np.sum(new_img) / (255 * cols * rows)
if not brightness_changed:
old_brightness = brightness
if brightness >= minimum_brightness:
break
# adjust alpha and beta
percentile += percentile_step
alpha, beta = percentile_to_bias_and_gain(new_img, percentile)
new_img = convertScale(gray_img, alpha = alpha, beta = beta)
brightness_changed = True
# adjust gamma
gamma += gamma_step
new_img = adjust_gamma(new_img, gamma = gamma)
if brightness_changed:
print("Old brightness: %3.3f, new brightness: %3.3f " %(old_brightness, brightness))
else:
print("Maintaining brightness at %3.3f" % old_brightness)
return new_img
答案 3 :(得分:-1)
如果您这样尝试怎么办:
bright_img = cv2.convertScaleAbs(img, alpha = 1, beta = 255 * (minimum_brightness - brightness))