C++OpenCV图像处理的基本操作(五)——直方图

 

直方图的优点

        图像直方图由于其计算代价较小,且具有图像平移旋转缩放不变性等众多优点,广泛地应用于图像处理的各个领域,特别是灰度图像的阈值分割、基于颜色的图像检索以及图像分类。

1.一维的直方图

函数部分如下所示:

void QuickDemo::histogram_demo(Mat &image) {
	/*图像直方图是图像像素值的统计学特征,计算代价较小,具有图像的平移、旋转、缩放不变性的优点。
	Bins是指直方图的大小范围
	*/
	//三通道分离
	std::vector<Mat>bgr_plane;
	split(image, bgr_plane);
	//定义参数变量
	const int channels[1] = { 0 };
	const int bins[1] = { 256 };//一共有256个灰度级别
	float hranges[2] = { 0,255 };//每个通道的灰度级别是0-255
	const float* ranges[1] = { hranges };
	Mat b_hist;
	Mat g_hist;
	Mat r_hist;
	//计算Blue、Green、Red通道的直方图,1表示只有一张图,因为可以支持多张图多个通道;0表示只有1个通道;raanges就是直方图的取值范围0-25
	calcHist(&bgr_plane[0], 1, 0, Mat(), b_hist,1,bins, ranges);
	calcHist(&bgr_plane[1], 1, 0, Mat(), g_hist, 1, bins, ranges);
	calcHist(&bgr_plane[2], 1, 0, 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);
	//归一化直方图数据
	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());
	//绘制直方图曲线
	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(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);
		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("Histogram Demo", WINDOW_AUTOSIZE);
	imshow("Histogram Demo", histImage);
}

2.二维的直方图

函数部分如下所示:

void QuickDemo::histogram_2d_demo(Mat& image) {
	//2D直方图
	Mat hsv, hs_hist;
	cvtColor(image, hsv, COLOR_BGR2HSV);
	int hbins = 30;//H一共有180,设置hbins为30可以理解为分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, true, false);
	double maxVal = 0;
	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++) {
		for (int s = 0; s < sbins; s++) {
			float binVal = hs_hist.at<float>(h, s);
			int intensity = cvRound(binVal * 255 / maxVal);
			rectangle(hist2d_image, Point(h * scale, s * scale), Point((h + 1) * scale - 1, (s + 1) * scale - 1), Scalar::all(intensity), -1);
		}
		 
	}
	imshow("H-S Histogram", hist2d_image);
	imwrite("D:/hist_2d.png", hist2d_image);

}

               

对于要显示彩色的二维直方图需要加一句话如下所示:

applyColorMap(hist2d_image, hist2d_image, COLORMAP_JET);

结果如下所示:

3.灰度直方图

Mat QuickDemo::histogram_grayImage(const Mat& image)
{
	//定义求直方图的通道数目,从0开始索引
	int channels[] = { 0 };
	//定义直方图的在每一维上的大小,例如灰度图直方图的横坐标是图像的灰度值,就一维,bin的个数
	//如果直方图图像横坐标bin个数为x,纵坐标bin个数为y,则channels[]={1,2}其直方图应该为三维的,Z轴是每个bin上统计的数目
	const int histSize[] = { 256 };
	//每一维bin的变化范围
	float range[] = { 0,256 };

	//所有bin的变化范围,个数跟channels应该跟channels一致
	const float* ranges[] = { range };

	//定义直方图,这里求的是直方图数据
	Mat hist;
	//opencv中计算直方图的函数,hist大小为256*1,每行存储的统计的该行对应的灰度值的个数
	calcHist(&image, 1, channels, Mat(), hist, 1, histSize, ranges, true, false);

	//找出直方图统计的个数的最大值,用来作为直方图纵坐标的高
	double maxValue = 0;
	//找矩阵中最大最小值及对应索引的函数
	minMaxLoc(hist, 0, &maxValue, 0, 0);
	//最大值取整
	int rows = cvRound(maxValue);
	//定义直方图图像,直方图纵坐标的高作为行数,列数为256(灰度值的个数)
	//因为是直方图的图像,所以以黑白两色为区分,白色为直方图的图像
	Mat histImage = Mat::zeros(rows, 256, CV_8UC1);

	//直方图图像表示
	for (int i = 0; i < 256; i++)
	{
		//取每个bin的数目
		int temp = (int)(hist.at<float>(i, 0));
		//如果bin数目为0,则说明图像上没有该灰度值,则整列为黑色
		//如果图像上有该灰度值,则将该列对应个数的像素设为白色
		if (temp)
		{
			//由于图像坐标是以左上角为原点,所以要进行变换,使直方图图像以左下角为坐标原点
			histImage.col(i).rowRange(Range(rows - temp, rows)) = 255;
		}
	}
	//由于直方图图像列高可能很高,因此进行图像对列要进行对应的缩减,使直方图图像更直观
	Mat resizeImage;
	resize(histImage, resizeImage, Size(256, 256));
	return resizeImage;
	
}

  • 1
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
计算机视觉图像处理中,直方图是一个非常重要的概念,它可以帮助我们更好地理解和处理图像。在 OpenCV 中,可以使用函数 `calcHist()` 来计算图像的直方图,该函数接收的参数包括图像、通道数、直方图尺寸、像素值范围等。具体的操作流程如下: 1. 读取图像并转换为灰度图像 2. 定义直方图的参数,包括通道数、直方图尺寸和像素值范围等 3. 计算直方图 4. 绘制直方图 下面是一个简单的代码示例: ```cpp #include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main() { // 读取图像并转换为灰度图像 Mat srcImage = imread("lena.jpg", IMREAD_GRAYSCALE); // 定义直方图的参数 int histSize[] = { 256 }; float range[] = { 0, 256 }; const float* histRange[] = { range }; int channels[] = { 0 }; // 计算直方图 Mat hist; calcHist(&srcImage, 1, channels, Mat(), hist, 1, histSize, histRange); // 绘制直方图 int hist_w = 512, hist_h = 400; int bin_w = cvRound((double)hist_w / histSize); Mat histImage(hist_h, hist_w, CV_8UC1, Scalar(0)); normalize(hist, hist, 0, histImage.rows, NORM_MINMAX, -1, Mat()); for (int i = 1; i < histSize[0]; 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(255), 2, LINE_AA); } // 显示原始图像和直方图 namedWindow("Source Image", WINDOW_AUTOSIZE); imshow("Source Image", srcImage); namedWindow("Histogram", WINDOW_AUTOSIZE); imshow("Histogram", histImage); waitKey(0); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

AI炮灰

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

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

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

打赏作者

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

抵扣说明:

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

余额充值