opencv第七章-直方图与匹配
一、基本概念
在分析图像、物体和视频信息的过程中,我们常常想把眼中看到的物体用直方图表示。直方图可以用来描述各种不同的事情,如物体的色彩分布、物体边缘梯度模板,以及表示目标位置的当前假设(目标当前位置的假设?)的概率分布。
设置一个摄像机,该摄像机观察人的各种手势以控制网络视频。在每帧中,从输入的视频中检测感兴趣的色彩区域,然后计算这些感兴趣区域周围的边缘梯度方向,将得到的边缘梯度方向放到一个方向直方图相应的bin中,然后将该直方图与手势模板进行匹配,从而识别出各种手势。
直方图广泛应用于很多计算机视觉应用中。通过标记帧与帧之间显著的边缘和颜色的统计变化,直方图被用来检测视频中场景的变换。通过为每个兴趣点设置一个有相近特征的直方图所构成的“标签”,用以确定图像中的兴趣点。边缘、色彩、角等直方图构成了可以被传递给目标识别分类器的一个通用特征类型。色彩和边缘的直方图序列还可以用来识别网络视频是否被复制等。直方图是计算机视觉中最经典的工具之一。
简单地说,直方图就是对数据进行统计,将统计值组织到一系列事先定义好的bin中。bin中的数值是从数据中计算出的特征的统计量,这些数据可以是诸如梯度、方向、色彩或任何其他特征。无论如何,直方图获得的是数据分布的统计图。通常直方图的维数要低于原始数据。
表示连续分布的直方图通过隐式计算每个网格单元中点的均值来实现前面的功能。这就会产生一个问题。如果网格太宽,则参与计算平均值的点太多,就会丧失分布的结构。如果网格太窄,则没有足够的点来准确表示分布而且我们会得到小而尖锐的单元。
opencv有表征直方图的数据类型。该直方图数据结构能够以一维或者多维的方式表示直方图,并且包含所有可能跟踪的均匀或非均匀的bin中的数据。并且,如我们所期待的,它可以配属各种有用的函数,使得我们能够在直方图上容易地进行各种常见操作。
二、直方图的基本数据结构
(1)CvHistogram 是个直方图数据结构。
(2)cvCreateHist 创建一个直方图
(3)cvSetHistBinRanges 设置直方图中的ranges值
(4)cvClearHist 直方图的bins清0
(5)cvMakeHistHeaderForArray 根据已给出的数据创建直方图
三、访问直方图
cvQueryHistValue_1D
cvQueryHistValue_2D
cvQueryHistValue_3D
cvQueryHistValue_nD
四、直方图的基本操作
cvNormalizeHist 直方图的归一化
cvThreshHist 直方图阈值化
cvCopyHist 复制直方图
cvGetMInMaxHistValue 直方图中最大值最小值
cvCalcHist 计算直方图的总像素点(处理单通道图像)
五、例程
#include <cv.h>
#include <highgui.h>
#include <iostream>
#include <cxcore.h>
using namespace std;
using namespace cv;
int main()
{
IplImage *src=cvLoadImage("f.jpg");
cout<<"total_pixel : "<<src->width*src->height<<endl;
assert(src);
IplImage *hsv=cvCreateImage(cvGetSize(src),8,3);
cvCvtColor(src,hsv,CV_BGR2HSV);//转换为hsv格式
IplImage *h_plane = cvCreateImage(cvGetSize(src),8,1);
IplImage *s_plane = cvCreateImage(cvGetSize(src),8,1);
IplImage *v_plane = cvCreateImage(cvGetSize(src),8,1);
IplImage *planes[] = {h_plane,s_plane};
cvCvtPixToPlane(hsv,h_plane,s_plane,v_plane,0);//分割多通道数组
int h_bins=30,s_bins=40;
int hist_size[]={h_bins,s_bins};
float h_ranges[]={0,256};
float s_ranges[]={0,256};
float *ranges[]={h_ranges,s_ranges};
int scale = 10;
IplImage *hist_img = cvCreateImage(cvSize(h_bins*scale,s_bins*scale),8,3);
CvHistogram *hist;
float max_value = 0;
int h,s;
hist = cvCreateHist(2,hist_size,CV_HIST_ARRAY,ranges,1);
cvCalcHist(planes,hist,0,0);
cvGetMinMaxHistValue(hist,0,&max_value,0,0);
cvZero(hist_img);
float cnt=0;
for(h=0;h<h_bins;h++)
{
for(s=0;s<s_bins;s++)
{
float bin_val=cvQueryHistValue_2D(hist,h,s);
cnt += bin_val;
int intensity = cvRound(bin_val*255/max_value);
cvRectangle(hist_img,cvPoint(h*scale,s*scale),
cvPoint((h+1)*scale - 1,(s+1)*scale - 1),
CV_RGB(intensity,0,0),
CV_FILLED);
}
}
cout<<"cnt = "<<cnt<<endl;
cvShowImage("h_s histogram " ,hist_img);
cvShowImage("src",src);
cvSaveImage("h_s histogram.bmp",hist_img);
cvWaitKey();
cvReleaseHist(&hist);
cvReleaseImage(&src);
cvReleaseImage(&hist_img);
cvDestroyAllWindows();
}
详细过程不细说,总结一下直方图流程:
(1)确定直方图的维数dims(1,2,3,4)。
(2)确定一个整数数组sizes[],数组长度等于dims,数组中的每一个整数表示分配给对应维数的bin的个数。
(3)确定type是密集多维矩阵结构还是稀疏矩阵。
(4)ranges为范围划分,bin里面像素划分
(5)uniform=1