OpenCV - 灰度直方图绘制

以下为借鉴的图像直方图的绘制方法,做此纪录: 

参考:https://blog.csdn.net/sinat_36264666/article/details/78754897

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 );
/*
参数1:输入源图像。注意这里的格式是const Mat*,也就是说,你要传入一个地址,输入的数组(图片)或者数组集(一堆图片)需要为相同的深度(CV_8U或CV_32F)和相同的尺寸。
参数2:int类型的nimages,输入数组的个数,也就是第一个参数中存放了多少张“图像”,有几个原数组。
参数3:const int*类型的channels,用来计算直方图的channes的数组,需要统计的通道(dim)索引。第一个数组通道从0到images[0].channels()-1,而第二个数组通道从images[0]计算到images[0].channels()+images[1].channels()-1,以此类推。比如输入是2副图像,第一副图像有0,1,2共三个channel,第二幅图像只有0一个channel,那么输入就一共有4个channes,如果int channels[3] = {3, 2, 0},那么就表示是使用第二副图像的第一个通道和第一副图像的第2和第0个通道来计算直方图。(这句表示没看懂)。
参数4:InputArray类型的mask,可选的操作掩码。如果此掩码不为空,那么它必须为8位(CV_8U)的数组,并且与images[i]有同样大小的尺寸,值为1的点将用来计算直方图。这里的非零掩码元素用于标记出统计直方图的数组元素数据。
参数5:OutputArray类型的hist,输出的计算出来的直方图,一个二维数组。
参数6:int类型dims,需要计算的直方图的维度,必须是正数,且不大于CV_MAX_DIMS。(32)
参数7:const int*类型的histSize,存放每个维度的直方图尺寸的数组。简单把直方图看作一个一个的竖条的话,就是每一维上竖条的个数。
参数8:const float**类型的ranges,表示每一个维度数组(第6个参数dims)的每一维的边界阵列,可以理解为每一维数值的取值范围。比如 float rang1[] = {0, 20};float rang2[] = {30, 40};  const float*rangs[] = {rang1, rang2};那么就是对0,20和30,40范围的值进行统计。
参数9:bool类型的uniform,表示直方图是否均匀的标识符,即每一个竖条的宽度是否相等。有默认值true。
参数10:bool类型的accumulate,累计标识符,有默认值false。若其为true,直方图在配置阶段不会被清零。此功能主要是允许从多个阵列中计算单个直方图,或者用于在特定的时间更新直方图。
*/
//功能:查找全局最小和最大数组元素并返回它们的值和它们的位置。
void minMaxLoc(InputArray src, CV_OUT double* minVal,
                           CV_OUT double* maxVal=0, CV_OUT Point* minLoc=0,
                           CV_OUT Point* maxLoc=0, InputArray mask=noArray());

//功能:缩放和移位数组元素,以便指定的标准(alpha)或最小(alpha)和最大(beta)数组值获得指定的值。
void normalize( InputArray src, OutputArray dst, double alpha=1, double beta=0,
                             int norm_type=NORM_L2, int dtype=-1, InputArray mask=noArray());

1、灰度直方图的绘制 

        cv::Mat src = cv::imread("lena.png", 0);
	cv::imshow("src", src);

	//------------【2】定义直方图参数并计算直方图------------
	//1--计算的图像的通道,就是需要计算图像的哪个通道(BGR空间需要确定计算 B或G或R空间)
	const int channels[] = { 0 };
	//2--配置输出的结果存储的 空间 ,用MatND类型来存储结果
	MatND hist;
	//3--设置计算直方图的维度
	int dims = 1;
	//4--直方图的每一个维度的柱条的数目(就是将数值分组,共有多少组)
	const int histSize[] = { 256 }; //如果这里写成int histSize = 256;   那么下面调用计算直方图的calcHist()函数的时候,该变量需要写 &histSize
	//5--最后是确定每个维度的取值范围,就是横坐标的总数	
	float pranges[] = { 0, 255 };//首先得定义一个变量用来存储单个维度的数值的取值范围
	const float* ranges[] = { pranges };
	//6--计算直方图
	calcHist(&src, 1, channels, Mat(), hist, dims, histSize, ranges, true, false);

	//------------【3】绘制直方图------------
	//*********绘制直方图(绘制方式一)*********
	int scale = 2;
	int hist_height = 256;
	Mat hist_img = Mat::zeros(hist_height, 256 * scale, CV_8UC3); //创建一个黑底的图像,为了可以显示彩色,所以该绘制图像是一个8位的3通道图像
	//因为任何一个图像的某个像素的总个数,都有可能会有很多,会超出所定义的图像的尺寸,针对这种情况,先对个数进行范围的限制
	//先用 minMaxLoc函数来得到计算直方图后的像素的最大个数
	double max_val;
	minMaxLoc(hist, 0, &max_val, 0, 0);
	//将像素的个数整合到 图像的最大范围内
	//遍历直方图得到的数据
	for (int i = 0; i < 256; i++)
	{
		float bin_val = hist.at<float>(i);   //注意hist中是float类型
		int intensity = cvRound(bin_val*hist_height / max_val);  //要绘制的高度  
		rectangle(hist_img, Point(i*scale, hist_height - 1), Point((i + 1)*scale - 1, hist_height - intensity), Scalar(255, 255, 255));
		//line(hist_img, Point(i*scale, hist_height - 1), Point((i + 1)*scale - 1, hist_height - intensity), Scalar(255, 255, 255), 2, 8, 0);
	}

	//*********绘制直方图(绘制方式二)*********
	int hist_w = 500;
	int hist_h = 300;
	int nHistSize = 256;
	int bin_w = cvRound((double)hist_w / nHistSize);	//区间
	Mat histImage(hist_h, hist_w, CV_8UC3, Scalar(0, 0, 0));//创建一个黑底的图像,为了可以显示彩色,所以该绘制图像是一个8位的3通道图像
	//将直方图归一化到[0,histImage.rows]
	normalize(hist, hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
	//在直方图画布上画出直方图
	for (int i = 1; i < nHistSize; i++)
	{
		line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(hist.at<float>(i - 1))),
			Point(bin_w*(i), hist_h - cvRound(hist.at<float>(i))), Scalar(0, 255, 0), 2, 8, 0);
	}

	//显示直方图
	imshow("【灰度直方图--方式一绘制】", hist_img);
	imshow("【灰度直方图--方式二绘制】", histImage);
	waitKey(0);

2、rgb直方图绘制

//------------【1】读取源图像并检查图像是否读取成功--------------------------------       
	Mat srcImage = imread("D:/OutPutResult/ImageTest/aurora.jpg");
	if (!srcImage.data)
	{
		cout << "读取图片错误,请重新输入正确路径!\n";
		system("pause");
		return -1;
	}
	namedWindow("【源图像-RGB颜色空间】");
	imshow("【源图像-RGB颜色空间】", srcImage);
	//-------------【2】图像通道的分离,3个通道B、G、R------------------------
	vector<Mat> rgb_channel;
	split(srcImage, rgb_channel);
	//-------------【3】初始化直方图计算参数---------------------------------------
	int bins = 256;
	int histsize[] = { bins };
	float range[] = { 0, 256 };
	const float* histRange = { range };
	Mat  b_Hist, g_Hist, r_Hist;
	//-------------【4】计算各个通道的直方图--------------------------------------
	calcHist(&rgb_channel[0], 1, 0, Mat(), b_Hist, 1, histsize, &histRange, true, false); //B-通道
	calcHist(&rgb_channel[1], 1, 0, Mat(), g_Hist, 1, histsize, &histRange, true, false); //G-通道
	calcHist(&rgb_channel[2], 1, 0, Mat(), r_Hist, 1, histsize, &histRange, true, false); //R-通道
	//-------------【5】设置直方图绘图参数----------------------------------------------------
	int hist_h = 360;
	int hist_w = bins * 3;
	int bin_w = cvRound((double)hist_w / bins);
	Mat histImage(hist_h, hist_w, CV_8UC3, Scalar(0, 0, 0));//创建一个黑底的图像,为了可以显示彩色,所以该绘制图像是一个8位的3通道图像  
	//-------------【6】将直方图归一化到[0,histImage.rows]  ------------------------------------------------------------------------------
	normalize(b_Hist, b_Hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());  //B-通道
	normalize(g_Hist, g_Hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());  //G-通道
	normalize(r_Hist, r_Hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());  //R-通道
	//--------------【7】绘制直方图  ----------------------------------------------------------------
	for (int i = 1; i < bins; i++)
	{
		//绘制B通道的直方图信息
		line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(b_Hist.at<float>(i - 1))), Point(bin_w*(i), hist_h - cvRound(b_Hist.at<float>(i))), Scalar(255, 0, 0), 2, 8, 0);
		//绘制G通道的直方图信息
		line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(g_Hist.at<float>(i - 1))), Point(bin_w*(i), hist_h - cvRound(g_Hist.at<float>(i))), Scalar(0, 255, 0), 2, 8, 0);
		//绘制R通道的直方图信息
		line(histImage, Point(bin_w*(i - 1), hist_h - cvRound(r_Hist.at<float>(i - 1))), Point(bin_w*(i), hist_h - cvRound(r_Hist.at<float>(i))), Scalar(0, 0, 255), 2, 8, 0);
	}
	namedWindow("【RGB直方图】");
	imshow("【RGB直方图】", histImage);
	waitKey(0);

 

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青山渺渺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值