可以分别使用alpha(α)和beta(β)调节亮度和对比度。表达式可以写成
OpenCV已经将其实现为cv2.convertScaleAbs()
因此我们可以将此功能与用户定义的alpha
和beta
值一起使用。
import cv2
import numpy as np
from matplotlib import pyplot as plt
image = cv2.imread('1.jpg')
alpha = 1.95 # Contrast control (1.0-3.0)
beta = 0 # Brightness control (0-100)
manual_result = cv2.convertScaleAbs(image, alpha=alpha, beta=beta)
cv2.imshow('original', image)
cv2.imshow('manual_result', manual_result)
cv2.waitKey()
但是问题是
如何获得彩色照片的自动亮度/对比度优化?
本质上,问题是如何自动计算alpha
和beta
。为此,我们可以查看图像的直方图。自动亮度和对比度优化计算alpha和beta,以便输出范围为[0...255]
。我们计算累积分布以确定颜色频率小于某个阈值(例如1%)的位置,并切掉直方图的右侧和左侧。这给了我们最小和最大范围。这是裁剪前(蓝色)和裁剪后(橙色)的直方图的可视化。请注意,裁剪后图像的“有趣”部分如何变得更加明显。
为了计算alpha
,我们在裁剪后取最小和最大灰度范围,并将其与所需的255
输出范围255
α = 255 / (maximum_gray - minimum_gray)
为了计算beta,我们将其插入公式中,其中g(i, j)=0
和f(i, j)=minimum_gray
g(i,j) = α * f(i,j) + β
解决后导致的结果
β = -minimum_gray * α
为您的图片,我们得到这个
阿尔法:3.75
Beta:-311.25
您可能需要调整裁剪阈值以优化结果。这是对其他图像使用1%阈值的一些示例结果
自动亮度和对比度代码
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=1):
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.jpg')
auto_result, alpha, beta = automatic_brightness_and_contrast(image)
print('alpha', alpha)
print('beta', beta)
cv2.imshow('auto_result', auto_result)
cv2.waitKey()
结果代码如下:
阈值为1%的其他图像的结果
另一种版本是使用饱和度算法而不是OpenCV的cv2.convertScaleAbs
向图像添加偏置和增益。内置方法未采用绝对值,这将导致无意义的结果(例如,在OpenCV中,alpha = 3且beta = -210处的像素在44处变为78,而实际上应变为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()
0
拍摄一张纸时(例如,使用电话摄像头),我得到以下结果(左图)(jpg 在此处下载)。所需的结果(使用图像编辑软件手动处理)在右侧:
我想用openCV处理原始图像,以自动获得更好的亮度/对比度(以使背景更白) 。
假设:图像具有A4纵向格式(在本主题中,我们无需对其进行透视变形),并且纸页为白色,可能带有黑色或彩色的文本/图像。
到目前为止,我已经尝试过:
各种自适应阈值方法,例如高斯,OTSU(请参阅OpenCV doc 图像阈值 )。通常可以与OTSU配合使用:
但它仅适用于灰度图像 ,不适用于彩色图像。此外, 输出是二进制(白色或黑色),我不希望这样 :我更喜欢保留彩色非二进制图像作为输出
直方图均衡
如本建议答案 ( 直方图均衡化不是彩色图像的工作- OpenCV的 )或该一个 ( OpenCV的Python的equalizeHist彩色图像 ):
或使用HSV:
不幸的是,结果非常糟糕,因为它会在本地产生可怕的微对比度(?):
我还尝试了YCbCr,这很相似。
我还尝试了从
1
到1000
各种tileGridSize
CLAHE(对比度受限的自适应直方图均衡) :但是结果也同样糟糕。
按照LAB颜色空间进行此CLAHE方法,如问题如何在RGB彩色图像上应用CLAHE所示 :
也给不好的结果。输出图像:
每个通道 (R,G,B) 上分别做一个自适应阈值或直方图均衡是不因为它会弄乱颜色平衡,如所解释的选项这里 。
scikit-image
的直方图均衡化教程中的“对比拉伸”方法:会好一些,但仍远未达到理想的结果(请参阅此问题顶部的图像)。
TL; DR:如何使用OpenCV / Python对一张纸的彩色照片进行自动亮度/对比度优化?可以使用哪种阈值/直方图均衡/其他技术?