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

 

直方图的优点

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

1.一维的直方图

函数部分如下所示:

void QuickDemo::histogram_demo(Mat &image) {
	/*图像直方图是图像像素值的统计学特征,计算代价较小,具有图像的平移、旋转、缩放不变性的优点。
	Bins是指直方图的大小范围
	*/
	//三通道分离
	std::vectorbgr_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(i - 1))),
			Point(bin_w * (i), hist_h - cvRound(b_hist.at(i))), Scalar(255, 0, 0), 2, 8, 0);
		line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(g_hist.at(i - 1))),
			Point(bin_w * (i), hist_h - cvRound(g_hist.at(i))), Scalar(0, 255, 0), 2, 8, 0);
		line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(r_hist.at(i - 1))),
			Point(bin_w * (i), hist_h - cvRound(r_hist.at(i))), Scalar(0, 0, 255), 2, 8, 0);
	}
	//显示直方图
	namedWindow("Histogram Demo", WINDOW_AUTOSIZE);
	imshow("Histogram Demo", histImage);
}

C++OpenCV图像处理的基本操作(五)——直方图_第1张图片

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

}

               C++OpenCV图像处理的基本操作(五)——直方图_第2张图片

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

applyColorMap(hist2d_image, hist2d_image, COLORMAP_JET);

C++OpenCV图像处理的基本操作(五)——直方图_第3张图片

结果如下所示:

C++OpenCV图像处理的基本操作(五)——直方图_第4张图片

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(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;
	
}

你可能感兴趣的:(c++opencv图像处理,计算机视觉-图像处理,计算机视觉,图像处理,c++,opencv)