直方图
以下主要涉及颜色直方图的概念和计算
最开始学习数字图像处理的时候就接触到了直方图的概念,也记录过OpenCV 1.x/2.x的直方图实现代码
颜色/纹理等特征通过直方图的形式能够有效的作用于图像检测/识别算法,所以打算再整理一下相关的概念和实现。参考:
头文件地址:
/path/to/opencv-4.0.1/modules/imgproc/include/opencv2/imgproc.hpp源文件地址:
/path/to/opencv-4.0.1/modules/imgproc/src/histogram.cpp
内容列表
- 什么是直方图?
- 直方图计算
- 直方图均衡
- 直方图比较
什么是直方图?
- 直方图(
histogram)统计不同强度下的像素数目。直方图的最小单位是bin(箱) - 强度通常指像素颜色值(颜色直方图)。但并不将其限制为颜色强度值,可以是任何对描述图像有用的特征,比如纹理特征(纹理直方图)
颜色直方图示例
假设图像及其像素灰度值大小如下:

灰度值的取值范围在[0, 255],每15个强度值划为一组,共得到16个子块
\[ [0,255]=[0,15]∪[16,31]∪....∪[240,255] \]
\[ range=bin_{1} ∪ bin_{2} ∪ .... ∪ bin_{n}=15 \]
统计每个子块中的像素个数,得到的就是颜色直方图。图形化显示如下(x轴表示bin,y轴表示像素个数)

关键参数
直方图有3个关键参数:
dims:要收集数据的参数数量。在上式灰度图像中,仅收集每个像素的强度值(灰度值),所以dims=1bins:每个dim中根据强度级别划分的子块数。上式中,灰度值取值范围在[0,255],每15个强度值划为一组,共得到16个bin-bins=16range:要测量的值的取值范围。上式中,要测量灰度值,取值为[0,255]
直方图的作用
- 它表示了图像强度分布
- 它量化了每个强度值的像素数
所以使用直方图能够统计数据的全局信息
直方图计算
实现步骤如下:
- 加载图像
- 分离彩色图像到
R/G/B通道 - 计算每个通道的颜色直方图
- 在同一图上绘制
3个颜色直方图
OpenCV提供了cv::calcHist用于直方图计算
1 | CV_EXPORTS void calcHist( const Mat* images, int nimages, |
images:原图数组。应该具有相同的深度(CV_8U、CV_16U或CV_32F)以及相同的尺寸。每个图像可以有任意数量的通道nimages:图像个数channels:用于计算直方图的dims通道列表。第一个列表值表示计算第一张图像的前几个通道;第二个列表值表示计算第二张图像的前几个通道,最后累加到一起得到直方图mask:可选。如果矩阵不是空的,它必须是一个8位数组,大小与images[i]相同。非零掩码元素标记会被直方图计数的数组元素(比如仅计算图像中某一区域的直方图)hist:输出直方图dims:直方图维数,必须是正数,不大于CV_MAX_DIMS(当前取值为32)histSize:每个维度的直方图大小数组ranges:每个图像的取值范围uniform:默认为true,表示每张图片计算的直方图是否一致accumulate:累积标志。如果已设置,直方图在分配时不会在开始时被清除。此功能使您能够从几组数组中计算出一个直方图,或者及时更新直方图
示例如下:
1 |
|
直方图均衡
参考:
直方图均衡通过扩展像素取值范围,能够提高图像对比度
均衡意味着将一个分布(给定直方图)映射到另一个分布(更宽和更均匀的分布),以便强度值分布在整个范围内
操作步骤
第一步:统计灰度直方图
第二步:计算每一级灰度的概率
\[ p_{x}(i) = p(x=i) = \frac {n_{i}}{n}, 0\leq i < L \]
其中\(L\)表示灰度级数(通常为\(256\)),\(n\)表示图像像素个数,\(p_{x}(i)\)表示直方图中像素值为\(i\)的概率
第三步:计算累积分布函数cdf(cumulative distribution function)
\[ cdf_{x}(i) = \sum_{j=0}^{i}p_{x}(j) \]
第四步:求取映射像素值
\[ s_{i} = T(r_{i}) = round((L-1)*cdf_{x}(i) + 0.5) \]
- 函数\(T\)表示映射函数
- 函数\(round\)表示去除小数部分取整数
- \((L-1)*cdf_{x}(i)\)表示将像素值扩展回原先的级数
经过第四步计算完成后就能够得到直方图均衡后的结果
OpenCV使用
OpenCV提供了函数equalizeHist()进行直方图均衡化的操作
1 | CV_EXPORTS_W void equalizeHist( InputArray src, OutputArray dst ); |
参数src是一个8位单通道图像,输出dst得到和原图同样大小和类型的结果
1 | ... |
直方图比较
直方图比较的目的是计算两个直方图的匹配程度
OpenCV提供了四种比较方式
CorrelationChi-SquareIntersection(直方图相交)Bhattacharyya distance
直方图相交
计算公式如下:
\[ d(H_{1}, H_{2}) = \sum_{I} \min (H_{1}(I), H_{2}(I)) \]
\(H_{1}\)和\(H_{2}\)是两个直方图
操作步骤
参考:颜色直方图,HSV直方图
- 加载两张比较图像
- 转换成
HSV格式,计算H-S直方图 - 使用直方图比较方式进行计算
- 输出匹配数值
将图像转换成HSV格式后再进行直方图比较,更能够符合人眼对颜色相似性的主观判断
OpenCV示例
1 | ... |
手动实现直方图计算
直方图计算主要涉及cv::calcHist和cv::normalize的使用。完整代码如下
1 | // |

