如果一个图像的直方图都集中在一个区域,则整体图像的对比度比较小,不便于图像中纹理的识别。例如相邻的两个像素灰度值如果分别是120和121,仅凭肉眼是如法区别出来的。同时,如果图像中所有的像素灰度值都集中在100到150之间,则整个图像想会给人一种模糊的感觉,看不清图中的内容。如果通过映射关系,将图像中灰度值的范围扩大,增加原来两个灰度值之间的差值,就可以提高图像的对比度,进而将图像中的纹理突出显现出来,这个过程称为图像直方图均衡化。
在OpenCV 4中提供了equalizeHist()函数用于将图像的直方图均衡化,该函数的函数原型在代码清单4-7中给出。
void cv::equalizeHist(InputArray src,OutputArray dst)
- src:需要直方图均衡化的CV_8UC1图像。
- dst:直方图均衡化后的输出图像,与src具有相同尺寸和数据类型。
该函数形式比较简单,但是需要注意该函数只能对单通道的灰度图进行直方图均衡化。对图像的均衡化示例程序在代码清单4-8中给出,程序中我们将一张图像灰度值偏暗的图像进行均衡化,通过结果可以发现经过均衡化后的图像对比度明显增加,可以看清楚原来看不清的纹理。通过绘制原图和均衡化后的图像的直方图可以发现,经过均衡化后的图像直方图分布更加均匀。
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace std;
void drawHist(Mat&hist,int type,string name){
//归一化并回执直方图函数
int hist_w=512;
int hist_h=400;
int width=2;
Mat histImage=Mat::zeros(hist_h,hist_w,CV_8UC3);
normalize(hist,hist,1,0,type,-1,Mat());
for(int i=1;i<=hist.rows;++i){
rectangle(histImage,Point(width*(i-1),hist_h-1),
Point(width*i-1,hist_h-cvRound(hist_h*hist.at<float>(i-1))-1),
Scalar(255,255,255),-1);
}
imshow(name,histImage);
}
int main(){
Mat img=imread("gearwheel.jpg");
if(img.empty()){
cout<<"请确认输入的图片路径是否正确"<<endl;
return -1;
}
Mat gray,hist,hist2;
cvtColor(img,gray,COLOR_BGR2GRAY);
Mat equalImg;
equalizeHist(gray,equalImg);//将图像直方图均衡化
const int channels[1]={
0};
float inRanges[2]={
0,255};
const float*ranges[1]={
inRanges};
const int bins[1]={
256};
calcHist(&gray,1,channels,Mat(),hist,1,bins,ranges);
calcHist(&equalImg,1,channels,Mat(),hist2,1,bins,ranges);
drawHist(hist,NORM_INF,"hist");
drawHist(hist2,NORM_INF,"hist2");
imshow("原图",gray);
imshow("均衡化后的图像",equalImg);
waitKey(0);
return 0;
}