色阶:就是用直方图描述出的整张图片的明暗信息。如图
从左至右是从暗到亮的像素分布,
黑色三角代表最暗地方(纯黑—黑点值为0),
白色三角代表最亮地方(纯白—白点为 255)。
灰色三角代表中间调。(灰点为1.00)
对于一个RGB图像, 可以对R, G, B 通道进行独立的色阶调整,即对三个通道分别使用三个色阶定义值。还可以再对 三个通道进行整体色阶调整。
因此,对一个图像,可以用四次色阶调整。最终的结果,是四次调整后合并产生的结果。
cv2.equalizeHist(img) 函数
img = cv2.imread('./20181106194742.png',0)
equ = cv2.equalizeHist(img) # 只能传入灰度图
res = np.hstack((img,equ)) # 图像列拼接(用于显示)
cv2.imshow('res',res)
cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.createCLAHE() 对比度有限自适应直方图均衡
直方图均衡后背景对比度有所改善。但导致亮度过高,我们丢失了大部分信息。这是因为它的直方图并不局限于特定区域。
因此,为了解决这个问题,使用自适应直方图均衡。在此,图像被分成称为“图块”的小块(在OpenCV中,tileSize默认为8x8)。然后像往常一样对这些块中的每一个进行直方图均衡。所以在一个小区域内,直方图会限制在一个小区域(除非有噪音)。如果有噪音,它会被放大。为避免这种情况,应用对比度限制。如果任何直方图区间高于指定的对比度限制(在OpenCV中默认为40),则在应用直方图均衡之前,将这些像素剪切并均匀分布到其他区间。均衡后,为了去除图块边框中的瑕疵,应用双线性插值。
import numpy as np
import cv2
img = cv2.imread('20181106194742.png',0)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
cl1 = clahe.apply(img)
cv2.imshow('img',img)
cv2.imshow('cl1',cl1)
cv2.waitKey(0)
cv2.destroyAllWindows()
自适应色阶去雾气【参看代码请点击】 主要使用numpy优化了计算耗时。
import numpy as np
import cv2
def ComputeMinLevel(hist, pnum):
index = np.add.accumulate(hist)
return np.argwhere(index>pnum * 8.3 * 0.01)[0][0]
def ComputeMaxLevel(hist, pnum):
hist_0 = hist[::-1]
Iter_sum = np.add.accumulate(hist_0)
index = np.argwhere(Iter_sum > (pnum * 2.2 * 0.01))[0][0]
return 255-index
def LinearMap(minlevel, maxlevel):
if (minlevel >= maxlevel):
return []
else:
index = np.array(list(range(256)))
screenNum = np.where(index<minlevel,0,index)
screenNum = np.where(screenNum> maxlevel,255,screenNum)
for i in range(len(screenNum)):
if screenNum[i]> 0 and screenNum[i] < 255:
screenNum[i] = (i - minlevel) / (maxlevel - minlevel) * 255
return screenNum
def CreateNewImg(img):
h, w, d = img.shape
newimg = np.zeros([h, w, d])
for i in range(d):
imghist = np.bincount(img[:, :, i].reshape(1, -1)[0])
minlevel = ComputeMinLevel(imghist, h * w)
maxlevel = ComputeMaxLevel(imghist, h * w)
screenNum = LinearMap(minlevel, maxlevel)
if (screenNum.size == 0):
continue
for j in range(h):
newimg[j, :, i] = screenNum[img[j, :, i]]
return newimg
if __name__ == '__main__':
img = cv2.imread('./20181106194742.png')
newimg = CreateNewImg(img)
cv2.imshow('original_img', img)
cv2.imshow('new_img', newimg / 255)
cv2.waitKey(0)
cv2.destroyAllWindows()