(本文所使用的 Python 库和版本号: Python 3.6, Numpy 1.14, scikit-learn 0.19, matplotlib 2.2 )
图像的直方图是指图像中每一像素范围内像素频率的统计关系图, 直方图能够给出图像灰度范围, 每个灰度的频度和灰度的分布, 整幅图的平均明暗, 对比度等概貌性描述. 灰度直方图是灰度级的函数, 反映的是图像中具有该灰度级像素的个数. 如果大部分像素都集中在低灰度区域, 图像会呈现暗的特性, 反之, 如果大部分图像都集中在高灰度区域, 图像呈现出亮的特性.
直方图均衡化是指, 将随机分布的图像直方图修改成均匀分布的直方图, 基本思想是对原始图像的像素灰度做某种映射变换, 使得变换后的图像灰度的概率密度呈均匀分布, 这就意味着图像灰度的动态范围得到扩大, 提高了图像的对比度.
1. 获取图像直方图
图像直方图有灰度直方图和彩色直方图的区别, 如果输入图像是灰度图, 则得到灰度直方图, 如果输入图像是 BGR 图像, 得到的则是某个颜色通道的直方图.
- # 获取灰度直方图
- gray_hist=cv2.calcHist([gray], [0], None, [256], [0, 256])
- plt.plot(gray_hist)
取得图像的灰度直方图, 只需要调用 cv2.calcHist()函数即可, 这个函数的参数为:
第一个参数为输入的图像, 可以是灰度图也可以是彩色图.
第二个参数是用于计算直方图的通道, 这里使用灰度图计算直方图, 所以就直接使用第一个通道;
第三个参数是 Mask, 这里没有使用, 所以用 None.
第四个参数是 histSize, 表示这个直方图分成多少份(即多少个直方柱).
第五个参数是表示直方图中各个像素的值,[0.0, 256.0]表示直方图能表示像素值从 0.0 到 256 的像素.
最后是两个可选参数, 由于直方图作为函数结果返回, 所以第六个 hist 就没有意义了(待确定)
最后一个 accumulate 是一个布尔值, 用来表示直方图是否叠加.
- # 获取彩色图的各个通道直方图
- hist_B=cv2.calcHist([img],[0],None,[256],[0,256])
- plt.plot(hist_B,'b',label='B') # Blue color
- hist_G=cv2.calcHist([img],[1],None,[256],[0,256])
- plt.plot(hist_G,'g',label='G') # green color
- hist_R=cv2.calcHist([img],[2],None,[256],[0,256])
- plt.plot(hist_R,'r',label='R')# red color
- plt.title('histogram of Color Chanel')
- plt.legend()
2. 直方图均衡化
2.1 灰度图的直方图均衡化
为了方便对比, 我将直方图均衡化前后的图像都绘制到同一个图片中. 如下:
- # 灰度图的直方图均衡化:
- # 先显示均衡化前后的图像
- plt.figure(12,figsize=(15,30))
- plt.subplot(121)
- plt.imshow(gray,cmap='gray')
- plt.title('GrayImg before Equalization')
- equalize = cv2.equalizeHist(gray)
- plt.subplot(122)
- plt.imshow(equalize,cmap='gray')
- plt.title('GrayImg after Equalization')
- plt.plot(gray_hist,c='b',label='raw_Hist')
- gray_equalized_hist=cv2.calcHist([equalize], [0], None, [256], [0, 256])
- plt.plot(gray_equalized_hist,c='r',label='Equalized')
- plt.legend()
- plt.title('Histogram comparison')
话说, 经过直方图均衡化之后的直方图怎么长的这么丑?
直方图均衡化只需要一个函数 cv2.equalizeHist()即可, 但是需要注意: cv2.equalizeHist()只提供灰度值图片的处理, 当把上面的图片换成 RGB 图片时, 就会报错了.
2.2 彩色图的直方图均衡化
彩色图的直方图均衡化需要借助 YUV 空间, 如下代码:
- # 彩色直方图均衡化需要借助 YUV 空间
- img_yuv = cv2.cvtColor(img, cv2.COLOR_BGR2YUV)
- img_yuv[:,:,0] = cv2.equalizeHist(img_yuv[:,:,0])
- img_histeq = cv2.cvtColor(img_yuv, cv2.COLOR_YUV2BGR)
- # 显示均衡化前后的图像
- plt.figure(12,figsize=(15,30))
- plt.subplot(121)
- img_rgb=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
- plt.imshow(img_rgb)
- plt.title('ColorImg before Equalization')
- plt.subplot(122)
- img_hist_rgb=cv2.cvtColor(img_histeq,cv2.COLOR_BGR2RGB)
- plt.imshow(img_hist_rgb)
- plt.title('ColorImg after Equalization')
- # 显示均衡化前后的直方图情况
- plt.figure(12)
- plt.subplot(121)
- hist_B=cv2.calcHist([img],[0],None,[256],[0,256])
- plt.plot(hist_B,'b',label='B') # Blue color
- hist_G=cv2.calcHist([img],[1],None,[256],[0,256])
- plt.plot(hist_G,'g',label='G') # green color
- hist_R=cv2.calcHist([img],[2],None,[256],[0,256])
- plt.plot(hist_R,'r',label='R')# red color
- plt.title('Color Histogram before Equalization')
- plt.legend()
- plt.subplot(122)
- hist_B=cv2.calcHist([img_histeq],[0],None,[256],[0,256])
- plt.plot(hist_B,'b',label='B') # Blue color
- hist_G=cv2.calcHist([img_histeq],[1],None,[256],[0,256])
- plt.plot(hist_G,'g',label='G') # green color
- hist_R=cv2.calcHist([img_histeq],[2],None,[256],[0,256])
- plt.plot(hist_R,'r',label='R')# red color
- plt.title('Color Histogram after Equalization')
- plt.legend()
同样的, 经过对比可以看出, 经过直方图均衡化之后的图像直方图都比较丑....
######################## 小 ********** 结 ###############################
1, 对于图像直方图进行操作可以比较明显的改变图像的对比度和明暗度.
2, 使用 cv2.equalizeHist 函数可以直接改变灰度图的直方图, 但是却不能直接改变彩色图的直方图, 对于彩色图如果想要均衡化, 需要先转变到 YUV 空间再进行转换.
#################################################################
注: 本部分代码已经全部上传到 (我的 GitHub https://github.com/RayDean/MachineLearning ) 上, 欢迎下载.
参考资料:
1, Python 机器学习经典实例, Prateek Joshi 著, 陶俊杰, 陈小莉译
来源: https://juejin.im/post/5bcd733ce51d457a944b563e