OpenCV4图像处理--图像直方图

图像直方图统计显示、均衡化、相似性比较

图像直方图统计显示

  • 图像直方图概念
    在这里插入图片描述
    那么,对于我们的图像直方图统计来说,对于 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);
}

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值