使用Opencv绘制灰度直方图/对比

一.所需结构体

CvHistogram

结构体原型:

typedef struct CvHistogram {
 int type; 		/* 直方图类型 */
 CvArr* bins;	 /* 直方图数据 */	
 float thresh[CV-MAX-DIM][2]; /* 每一维的直方块边界数组 */
 float** thresh2; /* 非均匀直方图 */
CvMatND mat; 			/* 阵列柱状图的嵌入式矩阵头*/
} CvHistogram;

二.所需函数

1.cvCalcHist

函数功能:用于计算图像直方图

函数原型:

void  cvCalcHist( IplImage** image, CvHistogram* hist,int accumulate = 0,const CvArr* mask = NULL );

参数介绍

IplImage** image:	          要计算直方图的图像指针,如果要累加直方图输入图像颜色深度必须一致

CvHistogram* hist:	    	 输出参数,计算出来的直方图。

int accumulate: 		     表示是否对传入的 hist 清零。不清零的话可以将多幅图像的直方图累加,0代表清零,非0代表不清零!

const CvArr* mask:		 掩码,如果mask不为空,那么它必须是一个8位(CV_8U)的数组,并且它的大小的和输入的图像的大小相同,值非 0 的点将用来计算直方图。


返回值:无

2.CvCreateHist

函数功能:用于创建直方图

函数原型:

CvHistogram*  cvCreateHist( int dims, int* sizes, int type,float** ranges = NULL,int uniform = 1);

参数介绍:

int dims:       	表示图像是几维空间,即一般彩色图像是3通道的,dim=3;而灰度图是1通道的,dim=1,如果带有透明度的图像即RGBA则dim=4
int* sizes:		//直方图维数尺寸,size数组的长度为dims,每个数表示分配给对应维数的bin的个数。如dims=3,则size中用[s1,s2,s3]分别指定每维bin的个数。
int type: 	        直方图的表示格式: CV_HIST_ARRAY 意味着直方图数据表示为多维密集数组, CV_HIST_TREE 意味着直方图数据表示为多维稀疏数组 
float** ranges:	       表示方块范围,假设该值设置为0-255意思就是说将像素点压缩到0-255个元素之间(压缩方法是叠加,列如像素点有1024个那么会将1024个像素点的每个值相加在一块放到size组中,比如将10个像素点的值叠加在一块,然后放到对应的size组中!),并将这0-255个元素分别分布到对应的size中!
int uniform:		归一化标识,如果不为0,bin均匀处理ranges的取值范围,为0,根据ranges的设置非均匀处理对应范围的直方块


返回值:成功返回一个指向堆中CvHistogram结构体的CvHistogram指针

3.cvGetMinMaxHistValue:

函数功能:用于统计直方图中最小值和最大值

函数原型:

void cvGetMinMaxHistValue( const CvHistogram* hist, float* min_value, float* max_value,int* min_idx = NULL,int* max_idx = NULL);

参数介绍:

const CvHistogram* hist:	        要统计的直方图
float* min_value:			直方图最小值的指针 
float* max_value:			直方图最大值的指针 
int* min_idx:				数组中最小坐标的指针 
int* max_idx:				数组中最大坐标的指针 

返回值:无

4.cvConvertScale

函数功能:按比例缩放bin

函数原型:

void  cvConvertScale( const CvArr* src, CvArr* dst,double scale = 1,double shift = 0);

参数介绍:

const CvArr* src:	  输入数组
CvArr* dst:		  输出数组
double scale:		  比例因子
double shift:		  该加数与输入元素相加并按比例缩放到输出数组的元素上

返回值:无

5.cvReleaseHist

函数功能:释放直方图

函数原型:

void cvReleaseHist( CvHistogram**hist); 

参数介绍:

CvHistogram**hist :	直方图指针

返回值:无

二. 编写绘制灰度图像的直方图代码

准备工作已经完成,下面开始正式代码编写

2.1 准备工作

准备一张用于测试的图像文件,图像文件格式任意!

这里我的是jpg格式的图像文件

使用Opencv绘制灰度直方图/对比_第1张图片


如需要可自行保存到本地

2.2 编写代码,加载测试图到内存

//打开测试图
IplImage * image = cvLoadImage("D:\\test.jpg",0);			//将本地测试图导入到程序堆中
if (image == NULL){										//判断是否打开成功
		printf("错误:无法打开该图像,图像文件路径不正确!");
		return -1;
	}

2.2 创建一个直方图

//创建一个直方图
int arr_size = 255;					//定义一个变量用于表示直方图行宽
float hranges_arr[] = { 0, 255 };		//图像方块范围数组
float *phranges_arr = hranges_arr;		//cvCreateHist参数是一个二级指针,所以要用指针指向数组然后传参
CvHistogram *hist = cvCreateHist(1, &arr_size, CV_HIST_ARRAY, &phranges_arr, 1);	//创建一个一维的直方图,行宽为255,多维密集数组,方块范围为0-255,bin均化


2.3 创建一个空白图像用来绘制直方图

//创建一个空白图像用于绘制直方图
IplImage *histimg = cvCreateImage(cvSize(320, 200), 8, 3);
cvZero(histimg);    //清空histimag-imagedata数据

2.4 计算图像直方图  

//计算图像直方图大小
cvCalcHist(&image, hist, 0, 0);     

2.5 缩放直方图尺寸

//直方图根据size分组然后根据ranges取值范围来统计图像像素点范围,也就是说ranges为0-255则将图像中像素值叠加在一起(叠加成MIN:0、MIX:255)组并分组到对应的size维中,所以size维里的每个元素非常大,所以要按比例缩小
float max_val;	//用于存储获取到的最大值cvGetMinMaxHistValue(hist, 0, &max_val, 0, 0);	//获取直方图最大值
cvConvertScale(hist->bins,hist->bins, max_val ? 255. / max_val : 0., 0);	//按比例缩小直方图

2.6 绘制直方图

//开始绘制直方图
int bin_w;
bin_w = histimg->width / arr_size; //得到开始绘制点位置

	for (int i = 0; i < arr_size; i++)
	{
		double val = (cvGetReal1D(hist->bins, i)*histimg->height / 255);//获取矩阵元素值,并转换为对应高度
		CvScalar color = CV_RGB(255, 255, 0);                                 				cvRectangle(histimg, cvPoint(i*bin_w, histimg->height),
			cvPoint((i + 1)*bin_w, (int)(histimg->height - val)),
			color, 1, 8, 0);
	}

2.7 将直方图显示出来

//显示结果
cvShowImage("1", image);		//原图
cvShowImage("2", histimg);		//绘制出来的直方图
cvWaitKey(0);					//消息循环

运行结果:

使用Opencv绘制灰度直方图/对比_第2张图片

完整代码:

//打开测试图
	IplImage * image = cvLoadImage("D:\\3.jpg", 0);			//将本地测试图导入到程序堆中
	if (image == NULL){										//判断是否打开成功
		printf("错误:无法打开该图像,图像文件路径不正确!");
		return -1;
	}
	//创建一个直方图
	int arr_size = 255;					//定义一个变量用于表示直方图行宽
	float hranges_arr[] = { 0, 255 };		//图像方块范围数组
	float *phranges_arr = hranges_arr;		//cvCreateHist参数是一个二级指针,所以要用指针指向数组然后传参
	CvHistogram *hist = cvCreateHist(1, &arr_size, CV_HIST_ARRAY, &phranges_arr, 1);	//创建一个一维的直方图,行宽为255,多维密集数组,方块范围为0-255,bin均化
	//创建一个空白图像用于绘制直方图
	IplImage *histimg = cvCreateImage(cvSize(320, 200), 8, 3);
	cvZero(histimg);//清空histimag-imagedata数据
	//计算图像直方图大小
	cvCalcHist(&image, hist, 0, 0);
	//直方图根据size分组然后根据ranges取值范围来统计图像像素点范围,也就是说ranges为0-255则将图像中像素值叠加在一起(叠加成MIN:0、MIX:255)组并分组到对应的size维中,所以size维里的每个元素非常大,所以要按比例缩小
	float max_val;	//用于存储获取到的最大值
	cvGetMinMaxHistValue(hist, 0, &max_val, 0, 0);		//获取直方图最大值
	cvConvertScale(hist->bins, hist->bins, max_val ? 255. / max_val : 0., 0);	//按比例缩小直方图
	//开始绘制直方图
	int bin_w; 
	bin_w = histimg->width / arr_size;//得到开始绘制点位置

	for (int i = 0; i < arr_size; i++)
	{
		double val = (cvGetReal1D(hist->bins, i)*histimg->height / 255); //获取矩阵元素值,并转换为对应高度
		CvScalar color = CV_RGB(255, 255, 0);                                 				cvRectangle(histimg, cvPoint(i*bin_w, histimg->height),
			cvPoint((i + 1)*bin_w, (int)(histimg->height - val)),
			color, 1, 8, 0);
	}
	//显示结果
	cvShowImage("1", image);		//灰度原图
	cvShowImage("2", histimg);		//绘制出来的直方图
	cvWaitKey(0);					//消息循环

三. 基于直方图颜色数据的对比

1. 所需函数

1.1cvCompareHist

函数功能:用于对比直方图bins数据,并将对比结果以double类型返回

函数原型:

double  cvCompareHist( const CvHistogram* hist1,const CvHistogram* hist2,int method);

参数介绍:

const CvHistogram* hist1:	模板图
const CvHistogram* hist2:	要对比的图片
int method			  : 对比方法可取宏:
#define CV_COMP_CORREL 0	//值越大匹配度越高
#define CV_COMP_CHISQR 1	//值越小匹配度越高
#define CV_COMP_INTERSECT 2	//(归一化)值越大匹配度越高
#define CV_COMP_BHATTACHARYYA 3	//(归一化)值越小匹配度越高

返回值:根据method参数的值返回不同的匹配值!

2. 准备两张图片

使用Opencv绘制灰度直方图/对比_第3张图片

使用Opencv绘制灰度直方图/对比_第4张图片

3.开始编写代码

3.1 将比对图加载到内存

//加载比对图
	IplImage * image = cvLoadImage("D:\\1.jpg", 0);			//将本地模板图导入到程序堆中
	if (image == NULL){										//判断是否打开成功
		printf("错误:无法打开该图像,图像文件路径不正确!");
		return -1;
	}
	IplImage * image1 = cvLoadImage("D:\\2.jpg", 0);			//将本地对比图导入到程序堆中
	if (image1 == NULL){										//判断是否打开成功
		printf("错误:无法打开该图像,图像文件路径不正确!");
		return -1;
	}

3.2 创建两个直方图

//创建两个直方图用于存储模板和对比图的bin
	//创建模板直方图
	int arr_size = 255;					//定义一个变量用于表示直方图行宽
	float hranges_arr[] = { 0, 255 };		//图像方块范围数组
	float *phranges_arr = hranges_arr;		//cvCreateHist参数是一个二级指针,所以要用指针指向数组然后传参
	//创建对比图的直方图
	CvHistogram *hist = cvCreateHist(1, &arr_size, CV_HIST_ARRAY, &phranges_arr, 1);//创建一个一维的直方图,行宽为255,多维密集数组,方块范围为0-255,bin均化
	int arr_size1 = 255;					//定义一个变量用于表示直方图行宽
	float hranges_arr1[] = { 0, 255 };		//图像方块范围数组
	float *phranges_arr1 = hranges_arr1;		//cvCreateHist参数是一个二级指针,所以要用指针指向数组然后传参
	CvHistogram *hist1 = cvCreateHist(1, &arr_size1, CV_HIST_ARRAY, &phranges_arr1, 1);//创建一个一维的直方图,行宽为255,多维密集数组,方块范围为0-255,bin均化3.3 计算两张图像的直方图

3.3 计算直方图大小

//计算图像的直方图大小,并保存到hist与hist1结构体中
cvCalcHist(&image, hist, 0, 0);
cvCalcHist(&image1, hist1, 0, 0);

3.4 对比直方图

//将计算后图像直方图与对比图进行比较,并将比较结果保存到Copare变量中
double Compare = cvCompareHist(hist, hist1, 0);		//使用CV_COMP_CORREL方法进行对比

3.5 将图像与对比结果显示出来

//将图像与对比结果显示出来
//创建窗口
cvNamedWindow("image_mode",0);//模板窗口
cvNamedWindow("image1",0);//对比图像窗口
//显示图像
cvShowImage("image_mode", image);
cvShowImage("image1", image1);
//打印对比结果:
printf("对比结果为:%lf", Compare);
cvWaitKey(0);		//消息循环

运行结果:

使用Opencv绘制灰度直方图/对比_第5张图片

可以看到相似度很高

完整代码:

//加载比对图
	IplImage * image = cvLoadImage("D:\\1.jpg", 0);			//将本地模板图导入到程序堆中
	if (image == NULL){										//判断是否打开成功
		printf("错误:无法打开该图像,图像文件路径不正确!");
		return -1;
	}
	IplImage * image1 = cvLoadImage("D:\\2.jpg", 0);			//将本地对比图导入到程序堆中
	if (image1 == NULL){										//判断是否打开成功
		printf("错误:无法打开该图像,图像文件路径不正确!");
		return -1;
	}
//创建两个直方图用于存储模板和对比图的bin
	//创建模板直方图
	int arr_size = 255;					//定义一个变量用于表示直方图行宽
	float hranges_arr[] = { 0, 255 };		//图像方块范围数组
	float *phranges_arr = hranges_arr;		//cvCreateHist参数是一个二级指针,所以要用指针指向数组然后传参
	//创建对比图的直方图
	CvHistogram *hist = cvCreateHist(1, &arr_size, CV_HIST_ARRAY, &phranges_arr, 1);//创建一个一维的直方图,行宽为255,多维密集数组,方块范围为0-255,bin均化
	int arr_size1 = 255;					//定义一个变量用于表示直方图行宽
	float hranges_arr1[] = { 0, 255 };		//图像方块范围数组
	float *phranges_arr1 = hranges_arr1;		//cvCreateHist参数是一个二级指针,所以要用指针指向数组然后传参
	CvHistogram *hist1 = cvCreateHist(1, &arr_size1, CV_HIST_ARRAY, &phranges_arr1, 1);//创建一个一维的直方图,行宽为255,多维密集数组,方块范围为0-255,bin均化3.3 计算两张图像的直方图
//计算图像的直方图大小,并保存到hist与hist1结构体中
cvCalcHist(&image, hist, 0, 0);
cvCalcHist(&image1, hist1, 0, 0);
//将计算后图像直方图与对比图进行比较,并将比较结果保存到Copare变量中
double Compare = cvCompareHist(hist, hist1, 0);		//使用CV_COMP_CORREL方法进行对比
//将图像与对比结果显示出来
//创建窗口
cvNamedWindow("image_mode",0);//模板窗口
cvNamedWindow("image1",0);//对比图像窗口
//显示图像
cvShowImage("image_mode", image);
cvShowImage("image1", image1);
//打印对比结果:
printf("对比结果为:%lf", Compare);
cvWaitKey(0);		//消息循环

试试看,修改以上代码,打印结果时将直方图也一并绘制出来

cvWaitKey代码前加入如下代码:

//直方图根据size分组然后根据ranges取值范围来统计图像像素点范围,也就是说ranges为0-255则将图像中像素值叠加在一起(叠加成MIN:0、MIX:255)组并分组到对应的size维中,所以size维里的每个元素非常大,所以要按比例缩小
//缩小模板直方图bin
float max_val;	//用于存储获取到的最大值
cvGetMinMaxHistValue(hist, 0, &max_val, 0, 0);		//获取直方图最大值
cvConvertScale(hist->bins, hist->bins, max_val ? 255. / max_val : 0., 0);	//按比例缩小直方图
//缩小对比直方图bin
float max_val1;	//用于存储获取到的最大值
cvGetMinMaxHistValue(hist1, 0, &max_val1, 0, 0);		//获取直方图最大值
cvConvertScale(hist1->bins, hist1->bins, max_val1 ? 255. / max_val1 : 0., 0);	//按比例缩小
IplImage *histimg = cvCreateImage(cvSize(320, 200), 8, 3);	//模板图的直方图
IplImage *histimg1 = cvCreateImage(cvSize(320, 200), 8, 3);	//对比图的直方图
//绘制模板直方图
	int bin_w; 
	bin_w = histimg->width / arr_size;//得到开始绘制点位置

	for (int i = 0; i < arr_size; i++)
	{
		double val = (cvGetReal1D(hist->bins, i)*histimg->height / 255); //获取矩阵元素值,并转换为对应高度
		CvScalar color = CV_RGB(255, 255, 0);                                 				cvRectangle(histimg, cvPoint(i*bin_w, histimg->height),
			cvPoint((i + 1)*bin_w, (int)(histimg->height - val)),
			color, 1, 8, 0);
	}

//绘制对比图直方图
	int bin_w1; 
	bin_w1 = histimg1->width / arr_size1;//得到开始绘制点位置

	for (int i = 0; i < arr_size1; i++)
	{
		double val = (cvGetReal1D(hist1->bins, i)*histimg1->height / 255); //获取矩阵元素值,并转换为对应高度
		CvScalar color = CV_RGB(255, 255, 0);                                 				cvRectangle(histimg1, cvPoint(i*bin_w1, histimg1->height),
			cvPoint((i + 1)*bin_w1, (int)(histimg1->height - val)),
			color, 1, 8, 0);
	}
//将直方图显示出来
cvShowImage("1", histimg);	//显示模板直方图
cvShowImage("2", histimg1);//显示对比直方图

运行结果:

使用Opencv绘制灰度直方图/对比_第6张图片

修改后的完整代码:

//加载比对图
	IplImage * image = cvLoadImage("D:\\1.jpg",0);			//将本地模板图导入到程序堆中
	if (image == NULL){										//判断是否打开成功
		printf("错误:无法打开该图像,图像文件路径不正确!");
		return -1;
	}
	IplImage * image1 = cvLoadImage("D:\\2.jpg",0);			//将本地对比图导入到程序堆中
	if (image1 == NULL){										//判断是否打开成功
		printf("错误:无法打开该图像,图像文件路径不正确!");
		return -1;
	}
	//创建两个直方图用于存储模板和对比图的bin
	//创建模板直方图
	int arr_size = 255;					//定义一个变量用于表示直方图行宽
	float hranges_arr[] = { 0, 255 };		//图像方块范围数组
	float *phranges_arr = hranges_arr;		//cvCreateHist参数是一个二级指针,所以要用指针指向数组然后传参
	//创建对比图的直方图
	CvHistogram *hist = cvCreateHist(1, &arr_size, CV_HIST_ARRAY, &phranges_arr, 3);//创建一个一维的直方图,行宽为255,多维密集数组,方块范围为0-255,bin均化
	int arr_size1 = 255;					//定义一个变量用于表示直方图行宽
	float hranges_arr1[] = { 0, 255 };		//图像方块范围数组
	float *phranges_arr1 = hranges_arr1;		//cvCreateHist参数是一个二级指针,所以要用指针指向数组然后传参
	CvHistogram *hist1 = cvCreateHist(1, &arr_size1, CV_HIST_ARRAY, &phranges_arr1, 3);//创建一个一维的直方图,行宽为255,多维密集数组,方块范围为0-255,bin均化3.3 计算两张图像的直方图
	//计算图像的直方图大小,并保存到hist与hist1结构体中
	cvCalcHist(&image, hist, 0, 0);
	cvCalcHist(&image1, hist1, 0, 0);
	//将计算后图像直方图与对比图进行比较,并将比较结果保存到Copare变量中
	double Compare = cvCompareHist(hist, hist1, 0);		//使用CV_COMP_CORREL方法进行对比
	//将图像与对比结果显示出来
	//创建窗口
	cvNamedWindow("image_mode",0);
	cvNamedWindow("image1",0);
	//显示图像
	cvShowImage("image_mode", image);
	cvShowImage("image1", image1);
	//打印对比结果:
	printf("对比结果为:%lf", Compare);
	//直方图根据size分组然后根据ranges取值范围来统计图像像素点范围,也就是说ranges为0-255则将图像中像素值叠加在一起(叠加成MIN:0、MIX:255)组并分组到对应的size维中,所以size维里的每个元素非常大,所以要按比例缩小
	//缩小模板直方图bin
	float max_val;	//用于存储获取到的最大值
	cvGetMinMaxHistValue(hist, 0, &max_val, 0, 0);		//获取直方图最大值
	cvConvertScale(hist->bins, hist->bins, max_val ? 255. / max_val : 0., 0);	//按比例缩小直方图
	//缩小对比直方图bin
	float max_val1;	//用于存储获取到的最大值
	cvGetMinMaxHistValue(hist1, 0, &max_val1, 0, 0);		//获取直方图最大值
	cvConvertScale(hist1->bins, hist1->bins, max_val1 ? 255. / max_val1 : 0., 0);	//按比例缩小
	IplImage *histimg = cvCreateImage(cvSize(320, 200), 8, 3);	//模板图的直方图
	IplImage *histimg1 = cvCreateImage(cvSize(320, 200), 8, 3);	//对比图的直方图
	//绘制模板直方图
	int bin_w;
	bin_w = histimg->width / arr_size;//得到开始绘制点位置

	for (int i = 0; i < arr_size; i++)
	{
		double val = (cvGetReal1D(hist->bins, i)*histimg->height / 255); //获取矩阵元素值,并转换为对应高度
		CvScalar color = CV_RGB(255, 255, 0);                                 				cvRectangle(histimg, cvPoint(i*bin_w, histimg->height),
			cvPoint((i + 1)*bin_w, (int)(histimg->height - val)),
			color, 1, 8, 0);
	}

	//绘制对比图直方图
	int bin_w1;
	bin_w1 = histimg1->width / arr_size1;//得到开始绘制点位置

	for (int i = 0; i < arr_size1; i++)
	{
		double val = (cvGetReal1D(hist1->bins, i)*histimg1->height / 255); //获取矩阵元素值,并转换为对应高度
		CvScalar color = CV_RGB(255, 255, 0);                                 				cvRectangle(histimg1, cvPoint(i*bin_w1, histimg1->height),
			cvPoint((i + 1)*bin_w1, (int)(histimg1->height - val)),
			color, 1, 8, 0);
	}
	cvShowImage("1", histimg);	//显示模板直方图
cvShowImage("2", histimg1);//显示对比直方图

	cvWaitKey(0);		//消息循环
















你可能感兴趣的:(Opencv图像处理)