zoukankan      html  css  js  c++  java
  • OpenCV —— 直方图与匹配

    直方图就是对数据进行统计,将统计值组织到一系列事先定义好的bin中。bin中的数值是从数据中计算出来的特征的统计量,这些数据可以是诸如梯度,方向,色彩或任何其他特征。

    直方图获得是是数据分布的统计图

    直方图的基本数据结构 CvHistogram

    创建一个新的直方图 cvCreateHist

    dims   直方图维数的数目

    sizes  直方图维数尺寸的数组

    type  直方图的表示格式: CV_HIST_ARRAY 意味着直方图数据表示为多维密集数组 CvMatND; CV_HIST_TREE 意味着直方图数据表示为多维稀疏数组 CvSparseMat.

    ranges  图中方块范围的数组. 它的内容取决于参数 uniform 的值。这个范围的用处是确定何时计算直方图或决定反向映射(backprojected ),每个方块对应于输入图像的哪个/哪组值。

    uniform  归一化标识。 如果不为0,则ranges[i](0<=i<cDims,译者注:cDims为直方图的维数,对于灰度图为1,彩色图为3)是包含两个元素的范围数组,包括直方图第i维的上界和下界。在第i维上的整个区域 [lower,upper]被分割成 dims[i] 个相等的块(译者注:dims[i]表示直方图第i维的块数),这些块用来确定输入象素的第 i 个值(译者注:对于彩色图像,i确定R, G,或者B)的对应的块;如果为0,则ranges[i]是包含dims[i]+1个元素的范围数组,包括lower0, upper0, lower1, upper1 == lower2, ..., upperdims[i]-1, 其中lowerj 和upperj分别是直方图第i维上第 j 个方块的上下界(针对输入象素的第 i 个值)。任何情况下,输入值如果超出了一个直方块所指定的范围外,都不会被 cvCalcHist 计数,而且会被函数 cvCalcBackProject 置零。

    cvSetHistBinRanges —— 在使用直方图之前给rangs设置数值

    cvSetHistRanges()

    cvClearHist  对直方图进行清零         cvReleaseHist   释放直方图

    cvMakeHistHeaderForArray  根据已给出的数据创建直方图  (直方图的内部数据类型描述永远是浮点数)

    访问直方图

    cvQueryHistValue_1D     cvQueryHistValue_2D    cvQueryHistValue_3D  每个函数都返回相应bin中的值的浮点数,同样,可以利用函数返回的bin的指针来设置直方图bin的值

    cvGetHistValue_1D   cvGetHistValue_2D 

    在稀疏直方图中,如果想利用函数 GetHist*() 来访问不存在的bin,这个不存在的bin会被自动创建,并且其值被设置为0

    直方图的基本操作

    cvNormalizeHist  归一化直方图

    cvThreshHist   直方图阈值函数,小于给定阈值的各个bin都被社为0

    cvCopyHist   将一个直方图的信息复制到另一个直方图

    cvGetMinMaxHistValue  输出直方图中找到的最小值和最大值 (如果不需要其中的一个,可以设置为NULL)

    cvCalcHist  自动从图像中计算直方图 (对于多通道图像,先要用函数cvSplit将图像分为单通道的)

    对比两个直方图

    cvCompareHist

    相关 CV_COMP_CORREL 线性相关 —— 两个向量协方差除以两个变量的标准差

    卡方 CV_COMP_CHISQR  低分比高分的匹配程度高,完全匹配的值为0

    直方图相交  CV_COMP_INTERSECT  高分表示好匹配

    Bhattacharyya  距离  CV_COMP_BHATTACHARYYA  低分表示好匹配

    在对比直方图之前,都应该自行进行归一化操作,因为如果不规一化,没有任何意义

    // 直方图的计算与显示
    
    #include <cv.h>
    #include <highgui.h>
    
    int main(int argc,char** argv)
    {
        IplImage* src=cvLoadImage("wukong.jpg",CV_LOAD_IMAGE_COLOR);
        IplImage* hsv=cvCreateImage(cvGetSize(src),8,3);
        cvCvtColor(src,hsv,CV_RGB2HSV);
    
        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=32;
        CvHistogram* hist;
    
        {
            int hist_size[]={h_bins,s_bins};
            float h_ranges[]={0,180};
            float s_ranges[]={0,255};
            float* ranges[]={h_ranges,s_ranges};
            hist=cvCreateHist(2,hist_size,CV_HIST_ARRAY,ranges,1);
        }
    
        cvCalcHist(planes,hist,0,0);
        cvNormalizeHist(hist,1.0);
    
        int scale=10;
        IplImage* hist_img=cvCreateImage(cvSize(h_bins*scale,s_bins*scale),8,3);
        cvZero(hist_img);
    
        float max_value=0;
        cvGetMinMaxHistValue(hist,0,&max_value,0,0);
    
        for (int h=0;h<h_bins;h++)
        {
            for (int s=0;s<s_bins;s++)
            {
                float bin_val=cvQueryHistValue_2D(hist,h,s);
                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,intensity,intensity),CV_FILLED);
            }
        }
    
        cvNamedWindow("w1",CV_WINDOW_AUTOSIZE);
        cvShowImage("w1",hist_img);
    
        cvWaitKey();
    
        cvReleaseImage(&hsv);
        cvReleaseImage(&h_plane);
        cvReleaseImage(&s_plane);
        cvReleaseImage(&v_plane);
        cvReleaseHist(&hist);
        cvReleaseImage(&hist_img);
        cvDestroyAllWindows();
    
    
    
        return 0;
    
    }

    陆地移动距离

    光线引起图像颜色值的漂移(没有改变颜色直方图的形状,但引起了颜色位置的变化,导致匹配策略失效)

    陆地移动距离 —— 实际上度量的是怎样将一个直方图的形状转变为另一个直方图的形状,包括移动直方图的部分到一个新的位置,可以在任何维的直方图上进行这种度量

    EMD 算法本身是一个通用的算法 —— 允许用户自己设置距离度量或者自己的移动代价矩阵  cvCalcEMD2

    #include <cv.h>
    
    #include <highgui.h>
    
    #include <IOSTREAM.H>
    
    
    
    int main(int argc, char** argv)
    
    {
    
    	IplImage *src = cvLoadImage("wukong.jpg",CV_LOAD_IMAGE_COLOR);
    
    	IplImage *hsv = cvCreateImage(cvGetSize(src),8,3);
    
    	cvCvtColor(src,hsv,CV_BGR2HSV);
    
    	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};
    
    	cvSplit(hsv,h_plane,s_plane,v_plane,0);
    
    	
    
    	//求得直方图
    
    	int h_bins=30,s_bins=32;
    
    	CvHistogram *hist1,*hist2;
    
    	int size[]={h_bins,s_bins};
    
    	float h_ranges[]={0,180};
    
    	float s_ranges[]={0,255};
    
    	float *ranges[]={h_ranges,s_ranges};
    
    	
    
    	hist1=cvCreateHist(2,size,CV_HIST_ARRAY,ranges,1);
    
    	cvCalcHist(planes,hist1,0,0);//只能一个通道一个通道的写入直方图,所以上面分成H、S、V
    
    	cvNormalizeHist(hist1,1.0);//归一化直方图,使所有块的值加起来为1
    
    	hist2=cvCreateHist(2,size,CV_HIST_ARRAY,ranges,1);
    
    	cvCalcHist(planes,hist2,0,0);
    
    	cvNormalizeHist(hist2,1.0);
    
    	
    
    	//求得signature用于比较直方图
    
    	CvMat *sig1,*sig2;
    
    	int numrows=h_bins*s_bins;
    
    	sig1=cvCreateMat(numrows,3,CV_32FC1);//由于是2维图像直方图,所以只需保存每个点的(值,横坐标,纵坐标)三个数,一共numrows个点
    
    	sig2=cvCreateMat(numrows,3,CV_32FC1);
    
    	for(int h=0;h<h_bins;h++)
    
    	{
    
    		for(int s=0;s<s_bins;s++)
    
    		{
    
    			float bin_val=cvQueryHistValue_2D(hist1,h,s);
    
    			cvSet2D(sig1,h*s_bins+s,0,cvScalar(bin_val));
    
    			cvSet2D(sig1,h*s_bins+s,1,cvScalar(h));
    
    			cvSet2D(sig1,h*s_bins+s,2,cvScalar(s));
    
    			bin_val=cvQueryHistValue_2D(hist2,h,s);
    
    			cvSet2D(sig2,h*s_bins+s,0,cvScalar(bin_val));
    
    			cvSet2D(sig2,h*s_bins+s,1,cvScalar(h));
    
    			cvSet2D(sig2,h*s_bins+s,2,cvScalar(s));
    
    		}
    
    	}
    
    	float emd=cvCalcEMD2(sig1,sig2,CV_DIST_L2);
    
    
    
    	cout<<emd<<endl;
    
    	return 0;
    
    }

    反向投影

    一种记录像素点或像素块如何适应直方图模型中分布的方式  —— 有一个颜色直方图,可以利用反向投影在图象中找到该区域

    cvCalcBackProject —— 在输入图像平面上的滑动块来设置目标图像上相应的像素(块的中心);对于归一化直方图模型来说,结果图像可以被解释为一个概率图(存储的数值代表了该像素属于皮肤区域的概率)

    可以通过 cvMinMaxLoc () 来寻找目标


    模板匹配

    cvMatchTemplate —— 在另一幅图像上移动模板图像块来寻找匹配

    CV_TM_SQDIFF 平方差匹配法

    CV_TM_CCORR 相关匹配法

    CV_TM_CCOEFF 相关匹配法

    归一化方法

    #include <cv.h>
    #include <cxcore.h>
    #include <highgui.h>
    #include <stdio.h>
    
    int main(int argc,char** argv)
    {
        IplImage *src,*templ,*ftmp[6];    // ftmp 用来保存结果
        int i;
    
        src=cvLoadImage("wukong.jgp",CV_LOAD_IMAGE_COLOR);
        templ=cvLoadImage("templ.jpg",CV_LOAD_IMAGE_COLOR);
    
        int iwidth=src->width-templ->width+1;
        int iheight=src->height-templ->height+1;
        for (i=0;i<6;i++)
        {
            ftmp[i]=cvCreateImage(cvSize(iwidth,iheight),32,1);
        }
    
        for (i=0;i<6;i++)
        {
            cvMatchTemplate(src,templ,ftmp[i],i);
            cvNormalize(ftmp[i],ftmp[i],1,0,CV_MINMAX);
        }
    
        cvNamedWindow("template",0);
        cvShowImage("template",templ);
    
        cvNamedWindow("image",0);
        cvShowImage("image",src);
    
        cvNamedWindow("sqdiff");
        cvShowImage("sqdiff",ftmp[0]);
    
        // 各种显示太烦了,不写了
    
        cvDestroyAllWindows();
    }
  • 相关阅读:
    鼠标滑动带动画下拉展开的滑动门代码
    很靓很大气的简约红色CSS菜单代码
    用Cookie来保存菜单当前位置代码
    单击单选按钮切换对应的菜单代码
    仿微软中国的滑动门导航菜单代码
    C#创建SQLServer的存储过程
    通过应用程序域AppDomain加载和卸载程序集(转载)
    多线程学习笔记一(转载)
    C#实现Treeview节点"正在载入..."效果
    JavaScript 学习笔记之函数理解二
  • 原文地址:https://www.cnblogs.com/sprint1989/p/3809001.html
Copyright © 2011-2022 走看看