C++ opencv二维直方图

1.二维直方图概念


opencv知识点:

计算直方图数据 - calcHist
四舍五入浮点数 - cvRound
寻找最小/最大值 - minMaxLoc
本课所解决的问题:

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

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

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

H(色调)范围是[0,180]
S(饱和度)范围是[0,255]
V(明度)范围是[0,255]
 

  • calcHist
  • cvRound
  • minMaxLoc
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
	将浮点数四舍五入到最近的整数
		共1个参数
			第1个参数 要处理的浮点数
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;
}

二维直方图

//函数实现
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(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);

}

你可能感兴趣的:(C++,opencv,开发语言,c++,opencv,计算机视觉,人工智能)