【问题标题】:How do I increase the contrast of an image in Python OpenCV如何在 Python OpenCV 中增加图像的对比度
【发布时间】:2017-01-11 11:49:21
【问题描述】:

我是 Python OpenCV 的新手。我已经阅读了一些文档和答案here,但我无法弄清楚以下代码的含义:

if (self.array_alpha is None):
    self.array_alpha = np.array([1.25])
    self.array_beta = np.array([-100.0])

# add a beta value to every pixel 
cv2.add(new_img, self.array_beta, new_img)                    

# multiply every pixel value by alpha
cv2.multiply(new_img, self.array_alpha, new_img)  

我知道Basically, every pixel can be transformed as X = aY + b where a and b are scalars.。基本上,我已经明白了这一点。但是,我不明白代码以及如何增加与此的对比度。

到目前为止,我已经设法使用 img = cv2.imread('image.jpg',0) 简单地读取图像

感谢您的帮助

【问题讨论】:

标签: python image opencv image-processing computer-vision


【解决方案1】:

对于 Python,我还没有找到提供对比的 OpenCV 函数。正如其他人所建议的那样,有一些技术可以使用非常简单的公式自动增加对比度。

official OpenCV docs中,建议可以使用这个方程同时应用对比度和亮度:

new_img = alpha*old_img + beta

其中 alpha 对应于对比度,而 beta 是亮度。不同的情况

alpha 1  beta 0      --> no change  
0 < alpha < 1        --> lower contrast  
alpha > 1            --> higher contrast  
-127 < beta < +127   --> good range for brightness values

在 C/C++ 中,您可以使用 cv::Mat::convertTo 来实现这个等式,但我们无法从 Python 访问该库的那部分。要在 Python 中执行此操作,我建议使用 cv::addWeighted 函数,因为它速度很快,并且它会自动强制输出在 0 到 255 的范围内(例如,对于 24 位彩色图像,每个通道 8 位)。您也可以按照@nathancy 的建议使用convertScaleAbs

import cv2
img = cv2.imread('input.png')
# call addWeighted function. use beta = 0 to effectively only operate one one image
out = cv2.addWeighted( img, contrast, img, 0, brightness)
output = cv2.addWeighted

上面的公式和代码写起来很快,会改变亮度和对比度。但它们产生的结果与照片编辑程序有很大不同。该答案的其余部分将产生一个结果,该结果将重现 GIMP 中的行为以及 LibreOffice 亮度和对比度。这是更多的代码行,但它给出了一个很好的结果。

对比

the GIMP 中,对比度从-127 到+127。我调整了公式from here 以适应该范围。

f = 131*(对比度 + 127)/(127*(131-对比度))
new_image = f*(old_image - 127) + 127 = f*(old_image) + 127*(1-f)

为了弄清楚亮度,我弄清楚了亮度和级别之间的关系,并使用this levels post中的信息得出了一个解决方案。

#pseudo code
if brightness > 0
    shadow = brightness
    highlight = 255
else:
    shadow = 0
    highlight = 255 + brightness
new_img = ((highlight - shadow)/255)*old_img + shadow

Python 和 OpenCV 中的亮度和对比度

将它们放在一起并使用来自USC SIPI 的参考“山魈”图像添加:

import cv2
import numpy as np

# Open a typical 24 bit color image. For this kind of image there are
# 8 bits (0 to 255) per color channel
img = cv2.imread('mandrill.png')  # mandrill reference image from USC SIPI

s = 128
img = cv2.resize(img, (s,s), 0, 0, cv2.INTER_AREA)

def apply_brightness_contrast(input_img, brightness = 0, contrast = 0):
    
    if brightness != 0:
        if brightness > 0:
            shadow = brightness
            highlight = 255
        else:
            shadow = 0
            highlight = 255 + brightness
        alpha_b = (highlight - shadow)/255
        gamma_b = shadow
        
        buf = cv2.addWeighted(input_img, alpha_b, input_img, 0, gamma_b)
    else:
        buf = input_img.copy()
    
    if contrast != 0:
        f = 131*(contrast + 127)/(127*(131-contrast))
        alpha_c = f
        gamma_c = 127*(1-f)
        
        buf = cv2.addWeighted(buf, alpha_c, buf, 0, gamma_c)

    return buf


font = cv2.FONT_HERSHEY_SIMPLEX
fcolor = (0,0,0)

blist = [0, -127, 127,   0,  0, 64] # list of brightness values
clist = [0,    0,   0, -64, 64, 64] # list of contrast values


out = np.zeros((s*2, s*3, 3), dtype = np.uint8)

for i, b in enumerate(blist):
    c = clist[i]
    print('b, c:  ', b,', ',c)
    row = s*int(i/3)
    col = s*(i%3)
    
    print('row, col:   ', row, ', ', col)
    
    out[row:row+s, col:col+s] = apply_brightness_contrast(img, b, c)
    msg = 'b %d' % b
    cv2.putText(out,msg,(col,row+s-22), font, .7, fcolor,1,cv2.LINE_AA)
    msg = 'c %d' % c
    cv2.putText(out,msg,(col,row+s-4), font, .7, fcolor,1,cv2.LINE_AA)
    
    cv2.putText(out, 'OpenCV',(260,30), font, 1.0, fcolor,2,cv2.LINE_AA)

cv2.imwrite('out.png', out)

我在 GIMP 中手动处理了图像,并在 Python/OpenCV 中添加了文本标签:

注意: @UtkarshBhardwaj 建议 Python 2.x 用户必须将对比度校正计算代码转换为 float 以获得浮动结果,如下所示:

...
if contrast != 0:
        f = float(131*(contrast + 127))/(127*(131-contrast))
...

【讨论】:

  • @Nykodym,您的评论完全正确。答案已经过大幅编辑,更加一致。
  • 太棒了,好多了:) 删除了旧的、断章取义的评论和 +1。
【解决方案2】:

这里有很多答案,从简单到复杂。我想在更简单的一面添加另一个,对于实际的对比度和亮度调整来说似乎更实用。

def adjust_contrast_brightness(img, contrast:float=1.0, brightness:int=0):
    """
    Adjusts contrast and brightness of an uint8 image.
    contrast:   (0.0,  inf) with 1.0 leaving the contrast as is
    brightness: [-255, 255] with 0 leaving the brightness as is
    """
    brightness += int(round(255*(1-contrast)/2))
    return cv2.addWeighted(img, contrast, img, 0, brightness)

我们通过addWeighted() 函数进行a*x+b 调整。然而,要改变对比度而不改变亮度,数据需要以零为中心。 OpenCVs 默认的 uint8 数据类型不是这种情况。所以我们还需要根据分布的变化来调整亮度。

【讨论】:

  • 这实际上是最有帮助的问题,因为如果你想保持它不受影响,其他人都错过了亮度调整。
【解决方案3】:

可以分别使用 alpha (α) 和 beta (β) 调整对比度和亮度。这些变量通常称为 gainbias 参数。表达式可以写成

OpenCV 已经将其实现为cv2.convertScaleAbs(),只需提供用户定义的alphabeta

import cv2

image = cv2.imread('1.jpg')

alpha = 1.5 # Contrast control (1.0-3.0)
beta = 0 # Brightness control (0-100)

adjusted = cv2.convertScaleAbs(image, alpha=alpha, beta=beta)

cv2.imshow('original', image)
cv2.imshow('adjusted', adjusted)
cv2.waitKey()

之前-&gt;之后

注意:要自动调整亮度/对比度,请查看automatic contrast and brightness adjustment of a color photo

【讨论】:

  • 当图像数据不是以零为中心(OpenCV 中通常是这种情况)时,调整 alpha 并不对应于改变对比度。你用这个例子很清楚地表明了这一点。修改后的图像更亮,尽管您似乎只想更改对比度。我自己添加了一个答案,根据选择的对比度改变亮度。
  • convertScaleAbs 不应以这种方式使用,因为如果结果值为负数,它们不会在零处饱和,而是应用绝对值。
【解决方案4】:
img = cv2.imread("/x2.jpeg")

image = cv2.resize(img, (1800, 1800))

alpha=1.5
beta=20

new_image=cv2.addWeighted(image,alpha,np.zeros(image.shape, image.dtype),0,beta)

cv2.imshow("new",new_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

【讨论】:

  • 有一些非常好的、详细的答案,在这个问题上有很多赞成票。如果现有答案缺少某些内容,可以添加另一个答案。但是考虑到它们的详细程度,以及它们已被社区验证的程度,更新你的答案以解释你在做什么以及为什么你认为它是真的有用的对那些现有答案的改进。你介意这样做吗?
  • @JeremyCaney 我添加了,因为它非常简单,人们让它变得复杂,只需几行非常简单的代码,我们就可以得到我们预期的结果,如果它是错误的,那么我可以删除它!
  • 是的,非常感谢您让我变得如此简单!喜欢它!
【解决方案5】:

我想建议一种使用 LAB 颜色通道的方法。维基百科有足够的关于 LAB 颜色通道的信息。

我使用 OpenCV 3.0.0 和 python 完成了以下操作:

import cv2

#-----Reading the image-----------------------------------------------------
img = cv2.imread('Dog.jpg', 1)
cv2.imshow("img",img) 

#-----Converting image to LAB Color model----------------------------------- 
lab= cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
cv2.imshow("lab",lab)

#-----Splitting the LAB image to different channels-------------------------
l, a, b = cv2.split(lab)
cv2.imshow('l_channel', l)
cv2.imshow('a_channel', a)
cv2.imshow('b_channel', b)

#-----Applying CLAHE to L-channel-------------------------------------------
clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8,8))
cl = clahe.apply(l)
cv2.imshow('CLAHE output', cl)

#-----Merge the CLAHE enhanced L-channel with the a and b channel-----------
limg = cv2.merge((cl,a,b))
cv2.imshow('limg', limg)

#-----Converting image from LAB Color model to RGB model--------------------
final = cv2.cvtColor(limg, cv2.COLOR_LAB2BGR)
cv2.imshow('final', final)

#_____END_____#

您可以按原样运行代码。 要了解 CLAHE(Contrast Limited Adaptive Histogram Equalization)是什么,您可以再次查看 Wikipedia。

【讨论】:

【解决方案6】:

X = aY + b(实际上是f(x) = ax + b)的最佳解释见https://math.stackexchange.com/a/906280/357701

通过调整亮度/亮度/亮度来获得更简单的对比度,如下所示:

import cv2

img = cv2.imread('test.jpg')
cv2.imshow('test', img)
cv2.waitKey(1000)
imghsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)


imghsv[:,:,2] = [[max(pixel - 25, 0) if pixel < 190 else min(pixel + 25, 255) for pixel in row] for row in imghsv[:,:,2]]
cv2.imshow('contrast', cv2.cvtColor(imghsv, cv2.COLOR_HSV2BGR))
cv2.waitKey(1000)
raw_input()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-24
    • 1970-01-01
    • 2021-07-05
    • 2013-10-22
    • 2011-05-07
    • 2018-05-23
    • 1970-01-01
    相关资源
    最近更新 更多