OpenCV4学习笔记(10)——直方图均衡化及直方图比较

本次要记录的内容的是有关于图像直方图的一些操作:直方图均衡化、直方图比较。

  • 直方图均衡化
    直方图均衡化是将原图像通过某种变换,得到一幅灰度直方图为均匀分布的新图像的方法。对于一幅图像来说,它的直方图形状是取决于图像的灰度级和像素的数量关系,那么如果我们对图像的直方图进行操作,同样的就会反映到原图像中。
    每幅图像的直方图形状可能都有不同,如果直方图的峰集中在直方图的左侧,那么图像显示出来就是偏暗的,如果峰集中在直方图的右侧,那么图像显示出来就是偏亮的,但是只有在直方图的数据是真正的 “直方”的时候,也就是对于图像而已,每个灰度级具有的像素点数都是一样的,这时候图像的显示效果才称得上是很好的。然而这是理想状态,实际上是不可能达到这么均衡分布的像素点数的,我们只能通过一些处理手段来将图像的直方图尽可能的变得均衡化。图像直方图均衡化可以用于图像增强、对输入图像进行直方图均衡化处理,提升后续对象检测的准确率,医学影像图像与卫星遥感图像也经常通过直方图均衡化来提升图像质量。OpenCV中就提供了直方图均衡化的相关API,代码如下图:
	Mat image_equalizeHist;
	Mat image_equalizeHist_B;
	Mat image_equalizeHist_G;
	Mat image_equalizeHist_R;
	vector<Mat>bgr;
	split(image, bgr);
	//Mat image_gray;
	//cvtColor(image, image_gray, COLOR_BGR2GRAY);
	equalizeHist(bgr[0], image_equalizeHist_B);			//直方图均衡化只可以输入单通道图
	equalizeHist(bgr[1], image_equalizeHist_G);
	equalizeHist(bgr[2], image_equalizeHist_R);
	//将RGB图像分离成三张单通道图分别均衡化后再合并
	bgr[0] = image_equalizeHist_B.clone();
	bgr[1] = image_equalizeHist_G.clone();
	bgr[2] = image_equalizeHist_R.clone();
	merge(bgr, image_equalizeHist);
	imshow("image_equalizeHist", image_equalizeHist);
	//imshow("image_gray", image_gray);

主要的API为equalizeHist(),这个函数的作用就是将输入图像进行直方图均衡化操作后输出一幅新图像,要注意的是,这里的输入图像只可以输入单通道图像,所以我们对三通道图像进行直方图均衡化时,需要先将其分离成三幅单通道的图像,再分别进行处理,随后再将输出的三幅单通道图像合成起来,这才最终完成对三通道图像的直方图均衡化操作。如果是单通道的图像,就可以直接使用这个API来进行操作。实现效果如下图:
OpenCV4学习笔记(10)——直方图均衡化及直方图比较_第1张图片
OpenCV4学习笔记(10)——直方图均衡化及直方图比较_第2张图片
OpenCV4学习笔记(10)——直方图均衡化及直方图比较_第3张图片

通过对比可以很明显的看出来,直方图均衡化后的图像的清晰度、对比度、图像质感都有所提高,所以直方图均衡化可以作为一种不错的图像增强手段。

  • 直方图比较
    首先,图像和直方图是一种多对一的关系,也就是一幅确定的图像只能有一个直方图,而一个直方图可能会对应多幅图像,但是不同图像具有相同直方图的几率还是很小的。所以每一幅直方图都大致上对应了一幅图像,如果我们要对比两张图像的相似程度如何,就可以通过比较他们各自的直方图来得出对比结果。当然如果是对图像内容相似度进行对比的话,使用HSV图像来做直方图比较效果更好,因为HSV图像可以只对前两个通道H色调和S饱和度进行考虑,忽略亮度的影响。
    代码如下:

	Mat src;
	src = imread("D:\\opencv_c++\\opencv_tutorial\\data\\dataset\\train_img\\0\\cat.9.jpg");
	imshow("src", src);
	cvtColor(src, src, COLOR_BGR2HSV);

	Mat image_hsv;
	cvtColor(image, image_hsv, COLOR_BGR2HSV);
	int channels[2] = { 0,1 };				//内容相关性比较,仅对H,S两个通道进行比较,不考虑V通道
	Mat hist;
	Mat hist2;
	int dim = 2;
	int histSize[2] = { 180, 255 };
	float range_h[2] = { 0, 180 };
	float range_s[2] = { 0, 256 };
	const float *histRange[2] = { range_h, range_s };
	calcHist(&image_hsv, 1, channels, Mat(), hist, dim, histSize, histRange, true, false);
	calcHist(&src, 1, channels, Mat(), hist2, dim, histSize, histRange, true, false);
	//进行直方图比较前需要先进行归一化
	normalize(hist, hist, 0, 1, NORM_MINMAX, -1, Mat());
	normalize(hist2, hist2, 0, 1, NORM_MINMAX, -1, Mat());

	double compare1 = compareHist(hist, hist2, HISTCMP_CORREL);
	double compare2 = compareHist(hist, hist2, HISTCMP_CHISQR);
	double compare3= compareHist(hist, hist2, HISTCMP_BHATTACHARYYA);
	cout << "相关性比较" << compare1 << endl;
	cout << "卡方比较" << compare2 << endl;
	cout << "巴氏距离" << compare3 << endl;

同样计算出H和S通道的直方图,然后进行归一化,注意这一步很重要,因为不同通道的取值范围不一样,需要先归一化到[0, 1],然后就可以通过APIcompareHist()进行直方图比较。
compareHist()这个API需要三个参数,分别是:前两个参数是需要进行比较的两个图像直方图,第三个参数是进行直方图比较的方法,主要有三种可以选择的方法:
相关性比较(HISTCMP_CORREL)值越接近1,相关性越高;越接近0,相关性越低;
卡方比较(HISTCMP_CHISQR)值越小越接近,为0时相似度最高;
巴氏距离(HISTCMP_BHATTACHARYYA),完全匹配为 0,完全不匹配为1。

从比较效果上看,巴氏距离是效果最好的直方图相似度算法。下面是两张猫猫图的对比输出结果:

可能是这两只猫猫的毛色背景的差距太大了,所以放在一起比较的话输出结果就偏向于是不相似的,因为上面的比较是基于H和S两个通道的,不同颜色对对比结果的影响是比较大。

好的本次整理到此结束,下次再继续~

PS:本人的注释比较杂,既有自己的心得体会也有网上查阅资料时摘抄下的知识内容,所以如有雷同,纯属我向前辈学习的致敬,如果有前辈觉得我的笔记内容侵犯了您的知识产权,请和我联系,我会将涉及到的博文内容删除,谢谢!

你可能感兴趣的:(学习笔记,opencv,c++,计算机视觉)