文章目录
- opencv图像的直方图,二维直方图,直方图均衡化
 - 一、图像的直方图
 - 1、什么是图像的直方图:
 - 2、直方图的作用:
 - 3、如何绘制图像的直方图:
 - (1)cv::calcHist()函数原型:
 - (2)代码示例:
 - cv::cvRound()函数:将浮点数值四舍五入为最接近的整数;
 - 灰度图像直方图:
 - 彩色图像直方图:
 
- 二、二维直方图
 - 1、什么是二维直方图:
 - 2、二维直方图与直方图有哪些不同:
 - 3、二维直方图的作用:
 - 4、如何绘制二维直方图:
 
- 三、直方图均衡化
 - 1、直方图均衡化的原理:
 - 2、opencv中,可以使用 `cv::equalizeHist()`函数来实现直方图均衡化:
 - (1)cv::equalizeHist()函数原型:
 - (2)代码示例:
 - 灰度直方图均衡化:
 - 彩色直方图均衡化:
 
opencv图像的直方图,二维直方图,直方图均衡化
一、图像的直方图
1、什么是图像的直方图:
- 要理解直方图,绕不开“亮度”这个概念,人们把亮度分为0到255共256个数值,数值越大,代表的亮度越高,其中0代表纯黑色,最暗区域,255表示最亮,纯白色,而中间的数字就是不同亮度的灰色;
 - 图像的直方图是一种统计图,它显示了图像中各个灰度级别的分布情况(也就是统计一幅图某个亮度像素的数量),通常它的横轴代表像素的灰度级别(从0到255),而纵轴代表该灰度级别在图像中出现的频次或概率;
 
2、直方图的作用:
- 可视化图像亮度分布:直方图能够帮助我们直观地了解图像的亮度分布情况,从而为图像处理提供重要参考;
 - 对比度调整:通过观察直方图,我们可以确定图像的对比度是否合适,从而决定是否需要进行对比度调整;
 - 灰度级别选择:直方图可以帮助我们选择合适的灰度级别,以使图像的细节更加清晰;
 
3、如何绘制图像的直方图:
在opencv中,可以使用
cv::calcHist()函数来计算图像的直方图,这个函数可以接受一个通道的图像(灰度图像)或多个通道的图像(彩色图像);
(1)cv::calcHist()函数原型:
void cv::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:要统计的通道索引,比如{0}表示统计第一个通道,{0, 1, 2}表示统计所有三个通道;
mask:掩码图像,用于指定计算直方图的区域(必须是一个8位(CV_8U)的数组并且和images的数组大小相同);
hist:直方图计算的输出值,是一个cv::Mat对象;
dims:输出直方图的维度(
	由channels值决定dims的数值;
	对于灰度图像dims为1,因为我们只考虑了一个通道(亮度通道);
	对于彩色图像,通常会考虑多个通道,比如在HSV色彩空间中,dims为2(H和S两个通道) 
);
histSize:指定每个dims维度需要分成多少个区间(用于控制直方图的精细度);
ranges:用于指定每个dims维度(通道)的取值范围,包含了每个通道的最小值和最大值(
	对于灰度图像,单通道只有1个range,灰度级别的范围从0到255;
	对于彩色图像有多个通道就有多个range,对于每个通道,ranges指定了取值范围,通常在彩色图像中,H(色相)的范围是0到180,S(饱和度)和V(明度)的范围是0到255 );
uniform:是否对得到的直方图数组进行归一化处理;
accumulate:在多个图像时,是否累积计算像素值的个数;
 
(2)代码示例:
cv::cvRound()函数:将浮点数值四舍五入为最接近的整数;
// 函数在图像处理过程中经常用于处理像素值,特别是当需要将浮点数转换为整数时,可以保留最接近的整数值
int cvRound(double value)
参数解释:
value:待四舍五入的浮点数;
 
灰度图像直方图:
#include <opencv2\opencv.hpp>
#include <iostream>
#include <demo.h>
using namespace cv;
using namespace std;
int main() {
	// 读取灰度图像
	cv::Mat image = cv::imread("C:\\cpp\\image\\suzy2.jpg", cv::IMREAD_GRAYSCALE);
	if (image.empty()) {
		std::cerr << "Error: 无法读取图像文件." << std::endl;
		return -1;
	}
	// 直方图计算的输出值,是一个cv::Mat对象
	cv::Mat hist;
	// 亮度级别的个数
	int histSize = 256; 
	// 亮度值的范围
	float range[] = { 0, 256 };
	// 在C++中,数组名本身就代表该数组的首地址,无需使用取地址符号&,
	const float* histRange = range;
	cv::calcHist(&image, 1, 0, cv::Mat(), hist, 1, &histSize, &histRange);
	// 待绘制的目标图像,将直方图计算的输出值hist,绘制到histImage图像上
	int histWidth = 512, histHeight = 400;
	int binWidth = cvRound( (double)histWidth/histSize );
	cv::Mat histImage(histHeight, histWidth, CV_8UC3, cv::Scalar(0, 0, 0));
	// 使用normalize()函数将直方图的值缩放到图像的高度范围内
	normalize(hist, hist, 0, histImage.rows, cv::NORM_MINMAX, -1, cv::Mat());
	// 使用cv::line()函数绘制直线
	for ( int i=1; i<histSize; i++ ) {
		cv::line( 
			histImage, 
			Point( binWidth*(i-1), histHeight-cvRound(hist.at<float>(i-1)) ),
			Point( binWidth*(i), histHeight-cvRound(hist.at<float>(i)) ),
			Scalar(255, 0, 0), 
			2, 
			LINE_8,
			0
		);
	}
	// 显示图像和直方图
	cv::imshow("Image", image);
	cv::imshow("Histogram", histImage);
	waitKey();
	return 0;
}
 
运行结果:
 
彩色图像直方图:
对于彩色图像,你可以分别计算其颜色通道(蓝色、绿色、红色)的直方图,或者将其转换为灰度图像后计算整体的亮度直方图;
在这个示例中,我们首先读取了一个彩色图像,然后使用 cv::split() 函数将图像分离成蓝色、绿色和红色通道,接着,我们分别计算了每个通道的直方图,最后我们绘制了各个通道的直方图并显示了原始图像和直方图;
#include <opencv2\opencv.hpp>
#include <iostream>
#include <demo.h>
using namespace cv;
using namespace std;
int main() {
	// 读取彩色图像
	cv::Mat image = cv::imread("C:\\cpp\\image\\suzy2.jpg");
	if (image.empty()) {
		std::cerr << "Error: 无法读取图像文件." << std::endl;
		return -1;
	}
	// 分离通道
	std::vector<cv::Mat> bgrPlanes;
	cv::split(image, bgrPlanes);
	// 计算直方图
	int histSize = 256; // 亮度级别的个数
	float range[] = { 0, 256 };
	const float* histRange = range;
	cv::Mat bHist, gHist, rHist;
	cv::calcHist(&bgrPlanes[0], 1, 0, cv::Mat(), bHist, 1, &histSize, &histRange);
	cv::calcHist(&bgrPlanes[1], 1, 0, cv::Mat(), gHist, 1, &histSize, &histRange);
	cv::calcHist(&bgrPlanes[2], 1, 0, cv::Mat(), rHist, 1, &histSize, &histRange);
	// 绘制直方图
	int histWidth=512, histHeight=400;
	int binWidth = cvRound( (double)histWidth/histSize );
	cv::Mat histImage(histHeight, histWidth, CV_8UC3, cv::Scalar(0, 0, 0));
	normalize(bHist, bHist, 0, histImage.rows, cv::NORM_MINMAX, -1, cv::Mat());
	normalize(gHist, gHist, 0, histImage.rows, cv::NORM_MINMAX, -1, cv::Mat());
	normalize(rHist, rHist, 0, histImage.rows, cv::NORM_MINMAX, -1, cv::Mat());
	for (int i=1; i<histSize; i++) {
		// 绘制蓝色分量直方图
		cv::line( 
			histImage, 
			cv::Point( binWidth*(i-1), histHeight-cvRound(bHist.at<float>(i-1)) ),
			cv::Point( binWidth*(i), histHeight-cvRound(bHist.at<float>(i)) ),
			cv::Scalar(255, 0, 0), 
			2, 
			LINE_8,
			0
		);
		// 绘制绿色分量直方图
		cv::line(
			histImage, 
			cv::Point( binWidth*(i-1), histHeight-cvRound(gHist.at<float>(i-1)) ),
			cv::Point( binWidth*(i), histHeight-cvRound(gHist.at<float>(i)) ),
			cv::Scalar(0, 255, 0), 
			2, 
			LINE_8,
			0
		);
		// 绘制红色分量直方图
		cv::line(
			histImage, 
			cv::Point( binWidth*(i-1), histHeight-cvRound(rHist.at<float>(i-1)) ),
			cv::Point( binWidth*(i), histHeight-cvRound(rHist.at<float>(i)) ),
			cv::Scalar(0, 0, 255), 
			2, 
			LINE_8,
			0
		);
	}
	// 显示图像和直方图
	cv::imshow("Image", image);
	cv::imshow("Histogram", histImage);
	cv::waitKey(0);
	return 0;
}
 
运行结果:
 
二、二维直方图
1、什么是二维直方图:
二维直方图是对彩色图像进行分析时的一个重要工具,与一维直方图不同,它同时考虑了两个通道的信息,通常是颜色空间中的两个分量,例如在HSV色彩空间中的H(色相)和S(饱和度);
2、二维直方图与直方图有哪些不同:
- 维度:直方图是一维的,它只考虑了图像的亮度或色彩信息;而二维直方图考虑了两个通道的信息,因此是二维的;
 - 通道:直方图通常只针对一个通道(灰度图只有亮度通道);而二维直方图可以同时考虑多个通道,通常是颜色空间中的两个分量;
 
3、二维直方图的作用:
- 颜色分布分析:通过二维直方图,我们可以了解图像中各个颜色组合的分布情况,有助于理解图像的颜色特性;
 - 图像分割与对象识别:在图像分割和对象识别任务中,二维直方图可用于将图像的颜色特征映射到特定的空间,从而实现对图像中的对象进行定位和识别;
 - 颜色调整与匹配:通过分析二维直方图,我们可以进行颜色调整,使图像的颜色分布更加符合预期;
 
4、如何绘制二维直方图:
首先读取了一个彩色图像,然后将其从BGR颜色空间转换为HSV颜色空间,接着我们分离了H和S通道,并指定了直方图的维度、通道数、亮度级别个数和范围,然后我们使用 cv::calcHist()计算了二维直方图并使用 cv::rectangle()绘制;
#include <opencv2\opencv.hpp>
#include <iostream>
#include <demo.h>
using namespace cv;
using namespace std;
int main() {
	// 读取彩色图像
	cv::Mat image = cv::imread("C:\\cpp\\image\\suzy2.jpg");
	if (image.empty()) {
		std::cerr << "Error: 无法读取图像文件." << std::endl;
		return -1;
	}
	// 将图像从BGR颜色空间转换为HSV颜色空间
	cv::Mat hsvImage;
	cv::cvtColor(image, hsvImage, cv::COLOR_BGR2HSV);
	// 分离H和S通道
	std::vector<cv::Mat> channels;
	cv::split(hsvImage, channels);
	int channelNumbers[] = { 0, 1 };
	int histSize[] = { 256, 256 };
	float hueRanges[] = { 0, 256 };
	float satRanges[] = { 0, 256 };
	const float* ranges[] = { hueRanges, satRanges };
	// 计算直方图
	cv::Mat hist;
	cv::calcHist(&channels[0], 1, channelNumbers, cv::Mat(), hist, 2, histSize, ranges, true, false);
	// 绘制直方图
	int histWidth= 512, histHeight = 512;
	int binWidth = histWidth/histSize[0];
	int binHeight = histHeight/histSize[1];
	cv::Mat histImage(histHeight, histWidth, CV_8UC3, cv::Scalar(0, 0, 0));
	cv::normalize(hist, hist, 0, 255, cv::NORM_MINMAX);
	for (int i = 0; i < histSize[0]; i++) {
		for (int j = 0; j < histSize[1]; j++) {
			int x = i * binWidth;
			int y = j * binHeight;
			int w = (i + 1) * binWidth - x;
			int h = (j + 1) * binHeight - y;
			cv::rectangle(histImage, cv::Rect(x, y, w, h), cv::Scalar(hist.at<float>(i, j), 0, 0), -1);
		}
	}
	// 显示图像和直方图
	cv::imshow("Image", image);
	cv::imshow("2D Histogram", histImage);
	cv::waitKey(0);
	return 0;
}
 
运行结果:
三、直方图均衡化
直方图均衡化是一种用于增强图像对比度的图像处理技术,它通过重新分配图像的像素值,使得整个亮度范围得到充分利用,从而使图像看起来更清晰和具有更好的对比度;
1、直方图均衡化的原理:
- 计算直方图:首先计算原始图像的灰度直方图,这个直方图描述了图像中各个灰度级别的分布情况;
 - 计算累积分布函数(CDF):将灰度直方图转换为累积分布函数,CDF表示了每个灰度级别的累积概率;
 - 映射新的像素值:对于每个像素,将其原始灰度值映射到新的值,使得新的值在整个亮度范围内均匀分布;
 
2、opencv中,可以使用 cv::equalizeHist()函数来实现直方图均衡化:
 
(1)cv::equalizeHist()函数原型:
void cv::equalizeHist(
	InputArray src, 
	OutputArray dst
);
参数解释:
src:输入图像(灰度图像);
dst:输出图像,用于存储均衡化后的结果;
 
(2)代码示例:
灰度直方图均衡化:
#include <opencv2\opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main() {
	// 读取灰度图像
	cv::Mat image = cv::imread("C:\\cpp\\image\\suzy2.jpg", cv::IMREAD_GRAYSCALE);
	if (image.empty()) {
		std::cerr << "Error: 无法读取图像文件." << std::endl;
		return -1;
	}
	// 均衡化灰度直方图
	cv::Mat equalizedImage;
	cv::equalizeHist(image, equalizedImage);
	 cv::imshow("Original Gray Image", grayImage);
  	 cv::imshow("Equalized Gray Image", equalizedImage);
	cv::waitKey(0);
	return 0;
}
 
运行结果:

彩色直方图均衡化:
首先将彩色图像转换为HSV色彩空间,然后对亮度(Value/V通道)进行均衡化,最后将其转换回BGR色彩空间以显示
#include <opencv2\opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main() {
	// 读取彩色图像
	cv::Mat image = cv::imread("C:\\cpp\\image\\suzy2.jpg", cv::IMREAD_COLOR);
	if (image.empty()) {
		std::cerr << "Error: 无法读取图像文件." << std::endl;
		return -1;
	}
	// 将图像从BGR色彩空间转换为HSV色彩空间
	cv::Mat hsvImage;
	cv::cvtColor(image, hsvImage, cv::COLOR_BGR2HSV);
	// 均衡化HSV通道的直方图
	std::vector<cv::Mat> channels;
	cv::split(hsvImage, channels);
	cv::equalizeHist(channels[2], channels[2]);
	cv::Mat equalizedHSV;
	cv::merge(channels, equalizedHSV);
	cv::cvtColor(equalizedHSV, equalizedHSV, cv::COLOR_HSV2BGR);
	cv::imshow("Original Color Image", image);
	cv::imshow("Equalized Color Image", equalizedHSV);
	cv::waitKey(0);
	return 0;
}
 
运行结果:
 






![[Android]问题解决-Device must be bootloader unlocked](https://img-blog.csdnimg.cn/f51ed7373b234c4a8fda588a164d1ff6.png)




![2023年中国家用智能微投市场销售概况分析:家用智能微投销量为727万台,销售额为131亿元[图]](https://img-blog.csdnimg.cn/img_convert/786693cf959d930901b4ebf91d8bd87a.png)







