基于C++的OpenCV4入门基础--图像的灰度直方图

本文介绍了图像直方图的概念及其在图像处理中的作用,特别是灰度直方图对亮度和对比度的体现。通过OpenCV的cv2.calcHist函数,讲解了如何计算和绘制图像直方图,并提到了Numpy的np.bincount作为替代方法。文章还强调了计算直方图时参数设置的注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

图像直方图是反映图像像素分布的统计表,横坐标代表像素值的取值区间,纵坐标代表每一像素值在图像中的像素总数或者所占的百分比。 灰度直方图是图像灰度级的函数,用来描述每个灰度级在图像矩阵中的像素个数。

灰度直方图反映了图像中的灰度分布规律,直观地表现了图像中各灰度级的占比,很好地体现出图像的亮度和对比度信息:灰度图分布居中说明亮度正常,偏左说明亮度较暗,偏右表明亮度较高;狭窄陡峭表明对比度降低,宽泛平缓表明对比度较高。

根据直方图的形态可以判断图像的质量,通过调控直方图的形态可以改善图像的质量。
直方图和addWeight方法都可以改善图像亮度和对比度。
直方图比较可以判断图像的相似度。

OpenCV 提供了函数 cv2.calcHist 可以计算直方图,Numpy 中的函数 np.bincount 也可以实现同样的功能。

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

函数 cv2.calcHist 可以计算一维直方图或二维直方图,函数的参数 images, channels, histSize, ranges 在计算一维直方图时也要带 [] 号。

参数说明:
images:输入图像,用 [] 括号表示数组
channels: 直方图计算的通道,用 [] 括号表示
mask:掩模图像,一般置为 None
histSize:直方柱的数量,一般取 256
ranges:像素值的取值范围,一般为 [0,256]
返回值 hist:返回每一像素值在图像中的像素总数,形状为 (histSize,1)
注意:
1.参数 images, channels, histSize, ranges 都要带 [] 号。
2.mask 是与 images 大小相同的掩模图像,掩模为 0 的区域不作处理。不使用掩模时设为 None。
3. channels 设置对彩色图像的指定通道计算直方图,灰度图像时设为 0。
4. Numpy 中的函数 np.bincount 也可以实现同样的功能,但该函数返回值的形状为 (histSize,)

1,图像直方图概念
在这里插入图片描述
那么,对于我们的图像直方图统计来说,对于 RGB 彩色图,像素值的范围是0~255,那么像素等级就有256个等级,也就是bin的个数是256,当然bin的个数也可以根据需要进行设置,例如设置16个bin,那么每个bin的范围是0-15

2,统计并绘制直方图:
对与 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);

在这里插入图片描述
你的鼓励将是我创作的最大动力
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

孤舟簔笠翁

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

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

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

打赏作者

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

抵扣说明:

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

余额充值