直方图
以下主要涉及颜色直方图的概念和计算
最开始学习数字图像处理的时候就接触到了直方图的概念,也记录过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=1
bins
:每个dim
中根据强度级别划分的子块数。上式中,灰度值取值范围在[0,255]
,每15
个强度值划为一组,共得到16
个bin
-bins=16
range
:要测量的值的取值范围。上式中,要测量灰度值,取值为[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 | #include "opencv2/highgui.hpp" |
直方图均衡
参考:
直方图均衡通过扩展像素取值范围,能够提高图像对比度
均衡意味着将一个分布(给定直方图)映射到另一个分布(更宽和更均匀的分布),以便强度值分布在整个范围内
操作步骤
第一步:统计灰度直方图
第二步:计算每一级灰度的概率
\[ 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
提供了四种比较方式
Correlation
Chi-Square
Intersection
(直方图相交)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 | // |