25 二维直方图

25 二维直方图

opencv知识点:

  • 计算直方图数据 - calcHist
  • 四舍五入浮点数 - cvRound
  • 寻找最小/最大值 - minMaxLoc

本课所解决的问题:

  • 如何绘制HSV图像的二维直方图?

1.二维直方图

上节课中,我们学习了一维直方图的绘制,那我们该如何绘制二维直方图呢?

关于二维直方图的绘制,我们通常选择HSV模式下的图像

我们回顾HSV的知识,可以发现

  • H(色调)范围是[0,180]

  • S(饱和度)范围是[0,255]

  • V(明度)范围是[0,255]

即HS两个通道就可以表示颜色,非常方便二维直方图的绘制

opencv中,如果我们想绘制二维维直方图,要用到三个API

  • calcHist
  • cvRound
  • minMaxLoc

介绍如下

calcHist

calcHist
	计算一维数组的直方图(输入图像可以有多通道)
		共10个参数
			第1个参数 图像数组
			第2个参数 输入图像数量
			第3个参数 通道数组
			第4个参数 可选mask
			
			第5个参数 输出直方图数据(值与对应频次)的n维数组
			第6个参数 直方图维数

					当通道为1个时,我们选择维度为1维,此时直方图数据就为一维数组
					当维度为2个时,我们选择维度为2维,此时直方图数据就为二维数组
					………………
					最大支持32维
					
					也就是说,n张图像 每张图像m个通道 可以计算出相应的直方图数据
					
					但对于绘制来说,一般都只绘制到2维,3维及以上就很复杂了

			第7个参数 histSize( bins数组,x轴长度)
			第8个参数 ranges(取值范围数组)
			
			//以下参数暂时用不到
			第9个参数 指示直方图bin间隔是否一致
						默认为true,即等间隔取值
						如果为false,则range不能写{0,255}这种,就要写{1,1,……,1}这种
								
			第10个参数 累计标志(默认为false)
				    	当多张图像的时候,
				    		如果为true,则绘制直每张方图的时候,不会从头清空
				    		会在前者直方图的基础上继续

cvRound

cvRound
	将浮点数四舍五入到最近的整数
		共1个参数
			第1个参数 要处理的浮点数

minMaxLoc

minMaxLoc
	寻找最小/最大值
		共5个参数 
			第1个参数 输入
			第2个参数 输出的最小值
			第3个参数 输出的最大值
			第4个参数 最小值下标
			第5个参数 最大值下标

2.绘制二维直方图

本课中计算的直方图维数为2维,采取方式为

  • 先转换色彩空间为HSV
  • 然后进行每个通道的直方图数据计算,得到二维数组
  • 最后利用直方图二维数组绘制直方图

我们先来输出一下得到的直方图数据

//函数定义
void histogram_2d_demo(Mat& image);

//函数实现
void QuickDemo::histogram_2d_demo(Mat& image) {
	
	// 2D 直方图
	Mat hsv, hs_hist;
	cvtColor(image, hsv, COLOR_BGR2HSV);

	int hbins = 30;
	int sbins = 32;
	int hist_bins[] = { hbins, sbins };
	
	float h_range[] = { 0, 180 };
	float s_range[] = { 0, 256 };
	const float* hs_ranges[] = { h_range, s_range };
	
	int hs_channels[] = { 0, 1 };
	
	calcHist(&hsv, 1, hs_channels, Mat(), hs_hist, 2, hist_bins, hs_ranges);

	std::cout << hs_hist;
}

可以看见,不同于上一课的256 * 1的列矩阵,这里变成了30 * 32的二维矩阵

465a41698861441ebe8a8a89549f3193

接下来,我们开始绘制二维直方图

//函数实现
void QuickDemo::histogram_2d_demo(Mat& image) {
	
	// 2D 直方图
	Mat hsv, hs_hist;
	cvtColor(image, hsv, COLOR_BGR2HSV);


	int hbins = 30;
	int sbins = 32;
	int hist_bins[] = { hbins, sbins };
	
	float h_range[] = { 0, 180 };
	float s_range[] = { 0, 256 };
	const float* hs_ranges[] = { h_range, s_range };
	
	int hs_channels[] = { 0, 1 };
	
	calcHist(&hsv, 1, hs_channels, Mat(), hs_hist, 2, hist_bins, hs_ranges);

	std::cout << hs_hist;

	double maxVal = 0;//寻找直方图数据中的最大值
	minMaxLoc(hs_hist, 0, &maxVal, 0, 0);


	int scale = 10;
	//行320 列300
	Mat hist2d_image = Mat::zeros(sbins * scale, hbins * scale, CV_8UC3);

	//h30行,s32列,一行一行的绘制矩形
	for (int h = 0; h < hbins; h++) {
		for (int s = 0; s < sbins; s++)
		{
			float binVal = hs_hist.at<float>(h, s);//位于横h,列s处的频次

			int intensity = cvRound(binVal * 255 / maxVal);//白色的强度,频次越大,小矩形越接近白色

			Point p1(h * scale, s * scale);
			/*
				矩形左上角的点
			*/
			Point p2((h + 1) * scale - 1, (s + 1) * scale - 1);
			/*
				矩形右下角的点
				-1只是为了不与其他矩形的左上角重合,不-1差异也不大
			*/

			rectangle(hist2d_image, p1, p2, Scalar::all(intensity), -1);
		}
	}

	//灰色的图像不容看出差异,这里我们转换色彩风格
	applyColorMap(hist2d_image, hist2d_image,COLORMAP_DEEPGREEN);

	imshow("H-S Histogram", hist2d_image);

}

cb0cfdba4d364e7d9bb53283bdb71570

本课所用API查阅

calcHist

cvRound

minMaxLoc

posted @ 2023-01-15 10:16  L707  阅读(226)  评论(0编辑  收藏  举报