【C++ calcHist函数(图像直方图)】

一、 函数原型

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 );

函数作用:计算一个或多个数组的直方图

参数解释
images输入图像
nimages输入图像个数
channels用来计算直方图的dims通道的列表
mask可选的掩码
hist输出直方图
dims直方图的维数(不大于CV_MAX_DIMS)
histSize每个维度的直方图尺寸的数组(256)
ranges每个维度的直方图范围的数组[dims]的阵列(0-255)
uniform表示直方图是否是统一的标志
accumulate累积标志

uniform:是否对灰度值范围进行均匀划分的标志
ccumulate:累积标志。如果它被设置,直方图在开始分配时不会被清除。
分配时不会被清除。这个特性使你可以从几组数组中计算出一个单一的直方图,或者更新直方图。

数组,或者及时更新柱状图。

二、参数具体解释

1. channels

用来计算直方图的dims通道的列表。
第一个通道索引值:0到images[0].channels()-1的数字

(如果是三通道,就是0 ~(3-1) 即 0 ~ 2)

第二个通道索引值:images[0].channels() 到 images[0].channels() + images[1].channels()-1

例:三张三通道图像,
则第一张图像三个通道索引值:0、1、2
第一张图像三个通道索引值:3、4、5
第一张图像三个通道索引值:6、7、8
计算二维直方图(第一张图像第二通道,第二张图象第三通道)
const int channels[1] = { 0,5 };

2. mask

可选的操作掩码矩阵,
如果是空矩阵则表示图像中所有位置的像素都计入直方图中,
如果矩阵不为空,则该操作掩码矩阵必须与输入图像尺寸相同且数据类型为CV_8U。当矩阵不为空的时候,那些掩码值不为0的掩码对应的像素被纳入统计范围,而那些掩码值为0的掩码对应的像素则不被纳入统计。
空矩阵:Mat();

3. dims

需要计算的直方图的维度(不大于CV_MAX_DIMS)
一般为数组channels大小(三通道为3),当写为1的时候计算的是通道索引数组中的第1个通道的直方图,当写为2的时候计算的是通道索引数组中的第1个通道和第2个通道的二维直方图。

4. histSize

每个维度的直方图尺寸,直方图中每个dims维度需要分成多少个区间(如果把直方图看作一个一个竖条的话,就是竖条的个数);

例如:
计算二维直方图(第一张图像第二通道,第二张图象第一通道)两个图象分别为RGB和HSV
const int histSize[2] = { 256 ,181 };
可以分为256个区间(也就是一个像素值一个区间)
const int histSize[2] = { 3 ,3 };
(也可以分为3个区间,也就是256/3个像素值一个区间,画出来的直方图就是三个点两个折线)

5. ranges

例如:
计算二维直方图(第一张图像第二通道,第二张图象第一通道)两个图象分别为RGB和HSV(也就是一维根据第一个图象决定,二维根据第二个图像决定)
float hranges1[2] = { 0,255 };
float hranges2[2] = { 0,180 };
const float* ranges[2] = { hranges1, hranges2};

三、 代码

1. 一维直方图

// 图像直方图
void QuickDemo::showHistogram(Mat& image)
{ 
	// 三通道分离
	std::vector<Mat> bgr_plane;			// Mat有三个通道
	split(image, bgr_plane);
	// 定义参数变量
	const int channels[1] = { 0 };
	const int bins[1] = { 256 };				// 每个维度分成256个区间
	float hranges[2] = { 0,255 };
	const float* ranges[1] = { hranges };
	Mat b_hist;
	Mat g_hist;
	Mat r_hist;
	// 计算Blue,GReen,Red通道的直方图
	//  输入图像  输入图像个数 统计直方图第几通道  输出直方图维度 每个维度分成多少区间 统计像素值的区间
	calcHist(&bgr_plane[0], 1, channels,Mat()       , b_hist, 1,     bins,             ranges);
	calcHist(&bgr_plane[1], 1, channels,Mat()       , g_hist, 1,     bins,             ranges);
	calcHist(&bgr_plane[2], 1, channels,Mat()       , r_hist, 1,     bins,             ranges);
	// 显示直方图
	int hist_w = 512;
	int hist_h = 400;
	int bin_w = cvRound((double)hist_w / bins[0]);		// 一个区间的长度(总长度/区间)
	Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);	// 定义一个Mat图像显示直方图
	// 1. 归一化直方图数据
	normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
	normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
	normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
	// 2. 绘制直方图曲线
	for (int i = 1; i < bins[0]; i++)		// 分别绘制每个区间
	{
		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);
		line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))),
			Point(bin_w * (i), hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0), 2, 8, 0);
		line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))),
			Point(bin_w * (i), hist_h - cvRound(r_hist.at<float>(i))), Scalar(0, 0, 255), 2, 8, 0);
	}
	// 3. 显示出来
	namedWindow("一维直方图", WINDOW_AUTOSIZE);
	imshow("一维直方图", histImage);
}

2. 二维直方图

// 二维直方图
void QuickDemo::showHistogram_2d_demo(Mat& image)
{
	// 直方图矩阵计算
	Mat hsv, hs_hist;	// hsv:将图像转换为HSV类型 hs_hist:直方图计算输出矩阵
	cvtColor(image, hsv, COLOR_BGR2HSV); 
	int hs_channels[] = {0,1};			// 参数channels:需要统计直方图的第几通道;h s
	int hbins = 30, sbins = 32;			// 参数histSize:直方图中每个dims维度需要分成多少个区间(如果把直方图看作一个一个竖条的话,就是竖条的个数);
	int hist_bins[] = { hbins, sbins };
	float h_range[] = { 0, 180 }, s_range[] = { 0,255 };
	const float* hs_ranges[] = { h_range,s_range };		// ranges:统计像素值的区间;
	calcHist(&hsv, 1, hs_channels, Mat(), hs_hist, 2, hist_bins, hs_ranges, true, false);
	// 直方图输出
	double maxVal;
	minMaxLoc(hs_hist, 0, &maxVal, 0, 0);	// 获取像素最大值
	int scale = 10;		// 确定输出直方图图像大小范围
	Mat hist2d_image = Mat::zeros(sbins * scale, hbins * scale, CV_8UC3);	// 用作输出的图像
	for (int h = 0; h < hbins; h++)		// 参数histSize:直方图中每个dims维度需要分成多少个区间(如果把直方图看作一个一个竖条的话,就是竖条的个数);
	{
		for (int s = 0; s < sbins; s++)
		{
			float binVal = hs_hist.at<float>(h, s);			// 获取像素值
			int intensity = cvRound(binVal * 255 / maxVal);	// 实现将hs_hist中对应第h行第s列的数值限制到0到255。如果只除以maxval(用minMaxLoc找到的矩阵中的最大值)就是归一化,限制到0到1,但乘上255就限制到255了。
			rectangle(hist2d_image, Point(h * scale, s * scale), Point((h + 1) * scale - 1, (s + 1) * scale - 1), Scalar::all(intensity), -1);
		}
	}
	applyColorMap(hist2d_image, hist2d_image, COLORMAP_JET);
	imshow("hs 二维直方图", hist2d_image);
	imwrite("D:\\software\\hist_2d.png", hist2d_image);
}

参考链接

  1. 对OpenCV的图像直方图计算函数calcHist()进行透彻解析
  2. OpenCV4 C++ 快速入门视频30讲 - 系列合集
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值