本文主要介绍了灰度直方图相关的处理,包括以下几个方面的内容:
- 利用OpenCV计算图像的灰度直方图,并绘制直方图曲线
- 直方图均衡化的原理及实现
- 直方图规定化(匹配)的原理及实现
图像的灰度直方图
一幅图像由不同灰度值的像素组成,图像中灰度的分布情况是该图像的一个重要特征。图像的灰度直方图就描述了图像中灰度分布情况,能够很直观的展示出图像中各个灰度级所占的多少。
图像的灰度直方图是灰度级的函数,描述的是图像中具有该灰度级的像素的个数:其中,横坐标是灰度级,纵坐标是该灰度级出现的频率。
![c0a810b4f22af6aad1f85575273399ae.png](https://i-blog.csdnimg.cn/blog_migrate/b9d9cb3376c7a07cf87a093308223a49.jpeg)
不过通常会将纵坐标归一化到[0,1]区间内,也就是将灰度级出现的频率(像素个数)除以图像中像素的总数。灰度直方图的计算公式如下:
![911e6b9a0f0d6845fb8717bdfbc90d98.png](https://i-blog.csdnimg.cn/blog_migrate/94e46816c538d0008984c8c7ed170367.jpeg)
其中,rk是像素的灰度级,nk是具有灰度rk的像素的个数,MN是图像中总的像素个数。
OpenCV灰度直方图的计算
直方图的计算是很简单的,无非是遍历图像的像素,统计每个灰度级的个数。在OpenCV中封装了直方图的计算函数calcHist,为了更为通用该函数的参数有些复杂,其声明如下:
void calcHist( const Mat* images, int nimages, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float** ranges, bool uniform = true, bool accumulate = false );
该函数能够同时计算多个图像,多个通道,不同灰度范围的灰度直方图. 其参数如下
- images,输入图像的数组,这些图像要有相同大大小,相同的深度(CV_8U CV_16U CV_32F).
- nimages ,输入图像的个数
- mask,可选的掩码,不使用时可设为空。要和输入图像具有相同的大小,在进行直方图计算的时候,只会统计该掩码不为0的对应像素
- hist,输出的直方图
- dims,直方图的维度
- histSize,直方图每个维度的大小
- ranges,直方图每个维度要统计的灰度级的范围
- uniform,是否进行归一化,默认为true
- accumulate,累积标志,默认值为false。
为了计算的灵活性和通用性,OpenCV的灰度直方图提供了较多的参数,但对于只是简单的计算一幅灰度图的直方图的话,又显得较为累赘。这里对calcHist进行一次封装,能够方便的得到一幅灰度图直方图。
class Histogram1D{private: int histSize[1]; // 项的数量 float hranges[2]; // 统计像素的最大值和最小值 const float* ranges[1]; int channels[1]; // 仅计算一个通道public: Histogram1D() { // 准备1D直方图的参数 histSize[0] = 256; hranges[0] = 0.0f; hranges[1] = 255.0f; ranges[0] = hranges; channels[0] = 0; } MatND getHistogram(const Mat &image) { MatND hist; // 计算直方图 calcHist(&image ,// 要计算图像的 1, // 只计算一幅图像的直方图 channels,