一.所需结构体
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格式的图像文件
如需要可自行保存到本地
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); //消息循环
运行结果:
完整代码:
//打开测试图
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. 准备两张图片
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); //消息循环
运行结果:
可以看到相似度很高
完整代码:
//加载比对图
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);//显示对比直方图
运行结果:
修改后的完整代码:
//加载比对图
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); //消息循环