使用OpenCV在Python (cv2)中增加彩色图像对比度的最快方法是什么?

14

我正在使用OpenCV处理一些图像,而我需要执行的第一个步骤之一是增加彩色图像的对比度。到目前为止,我发现最快的方法是使用以下代码(其中np是numpy导入),按照原始基于C的cv1文档中建议的方式进行乘法和加法操作:

    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)  

有没有更快的Python方法做这件事?我尝试过使用numpy的标量乘法,但实际上性能更差。我还尝试使用cv2.convertScaleAbs(OpenCV文档建议使用convertTo,但cv2似乎缺少该函数的接口),但在测试中性能仍然更差。


这已经很快了。只是加法和乘法而已。 - Abid Rahman K
加法和乘法操作可以同时进行,以获得有趣的效果。基本上,每个像素都可以转换为 X = aY + b,其中 ab 是标量。这是一种线性变换。我在答案中展示了二次变换,它产生了更有趣的结果 ;) - samkhan13
3个回答

23

正如Abid Rahaman K所评论的那样,使用numpy数组进行简单算术运算是最快的。

以此图片为例:http://i.imgur.com/Yjo276D.png

这里有一个类似于亮度/对比度调整的图像处理示例:

'''
Simple and fast image transforms to mimic:
 - brightness
 - contrast
 - erosion 
 - dilation
'''

import cv2
from pylab import array, plot, show, axis, arange, figure, uint8 

# Image data
image = cv2.imread('imgur.png',0) # load as 1-channel 8bit grayscale
cv2.imshow('image',image)
maxIntensity = 255.0 # depends on dtype of image data
x = arange(maxIntensity) 

# Parameters for manipulating image data
phi = 1
theta = 1

# Increase intensity such that
# dark pixels become much brighter, 
# bright pixels become slightly bright
newImage0 = (maxIntensity/phi)*(image/(maxIntensity/theta))**0.5
newImage0 = array(newImage0,dtype=uint8)

cv2.imshow('newImage0',newImage0)
cv2.imwrite('newImage0.jpg',newImage0)

y = (maxIntensity/phi)*(x/(maxIntensity/theta))**0.5

# Decrease intensity such that
# dark pixels become much darker, 
# bright pixels become slightly dark 
newImage1 = (maxIntensity/phi)*(image/(maxIntensity/theta))**2
newImage1 = array(newImage1,dtype=uint8)

cv2.imshow('newImage1',newImage1)

z = (maxIntensity/phi)*(x/(maxIntensity/theta))**2

# Plot the figures
figure()
plot(x,y,'r-') # Increased brightness
plot(x,x,'k:') # Original image
plot(x,z, 'b-') # Decreased brightness
#axis('off')
axis('tight')
show()

# Close figure window and click on other window 
# Then press any keyboard key to close all windows
closeWindow = -1
while closeWindow<0:
    closeWindow = cv2.waitKey(1) 
cv2.destroyAllWindows()

原始灰度图像:

enter image description here

明亮的图像看起来似乎被膨胀了:

enter image description here

变暗的图像看起来被侵蚀、锐化,并具有更好的对比度:

enter image description here

像素强度的转换方式:

enter image description here

如果你调整 phitheta 的值,可以得到非常有趣的结果。你也可以将此技巧应用于多通道图像数据。

--- 编辑 ---

在这个YouTube视频中,查看Photoshop中“级别”和“曲线”的概念:http://youtu.be/hZeMqXxMG_8。线性变换方程会在每个像素上创造相同数量即“水平”的变化。如果你编写一个可以区分像素类型(例如那些已经具有某个值的像素)的方程式,则可以根据该方程式描述的“曲线”更改像素。


如果我需要同时编译两个功能,即增加暗像素的亮度和降低过亮像素的亮度,我们能实现这种行为吗? - ZdaR
我尝试过了,但没有得到期望的结果,有什么建议吗? - ZdaR
@Anmol_uppal,就像我在“EDIT”部分所说的那样,你需要找到能够实现此功能的方程式。我能想到的最简单的方法是使用cv2.inrange()函数来修改在较低和较高范围内的像素。你可能只需要调用两次cv2.inrange()函数,分别针对两个不同的边界条件。 - samkhan13
@samkahn13 如果您能在 http://stackoverflow.com/questions/28370075/descent-image-equalization 的上下文中提供指导,那将非常有帮助。 - ZdaR
@samkhan13,如何最好地加深暗像素并使较亮的像素变亮。我在你的回答中没有看到任何示例。 - gabbar0x

21

尝试使用这段代码:

import cv2

img = cv2.imread('sunset.jpg', 1)
cv2.imshow("Original image",img)

# CLAHE (Contrast Limited Adaptive Histogram Equalization)
clahe = cv2.createCLAHE(clipLimit=3., tileGridSize=(8,8))

lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)  # convert from BGR to LAB color space
l, a, b = cv2.split(lab)  # split on 3 different channels

l2 = clahe.apply(l)  # apply CLAHE to the L-channel

lab = cv2.merge((l2,a,b))  # merge channels
img2 = cv2.cvtColor(lab, cv2.COLOR_LAB2BGR)  # convert from LAB to BGR
cv2.imshow('Increased contrast', img2)
#cv2.imwrite('sunset_modified.jpg', img2)

cv2.waitKey(0)
cv2.destroyAllWindows()

日落之前: 在此输入图片描述 增强对比度后的日落: 在此输入图片描述


1
OP要求最快的对比增强,线性转换对他们来说不够快!您提出的解决方案在速度上与OP中不够快的过程相比如何? - gboffi
@gboffi -- 是的,“最快的方法”...我太专注于制作更清晰的彩色图像,以至于问题的本质没有浮现在我的脑海中 :-)。据我所知,NumPy具有C语言的速度,因为它是用C语言编写的。比C语言更快的方式是什么?是汇编语言 :-)。我认为没有比二维矩阵的线性变换更快的算法了。因此,如果OP在汇编语言上进行二维矩阵的线性变换,它将比C语言(或用C语言编写的NumPy)更快。我认为CLAHE不比NumPy的线性变换更快,因为它是更复杂的算法。 - FooBar167
这段代码的缺点在于它增加了亮度通道的对比度,但保持了颜色通道不变。因此,结果图像的颜色对比度降低了。你的照片并不是最好的例子。当你尝试用其他颜色更多、对比度较少的照片时,你会注意到这段代码并不能产生最佳效果。 - Elmue
1
我忘记了问题,但答案很棒。感谢您对我的色彩科学知识的贡献。 - nerkn

0

使用cv2::addWeighted函数。它比迄今为止介绍的任何其他方法都要快。它是设计用于处理两个图像:

dst = cv.addWeighted( src1, alpha, src2, beta, gamma[, dst[, dtype]] )

但如果您两次使用相同的图像,并将beta设置为零,您可以获得所需的效果。

dst = cv.addWeighted( src1, alpha, src1, 0, gamma)

使用此功能的最大优点是,您不必担心值低于0或高于255时会发生什么。在numpy中,您必须自己解决所有剪辑问题。使用OpenCV函数,它会为您完成所有剪辑工作,并且速度很快。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接