下面的程序给出了如何绘制一幅图像整体的直方图和每个通道的直方图
#-*- coding:utf-8 -*-
import cv2
from matplotlib import pyplot as plt
def whole_hist(image):
'''
绘制整幅图像的直方图
'''
plt.hist(image.ravel(), 256, [0, 256]) #numpy的ravel函数功能是将多维数组降为一维数组
plt.show()
def channel_hist(image):
'''
画三通道图像的直方图
'''
color = ('b', 'g', 'r') #这里画笔颜色的值可以为大写或小写或只写首字母或大小写混合
for i , color in enumerate(color):
hist = cv2.calcHist([image], [i], None, [256], [0, 256]) #计算直方图
plt.plot(hist, color)
plt.xlim([0, 256])
plt.show()
image = cv2.imread('/home/liubo/tmp/sample/00001.jpg')
cv2.imshow('image', image)
cv2.waitKey(0)
whole_hist(image)
channel_hist(image)
可以明显看到这是一个直方图分布不是很均衡的图像,所以我们将尝试在下面进行直方图均衡化。
如果图像曝光过度或者曝光不足会导致计算机视觉相关算法表现的不够稳定,比如说一幅曝光过度的图像很有可能导致人脸识别算法的置信度降低甚至错误识别。直方图对于我们理解曝光有很大的帮助,以下三幅图在同一时间段拍摄于同一地方,分别是欠曝、准确曝光和过曝的效果,右下角为其对应的直方图[1][2]
直方图不管是向右“撞墙”还是向左“爬墙”了,只能说明高光像素量大,可能是过曝了,仅可用作参考,不能100%确定就是过曝。况且有时为了创意刻意而为之,这时的过曝是一种拍摄技法,可以起到烘托照片的气氛,或者起到纯化背景的作用,比如说下面这张图像
针对曝光过度或者曝光欠缺可以使用 gamma 变化的方法,具体可以参考文章《opencv-python 图像灰度变换》。除了这种方法还可以使用直方图均衡化的方法。
在现实的拍摄过程中,比如说视频监控领域,由于其图像的灰度分布集中在较窄的范围内,这就导致了图像的细节不够清晰。为什么不清晰呢,因为灰度分布较窄时,那么,在计算对比度的时候,对比度就很小,所以就不清晰。为了使得图像变得清晰,那么就需要使得灰度值的差别变大,为了使得灰度值的差别变大,就意味着灰度分布就变的较宽,使得灰度值分布变得均匀,在某个灰度级区间内,像素的个数分布大致相同,这样才能使得图像的对比度增强,细节变得清晰可见[3]。
在opencv 3 中的函数 cv2.equalizeHist(img)
可以将输入图像进行图像均衡化处理,但是需要注意的是输入图像必须是 8 位的单通道图像,返回图像也是一个 8 位的单通道图像,对于彩色图像必须逐一通道处理,如下所示
# 直方图均衡化
(b, g, r) = cv2.split(frame)
bH = cv2.equalizeHist(b)
gH = cv2.equalizeHist(g)
rH = cv2.equalizeHist(r)
frameH = cv2.merge((bH, gH, rH))
但是在实践中,对RGB 图像中的每个通道的图像单独应用直方图均衡不太可能给出美观的效果。一种可能比较好的方法是,将图像转换到 LAB 颜色空间,然后再将直方图均衡应用于亮度通道。
[1] 叶明 蜂鸟网 《教你如何判断一张照片的曝光是否完全准确》
[2] brucebruce 豆瓣 判定照片曝光过度的4个窍门!
[3]菲尔因惹火 CSDN 《直方图均衡化(Histogram equalization)与直方图规定化》