目录
一、相关概念
1、灰度直方图概念(hist)
2、灰度概率累积函数(cdf)
3、灰度直方图均衡化(equalizehist)
4、均衡化适用范围
二、均衡化的目的以及求解步骤
1、目的
2、求解步骤
(1)原图灰度直方图求解
(2)计算累积直方图
直方图.cumsum(),返回累积直方图数据
(3)取整扩展确定映射关系
(4)根据映射关系计算均衡化直方图以及图像(这一步是关键)
3、绘制未均衡和均衡后对应像素点像素值的改变
三、全局均衡化直方图
1、系统自带函数
2、自定义函数
3、结果展示
四、限制对比度自适应直方图均衡(Contrast LimitedAdaptive histgram equalization/CLAHE)
1、限制对比度自适应直方图均衡的概念
2、适用场景与优势
3、原理及代码
一、相关概念
1、灰度直方图概念(hist)
对图像中不同灰度级别出现的次数进行统计,统计后进行绘制直方图,横坐标表示灰度级别0-255,纵坐标表示每个灰度级别在图像中出现的次数,一般会对次数进行归一化,用每个灰度级出现的次数除以图像的像素总个数
2、灰度概率累积函数(cdf)
灰度级由0到255出现频率次数不断进行累加得到的直方图
3、灰度直方图均衡化(equalizehist)
简单来说就是使得灰度在不同灰度级别出现的概率更加的均匀均衡的意思就是使得每一个灰度级别的像素点个数是一样或者相近的,这时候灰度累积直方图是一条直线,这时候出现的频率相近则灰度级别类别也就多了,出现的次数也差不多,能够增加图像的对比度,均衡化常用于偏暗和偏亮的图像处理
4、均衡化适用范围
当直方图中的数据集中在某一个灰度值范围内时,直方图均衡化很有用。但是如果像素的变化很大,而且占据的灰度范围非常广时,例如:既有很亮的像素点又有很暗的像素点时。请查看更多资源中的 SOF 链接。
二、均衡化的目的以及求解步骤
1、目的
这种方法通常用来增加许多图像的全局对比度,尤其是当图像的有用数据的对比度相当接近的时候。通过这种方法,亮度可以更好地在直方图上分布,这样就可以用于增强局部的对比度而不影响整体的对比度。
这种方法对于背景和前景都太亮或者太暗的图像非常有用,这种方法尤其是可以带来X光图像中更好的骨骼结构显示以及曝光过度或者曝光不足照片中更好的细节。
这种方法的一个主要优势是它是一个相当直观的技术并且是可逆操作,如果已知均衡化函数,那么就可以恢复原始的直方图,并且计算量也不大。这种方法的一个缺点是它对处理的数据不加选择,它可能会增加背景噪声的对比度并且降低有用信号的对比度。
2、求解步骤
以图像为3位,共2**3-1 = 8个灰度级 ,0-7,求解过程如表中数据
(1)原图灰度直方图求解
用自带函数cv2.calcHist()也可以求解,表示每个灰度级的频率,即该灰度级出现的个数占总像素点的比例
img = cv2.imread(img,0)#第一步获取图像的直方图h,w = img.shapehist = cv2.calcHist([img],[0],None,[256],[0,255])#这里返回的是次数hist[0:255] = hist[0:255]/(h*w)#将直方图归一化,化为概率的形式
(2)计算累积直方图
也就是统计每一个灰度在整个图像中像素个数的占比,总和为1。记第i个灰度的直方图分布概率为p(i)。利用cumsum()函数
直方图.cumsum(),返回累积直方图数据
def cdf(img):img = cv2.imread(img,0)#flatten() 将数组变成一维hist,bins = np.histogram(img.flatten(),256,[0,256])#计算直方图#bins:每个区间的起始点和终点,(257,1)#hist:直方图(256.1)# 计算累积分布图print(hist)cdf = hist.cumsum()cdf_normalized = cdf * hist.max()/ cdf.max()#plt.plot(cdf_normalized, color = 'b')#绘制累积灰度级别曲线plt.hist(img.flatten(),256,[0,256], color = 'r')#绘制原始图像的直方图plt.xlim([0,256])plt.legend(('cdf','histogram'), loc = 'upper left')plt.show()
自定义
#第二步得到灰度级概率累积直方图sum_hist = np.zeros(hist.shape)#用于存放灰度级别概率的累和for i in range(256):sum_hist[i] = sum(hist[0:i+1])#将前i+1个灰度级别的出现概率总和赋值给sum_hist[i]
(3)取整扩展确定映射关系
每个Pk经过映射后的灰度级值
L表示图像处理的灰度级个数,因为此表处理的图像为3位,所以灰度级共2的3次方,8个灰度级,所以L=8 ,一般L=256
L-1 表示最大灰度级
0 表示最小灰度级
例 S(0) = int[((8-1)-0)*0.02+0.5] = 0
#第三步通过映射函数获得原图像灰度级与均衡后图像的灰度级的映射关系,这里创建映射后的灰度级别排序equal_hist = np.zeros(sum_hist.shape)for i in range(256):equal_hist[i] = int(((L-1)-0)*sum_hist[i]+0.5)
(4)根据映射关系计算均衡化直方图以及图像(这一步是关键)
计算后的灰度级替换掉计算前的灰度级,得到均衡化后的直方图
#第四步根据第三步的映射关系将灰度图每个像素点的灰度级别替换为映射后的灰度级别,这里是这样换的,equal_hist的索引号相当于原先的灰度级别排序,元素值则是映射后的灰度级别equal_img = img.copy()#用于存放均衡化后图像的灰度值for i in range(h):for j in range(w):equal_img[i,j] = equal_hist[img[i,j]]#计算得到均衡化后的直方图equal_hist = cv2.calcHist([equal_img],[0],None,[256],[0,255])equal_hist[0:255] = equal_hist[0:255] / (h * w) # 将直方图归一化,化为概率的形式
3、绘制未均衡和均衡后对应像素点像素值的改变
import cv2import numpy as npfrom matplotlib import pyplot as pltdef sys_equalizehist(img):'''利用系统自带的函数进行直方图均衡化:param img: 待处理图像:return: [equ_img,equ_hist],返回一个列表,第一个元素是均衡化后的图像,第二个是均衡了的直方图'''img = cv2.imread(img,0)h,w = img.shapeequ_img = cv2.equalizeHist(img)#得到直方图均衡化后的图像equ_hist = cv2.calcHist([equ_img],[0],None,[256],[0,255])#得到均衡化后的图像的灰度直方图equ_hist[0:255] = equ_hist[0:255] / (h * w) # 将直方图归一化,化为概率的形式# res = np.hstack((img,equ)) #stacking images side-by-side#这一行是将两个图像进行了行方向的叠加return [img,equ_img,equ_hist]#创建绘制原图像和均衡化后图像的对应灰度值变化曲线def equalWithOrignImg(gray_img,sys_img):''':param gray_img: 未均衡图:param sys_img: 均衡图:return:无返回值'''#将图像像素变成一维的gray_img = gray_img.ravel()sys_img = sys_img.ravel()#返回gray_img像素值从小到大的索引号,对其进行排序argOfGrayImg = np.argsort(gray_img)gray_img = sorted(gray_img)#根据索引号来取sys_img中的元素sys_img_sorted = []for i in argOfGrayImg:sys_img_sorted.append(sys_img[i])plt.plot(gray_img,sys_img_sorted)plt.show()if __name__ == '__main__':img = "E:\PYTHON\Image_Processing\colorful_lena.jpg"gray_img,sys_img,sys_hist = sys_equalizehist(img)equalWithOrignImg(gray_img,sys_img)
三、全局均衡化直方图
OpenCV 中的直方图均衡化函数为cv2.equalizeHist()
。这个函数的输入图片仅仅是一副灰度图像,输出结果是直方图均衡化之后的图像。对全局进行均衡化
1、系统自带函数
import cv2import numpy as npfrom matplotlib import pyplot as pltdef sys_equalizehist(img):'''利用系统自带的函数进行直方图均衡化:param img: 待处理图像:return: [equ_img,equ_hist],返回一个列表,第一个元素是均衡化后的图像,第二个是均衡了的直方图'''img = cv2.imread(img,0)h,w = img.shapeequ_img = cv2.equalizeHist(img)#得到直方图均衡化后的图像equ_hist = cv2.calcHist([equ_img],[0],None,[256],[0,255])#得到均衡化后的图像的灰度直方图equ_hist[0:255] = equ_hist[0:255] / (h * w) # 将直方图归一化,化为概率的形式# res = np.hstack((img,equ)) #stacking images side-by-side#这一行是将两个图像进行了行方向的叠加return [equ_img,equ_hist]
2、自定义函数
def def_equalizehist(img,L=256):'''根据均衡化原理自定义函数:param img: 待处理图像:param L: 灰度级别的个数:return: [equal_img,equal_hist]返回一个列表,第一个元素是均衡化后的图像,第二个是均衡了的直方图'''img = cv2.imread(img,0)#第一步获取图像的直方图h,w = img.shapehist = cv2.calcHist([img],[0],None,[256],[0,255])#这里返回的是次数hist[0:255] = hist[0:255]/(h*w)#将直方图归一化,化为概率的形式#第二步得到灰度级概率累积直方图sum_hist = np.zeros(hist.shape)#用于存放灰度级别概率的累和for i in range(256):sum_hist[i] = sum(hist[0:i+1])#将前i+1个灰度级别的出现概率总和赋值给sum_hist[i]#第三步通过映射函数获得原图像灰度级与均衡后图像的灰度级的映射关系,这里创建映射后的灰度级别排序equal_hist = np.zeros(sum_hist.shape)for i in range(256):equal_hist[i] = int(((L-1)-0)*sum_hist[i]+0.5)#第四步根据第三步的映射关系将灰度图每个像素点的灰度级别替换为映射后的灰度级别,这里是这样换的,equal_hist的索引号相当于原先的灰度级别排序,元素值则是映射后的灰度级别equal_img = img.copy()#用于存放均衡化后图像的灰度值for i in range(h):for j in range(w):equal_img[i,j] = equal_hist[img[i,j]]#计算得到均衡化后的直方图equal_hist = cv2.calcHist([equal_img],[0],None,[256],[0,255])equal_hist[0:255] = equal_hist[0:255] / (h * w) # 将直方图归一化,化为概率的形式return [equal_img,equal_hist]if __name__ == '__main__':img = "colorful_lena.jpg"sys_img,sys_hist = sys_equalizehist(img)def_img,def_hist = def_equalizehist(img)x = np.linspace(0,255,256)plt.subplot(1,2,1),plt.plot(x,sys_hist,'-b')plt.subplot(1,2,2),plt.plot(x,def_hist,'-r')plt.show()
3、结果展示
均衡化以前
均衡化以后
可见均衡化后的直方图比较密集了,且比较均匀,说明各个灰度级别出现的概率比较相近 ,且均衡化的图像比均衡化前的对比度大,亮的更亮,暗的更暗,色差大
四、限制对比度自适应直方图均衡(Contrast LimitedAdaptive histgram equalization/CLAHE)
1、限制对比度自适应直方图均衡的概念
有限对比适应性直方图均衡化我们在上边做的直方图均衡化会改变整个图像的对比度,但是在很多情况下,这样做的效果并不好。如下图:
的确在进行完直方图均衡化之后,图片背景的对比度被改变了。但是你再对比一下两幅图像中雕像的面图,由于太亮我们丢失了很多信息。造成这种结果的根本原因在于这幅图像的直方图并不是集中在某一个区域(试着画出它的直方图,你就明白了)。
为了解决这个问题,我们需要使用自适应的直方图均衡化。这种情况下,整幅图像会被分成很多小块,这些小块被称为“tiles”(在 OpenCV 中 tiles 的大小默认是 8x8),然后再对每一个小块分别进行直方图均衡化(跟前面类似)。
所以在每一个的区域中,直方图会集中在某一个小的区域中(除非有噪声干扰)。如果有噪声的话,噪声会被放大。为了避免这种情况的出现要使用对比度限制。对于每个小块来说,如果直方图中的 也就是灰度级别 超过对比度的上限的话,就把其中的像素点均匀分散到其他 bins 中,然后在进行直方图均衡化。最后,为了去除每一个小块之间“人造的”(由于算法造成)边界,再使用双线性差值,对小块进行缝合。
2、适用场景与优势
自适应直方图均衡化(AHE)用来提升图像的对比度的一种计算机图像处理技术。和普通的直方图均衡算法不同,AHE算法通过计算图像的局部直方图,然后重新分布亮度来来改变图像对比度。因此,该算法更适合于改进图像的局部对比度以及获得更多的图像细节。
3、原理及代码
原理比较复杂,可参考:/huangli19870217/article/details/45534397
def clahe(img,tileGridSize=8):'''限制对比度自适应直方图均衡:param img: 待测图像:param tileGridSize: 划分小区域的大小一般为8:return: 返回的是直方图均衡化后的图像'''img = cv2.imread(img, 0)clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(tileGridSize, tileGridSize))#先设置区域块tile的大小以及裁剪的限制cl1 = clahe.apply(img)#对图片进行自适应均衡化return cl1
这时候的图像对比度高,且不会模糊细节