OpenCV学习笔记07_直方图的创建与显示

①直方图概述:
在统计学中,直方图是一种对数据分布情况的图形表示,是一种二维统计图表,他的两个坐标分别是统计样本(图像、视频帧)和样本的某种属性(亮度,像素值,梯度,方向,色彩等等任何特征)。通常直方图的维数要低于原始数据。

步骤:

1.创建矩阵;

2.加载原图像;

3.使用OpenCV函数 split() 将图像分割成3个单通道图像;

4.设定像素取值范围,我们知道像素值的范围是 [0,255];

5.使用OpenCV函数calcHist() 分别计算三个通道的直方图;

6.创建显示直方图的画布并使用 normalize() 函数归一化直方图;

7.最后显示直方图

前面四步过程说明省略

第五步:创建直方图:calcHist()函数

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

参数解释:

1.const Mat* images:输入图像

2.int nimages:输入图像的个数

3.const int* channels:需要统计直方图的第几通道

4.InputArray mask:掩膜,,计算掩膜内的直方图 …Mat()

5.OutputArray hist:输出的直方图数组(一维的数组但是保存为Mat类型,如下图所示)

在这里插入图片描述

6.int dims:需要统计直方图通道的个数

7.const int* histSize:指的是直方图分成多少个区间,就是 bin的个数

8.const float** ranges: 统计像素值的区间

9.bool uniform=true::是否对得到的直方图数组进行归一化处理

10.bool accumulate=false:在多个图像时,是否累计计算像素值的个数

第六步:使用normalize()将直方图的个数规范到画布高度

CV_EXPORTS_W void normalize( 
InputArray src, 
InputOutputArray dst, 
double alpha = 1, 
double beta = 0,
int norm_type = NORM_L2, 
int dtype = -1, 
InputArray mask = noArray());

参数解释:
1、InputArray src 输入图像数组;
2、InputOutputArray dst 输出图像数组(可与输入数组相同);
3、double alpha 规范化的最小值 normalization模式
4、double beta 规范化的最大值
5、int norm_type:归一化的类型,可以有以下的取值:
NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化,一般较常用。
NORM_INF:此类型的定义没有查到,根据OpenCV 1的对应项,可能是归一化数组的C-范数(绝对值的最大值)
NORM_L1 : 归一化数组的L1-范数(绝对值的和)
NORM_L2: 归一化数组的(欧几里德)L2-范数
6、int dtype为负数时,输出数组的type与输入数组的type相同;
7、mask操作掩膜,用于指示函数是否仅仅对指定的元素进行操作。

第7步:使用cv::line()函数或cv::rectangle()函数在画布上画出图像。

CV_EXPORTS_W void rectangle(InputOutputArray img, Point pt1, Point pt2,
                          const Scalar& color, int thickness = 1,
                          int lineType = LINE_8, int shift = 0);

参数解释:
1、InputOutputArray img 输入图像;
2、Point pt1,左上角坐标点;
3、Point pt2,右下角坐标点;
4、const Scalar& color,框线颜色;
5、int thickness 框线宽度;
6、int lineType 线的类型;
7、int shift 坐标点的小数点位数

CV_EXPORTS_W void rectangle(InputOutputArray img, Rect rec,
                          const Scalar& color, int thickness = 1,
                          int lineType = LINE_8, int shift = 0);

参数解释:
1、InputOutputArray img 输入图像;
2、Rect rec,cv::Rect型对象的框线;
3、const Scalar& color,框线颜色;
4、int thickness 框线宽度;
5、int lineType 线的类型;
6、int shift 坐标点的小数点位数

#include <opencv.hpp>
#include <opencv2/highgui.hpp>

int main() 
{
    
    
	//读入图像数据
	cv::Mat src = cv::imread("C:\\Users\\Administrator\\Desktop\\test.jpg");

	/*cv::Mat channles[3];*/
	//创建通道向量
	std::vector<cv::Mat> channels;
	//分割通道
	cv::split(src, channels);

	cv::Mat B_hist, G_hist, R_hist;
	//histSize区间个数
	int hist_size = 256;
	//统计像素值的区间 包含range数组的数组
	float range[] = {
    
    0,256};
	const float *hist_Range ={
    
    range};
	//归一化   //多个图像是否累计计数
	bool uniform = true; bool accumulate = false;

	cv::calcHist(&channels[0], 1, 0, cv::Mat(), B_hist, 1, &hist_size, &hist_Range, uniform, accumulate);
	cv::calcHist(&channels[1], 1, 0, cv::Mat(), G_hist, 1, &hist_size, &hist_Range, uniform, accumulate);
	cv::calcHist(&channels[2], 1, 0, cv::Mat(), R_hist, 1, &hist_size, &hist_Range, uniform, accumulate);
	for (int i =0;i<256;i++)
	{
    
    
		printf("%f\t", B_hist.at<float>(i));
	}
	

	int W = 512;
	int H = 400;

	//创建一个Mat背景矩阵
	cv::Mat dst(H,W,CV_8UC3, cv::Scalar(0, 0, 0));

	cv::Mat B_H, G_H, R_H;

	//深拷贝,需要单独处理
	B_H = dst.clone();
	G_H = dst.clone();
	R_H = dst.clone();

	//个数归一化
	cv::normalize(B_hist, B_hist, 0, dst.rows, cv::NORM_MINMAX, -1, cv::Mat());
	cv::normalize(G_hist, G_hist, 0, dst.rows, cv::NORM_MINMAX, -1, cv::Mat());
	cv::normalize(R_hist, R_hist, 0, dst.rows, cv::NORM_MINMAX, -1, cv::Mat());


	cv::imshow("B_hist",B_hist);
	cv::imshow("G_hist", G_hist);
	cv::imshow("R_hist", R_hist);
	
	//将Mat宽等分成256份
	int bin_w = cvRound((double) W / 256);

	for (int i = 1; i < 256; i++)
	{
    
    
		//画线
		cv::line(dst, 
			cv::Point(bin_w*(i-1), H - B_hist.at<float>(i - 1)),
			cv::Point(bin_w*(i), H - B_hist.at<float>(i)),
			cv::Scalar(255,0,0));
		cv::line(dst, 
			cv::Point(bin_w*(i - 1), H - G_hist.at<float>(i - 1)),
			cv::Point(bin_w*i, H - G_hist.at<float>(i) ),
			cv::Scalar(0, 255, 0));
		cv::line(dst, 
			cv::Point(bin_w*(i - 1), H - R_hist.at<float>(i - 1)),
			cv::Point(bin_w*(i), H - R_hist.at<float>(i)),
			cv::Scalar(0, 0,255));


		/*带有单个索引(i)的变量可用于访问单行或单列二维数组的元素。也就是说,如果,例如,A是一个1 x N的浮点矩阵,B是一个M x 1的整数矩阵,你可以简单地写A在<float>(k+4)处和B在`<int>(2*i+1)`处,而不是A在`<float>(0,k+4)`处和B在`<int>(2*i+1,0)`处。*/

	}

	/*cv::Rect rect;*/

	for (int i = 1; i < 256; i++)
	{
    
    

		//画矩形
		cv::rectangle(B_H,
			cv::Rect((i-1)*bin_w, H - B_hist.at<float>(i - 1),2,B_hist.at<float>(i-1)),
			cv::Scalar(255,0,0));
		cv::rectangle(G_H, 
			cv::Rect((i - 1)*bin_w, H - G_hist.at<float>(i - 1), 2, G_hist.at<float>(i-1)),
			cv::Scalar(0, 255, 0));
		cv::rectangle(R_H, 
			cv::Rect((i - 1)*bin_w, H -R_hist.at<float>(i - 1), 2, R_hist.at<float>(i-1)),
			cv::Scalar(0, 0, 255));

	}

// 	cv::imshow("B_H", B_H);
// 	cv::imshow("G_H", G_H);
// 	cv::imshow("R_H", R_H);




	cv::imshow("Hist", dst);
	cv::waitKey(0);
}

请添加图片描述

猜你喜欢

转载自blog.csdn.net/qq_40595787/article/details/120706726