一、直方图概述
在统计学中,直方图是一种对数据分布情况的图形表示,是一种二维统计图表,他的两个坐标分别是统计样本(图像、视频帧)和样本的某种属性(亮度,像素值,梯度,方向,色彩等等任何特征)。
也可以这么理解,直方图是对数据的统计,并把统计值显示到事先设定好的bin(矩形条)中,bin中的数值是从数据中计算出的特征的统计量。总之,直方图获取的是数据分布的统计图,通常直方图的维数要低于原始数据。
图像直方图是用一表示数字图像中亮度分布的直方图,标绘了图像中每个亮度值的像素数。可以借助观察该直方图了解需要如何调整亮度分布的直方图。这种直方图中,横坐标的左侧为纯黑、较暗的区域,而右侧为较亮、纯白的区域。因此,一张较暗图片的图像直方图中的数据多集中于左侧和中间部分,而整体明亮、只有少量阴影的图像则相反。计算机视觉邻域常借助图像直方图来实现图像的二值化。
灰度直方图是一幅图像中个像素灰度值出现次数或频数的统计结果,它只反映该图像中灰度值出现的频率,而未反映某一灰度值像素所在的位置。也就是说,它只包含了该图像中某个灰度值的像素出现的概率,而丢失了其所在的位置的信息。任一幅图像,都能唯一地算出一幅与它对应的直方图。但不同的图像,可能有相同的直方图。即图像与直方图之间是多对一的映射关系。
直方图意义:
1.直方图是图像中像素强度分布的图形表达方式。
2.直方图统计了每一个强度值所具有的像素个数。
直方图术语:
dims:需要统计的特征的数目。例如:dims=1,表示我们仅统计灰度值。
bins:每个特征空间子区段的数目。
range:每个特征空间的取值范围。
二、直方图均衡化
直方图均衡化是通过拉伸像素强度的分布范围,使得在0~255灰阶上的分布更加均衡,提高了图像的对比度,达到改善图像主观视觉效果的目的。对比度较低的图像适合使用直方图均衡化方法来增强图像细节。
函数原型:
参数:
src:源图像,需为8位单通道图像
dst:输出图像,尺寸、类型和源图像一致
该函数采用如下步骤对输入图像进行直方图均衡化:
效果:
#define HIST_SIZE 256//计算直方图数据的函数static Mat cal_histogram(const Mat& src){
int hist[HIST_SIZE] = {
0}; //遍历图像,对直方图对应的格子累加计算 for (int i = 0; i < src.rows; i++) {
for (int j = 0; j < src.cols; j++) {
int idx = src.ptr(i)[j]; if (idx < HIST_SIZE) {
hist[idx]++; } } } //把直方图数据从数组转换成只有一列的矩阵 Mat histMat(HIST_SIZE, 1, CV_32FC1); for (int i = 0; i < HIST_SIZE; i++) {
histMat.ptr<float>(i)[0] = hist[i]; } return histMat;}//定义函数把直方图以图像形式显示static void show_histogram(const Mat& src, String winName){
//先调用计算直方图的函数得到直方图数据,并归一化到0-255 Mat hist = cal_histogram(src); normalize(hist, hist, 0, 255, NORM_MINMAX, CV_8UC1); //定义用于显示的图像 Mat hist2 = Mat(300, 256, CV_8UC1, Scalar(0)); //遍历直方图,一个格子的数据画一条竖线 for (int i = 0; i < HIST_SIZE; i++) {
//从左到右,高度相反画图线 line(hist2, Point(i, 299), Point(i, 299 - hist.at(i)), Scalar(255), 1, LINE_AA); } imshow(winName, hist2);}
均衡化前后强度对比:
均衡化前,像素强度分布相对集中,均衡化后,分布相对散开一点,对比度就改善了。
如果图像是彩色图像,则先分离通道,分别做均衡化,再合并通道。
vectorchannels;split(src, channels);Mat blue, green, red;blue = channels.at(0);green = channels.at(1);red = channels.at(2);equalizeHist(blue, blue);equalizeHist(green, green);equalizeHist(red, red);merge(channels, dst);
效果:
具体实现:
static Mat histogram_equalize(Mat& src){
//第一步,计算直方图数据 Mat hist = cal_histogram(src); //第二步,计算累积直方图,同时进行第三步,把累积直方图的数据归一化到0-255 int hist_accumulate[HIST_SIZE]; int sum = 0; int total_number_pixels = src.cols * src.rows; for (int i = 0; i < HIST_SIZE; i++) {
sum += (int)hist.ptr<float>(i)[0]; hist_accumulate[i] = saturate_cast(sum * 255 / total_number_pixels); } //第四步,遍历原图像,以原图像的像素值为索引,从第三步的归一化后的直方图中取值组成最终均衡化图像 Mat dst(src.size(), CV_8UC1); for (int i = 0; i < dst.rows; i++) {
for (int j = 0; j < dst.cols; j++) {
dst.ptr(i)[j] = hist_accumulate[src.ptr(i)[j]]; } } return dst;}
效果: