图像直方图统计显示
- 图像直方图概念
那么,对于我们的图像直方图统计来说,对于 RGB 彩色图,像素值的范围是0~255,那么像素等级就有256个等级,也就是bin的个数是256,当然bin的个数也可以根据需要进行设置,例如设置16个bin,那么每个bin的范围是0-15 - API :
calcHist
,可以进行单通道或者多通道图像进行直方图统计
CV_EXPORTS 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 );
- 统计并绘制直方图:对与 RGB 彩色图像我们通过通道分离,对每一个图像通道进行直方图统计,并绘制统计直方图,绘制通过直线实现,其中前后两个点分别是相邻两个bin
Mat src = imread("F:/code/images/yuan_test.png");
if (src.empty()) {
printf("fail to read");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
//通道分离
vector<Mat> mv;
split(src, mv);
//直方图计算
//设定像素取值范围
int histSize = 256;//像素等级数,也就是bin的个数
float range[] = { 0,255 };//需要统计的像素值范围
const float* histRanges = { range };
//三个通道分别计算直方图
Mat b_hist, g_hist, r_hist;//统计后输出的 Mat
calcHist(&mv[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRanges, true, false);
calcHist(&mv[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRanges, true, false);
calcHist(&mv[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRanges, true, false);
//创建直方图画布并归一化处理
Mat histImage = Mat::zeros(Size(600, 400), CV_8UC3);
int margin = 50;
int nm = histImage.rows - 2*margin;//像素直方图统计值显示的最大值
float bh = (float)(histImage.cols - 2*margin) / (float)histSize;//每个 bin 的宽度
normalize(b_hist, b_hist, 0, nm, NORM_MINMAX, -1, Mat());//使用最小值和最大值进行归一化处理,最小值是0,最大值是nm
normalize(g_hist, g_hist, 0, nm, NORM_MINMAX, -1, Mat());
normalize(r_hist, r_hist, 0, nm, NORM_MINMAX, -1, Mat());
//绘制前后两个统计点
for (int i = 0; i < histSize - 1; i++) {
line(histImage, Point( i * bh + margin, nm - b_hist.at<float>(i) + margin ),
Point((i + 2) * bh + margin, nm - b_hist.at<float>(i+1) + margin), Scalar(255,0,0), 1, LINE_AA);
line(histImage, Point(i * bh + margin, nm - g_hist.at<float>(i) + margin),
Point((i + 2) * bh + margin, nm - g_hist.at<float>(i + 1) + margin), Scalar(0, 255, 0), 1, LINE_AA);
line(histImage, Point(i * bh + margin, nm - r_hist.at<float>(i) + margin),
Point((i + 2) * bh + margin, nm - r_hist.at<float>(i + 1) + margin), Scalar(0, 0, 255), 1, LINE_AA);
}
namedWindow("histImage", WINDOW_AUTOSIZE);
imshow("histImage", histImage);
直方图均衡化
- 均衡化原理
直方图均衡化的基本原理是:对在图像中像素个数多的灰度值(即对画面起主要作用的灰度值)进行展宽,而对像素个数少的灰度值(即对画面不起主要作用的灰度值)进行归并,从而增大对比度,使图像清晰,达到增强的目的。
- 均衡化缺点
如果一幅图像整体偏暗或者偏亮,那么直方图均衡化的方法很适用。但直方图均衡化是一种全局处理方式,它对处理的数据不加选择,可能会增加背景干扰信息的对比度并且降低有用信号的对比度(如果图像某些区域对比度很好,而另一些区域对比度不好,那采用直方图均衡化就不一定适用)。此外,均衡化后图像的灰度级减少,某些细节将会消失;某些图像(如直方图有高峰),经过均衡化后对比度不自然的过分增强。针对直方图均衡化的缺点,已经有局部的直方图均衡化方法出现。 - API :
equalizeHist
CV_EXPORTS_W void equalizeHist( InputArray src, OutputArray dst );
PS: 此API只接受灰度图
- 图像均衡化处理并进行直方图统计显示:首先读取RGB彩色三通道图,然后通过
cvtColor
进行彩色图转灰度图,然后对灰度图进行均衡化,通过直方图可以看到灰度图gray和均衡化后的灰度图dst的差别
Mat src = imread("F:/code/images/aero1.jpg");
if (src.empty()) {
printf("fail to read");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
//直方图均衡化
Mat gray, dst;
cvtColor(src, gray, COLOR_BGR2GRAY);
imshow("gray", gray);
equalizeHist(gray, dst);//只能接受灰度图
imshow("eh-demo", dst);
//直方图计算
//设定像素取值范围
int histSize = 256;
float range[] = { 0,255 };
const float* histRanges = { range };
Mat gray_hist, dst_hist;
calcHist(&gray, 1, 0, Mat(), gray_hist, 1, &histSize, &histRanges, true, false);
calcHist(&dst, 1, 0, Mat(), dst_hist, 1, &histSize, &histRanges, true, false);
//创建直方图画布并归一化处理
Mat histImage = Mat::zeros(Size(600, 400), CV_8UC3);
int margin = 50;
int nm = histImage.rows - 2 * margin;
float bh = (float)(histImage.cols - 2 * margin) / (float)histSize;
normalize(gray_hist, gray_hist, 0, nm, NORM_MINMAX, -1, Mat());//使用最小值和最大值进行归一化处理,最小值是0,最大值是nm
normalize(dst_hist, dst_hist, 0, nm, NORM_MINMAX, -1, Mat());
//绘制前后两个统计点
for (int i = 0; i < histSize - 1; i++) {
line(histImage, Point(i * bh + margin, nm - gray_hist.at<float>(i) + margin),
Point((i + 2) * bh + margin, nm - gray_hist.at<float>(i + 1) + margin), Scalar(255, 0, 0), 1, LINE_AA);
line(histImage, Point(i * bh + margin, nm - dst_hist.at<float>(i) + margin),
Point((i + 2) * bh + margin, nm - dst_hist.at<float>(i + 1) + margin), Scalar(0, 255, 0), 1, LINE_AA);
}
imshow("histImage", histImage);
直方图相似性比较
- 比较方法
- API :
compareHist
CV_EXPORTS_W double compareHist( InputArray H1, InputArray H2, int method );
PS : 通过 method 选择需要进行比较的方法
- 通过读取两张RGB彩色图像,然后对每张图像进行三通道图像直方图统计,最后进行两张图像的直方图相似性比较,选择了相关性和巴氏距离分别进行比较
void hist_compare() {
Mat src1 = imread("F:/code/images/face_01.png");
Mat src2 = imread("F:/code/images/face_02.png");
imshow("src1", src1);
imshow("src2", src2);
//计算三通道直方图(不用通道分离,而设置多通道参数)
Mat hist1, hist2;
int histSize[] = { 256, 256, 256 };
int channels[] = { 0, 1, 2 };
float c1[] = { 0, 255 };
float c2[] = { 0, 255 };
float c3[] = { 0, 255 };
const float* histRanges[] = { c1, c2, c3 };
calcHist(&src1, 1, channels, Mat(), hist1, 3, histSize, histRanges, true, false);
calcHist(&src2, 1, channels, Mat(), hist2, 3, histSize, histRanges, true, false);
//归一化处理
normalize(hist1, hist1, 0, 1, NORM_MINMAX, -1, Mat());
normalize(hist2, hist2, 0, 1, NORM_MINMAX, -1, Mat());
//比较(巴氏距离)
double bs_h12 = compareHist(hist1, hist2, HISTCMP_BHATTACHARYYA);
double bs_h11 = compareHist(hist1, hist1, HISTCMP_BHATTACHARYYA);
printf("bs_h12:%.2f, bs_h11:%.2f\n", bs_h12, bs_h11);
//比较(相关性)
double co_h12 = compareHist(hist1, hist2, HISTCMP_CORREL);
double co_h11 = compareHist(hist1, hist1, HISTCMP_CORREL);
printf("co_h12:%.2f, co_h11:%.2f\n", co_h12, co_h11);
}