学习OpenCV——EMD算法

 

 

//adapted by the example of leanring opencv by mikewolf
//2008-11-26
#include "stdafx.h"
#include <cv.h>
#include <highgui.h>

int _tmain(int argc, _TCHAR* argv[])
{
   IplImage* src, *src1;


   src=cvLoadImage("lena.jpg", 1);
   src1=cvLoadImage("lena3.jpg", 1);

   // Compute the HSV image and decompose it into separate planes.
   //
   IplImage* hsv = cvCreateImage( cvGetSize(src), 8, 3 );
   IplImage* hsv1 = cvCreateImage( cvGetSize(src), 8, 3 );
   cvCvtColor( src, hsv, CV_BGR2HSV );
   cvCvtColor( src1, hsv1, 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* h_plane1 = cvCreateImage( cvGetSize(src), 8, 1 );
   IplImage* s_plane1 = cvCreateImage( cvGetSize(src), 8, 1 );
   IplImage* v_plane1 = cvCreateImage( cvGetSize(src), 8, 1 );
   IplImage* planes[] = { h_plane, s_plane,v_plane };
   IplImage* planes1[] = { h_plane1, s_plane1,v_plane1 };
   cvCvtPixToPlane( hsv, h_plane, s_plane, v_plane, 0 );
   cvCvtPixToPlane( hsv1, h_plane1, s_plane1, v_plane1, 0 );
   // Build the histogram and compute its contents.
   //计算规模与h_bins*s_bins*v_bins成指数关系,原先 int h_bins = 32, s_bins = 30, v_bins = 8 时,运行半天都没反应
   int h_bins = 8, s_bins = 5, v_bins = 5;  
   CvHistogram* hist, *hist1;
   {
      int hist_size[] = { h_bins, s_bins ,v_bins};
      float h_ranges[] = { 0, 180 }; // hue is [0,180]
      float s_ranges[] = { 0, 255 };
      float v_ranges[] = { 0, 255 };
      float* ranges[] = { h_ranges, s_ranges ,v_ranges};
      hist = cvCreateHist(
         3,
         hist_size,
         CV_HIST_ARRAY,
         ranges,
         1
         );
      hist1 = cvCreateHist(
         3,
         hist_size,
         CV_HIST_ARRAY,
         ranges,
         1
         );
   }
   cvCalcHist( planes, hist, 0, 0 ); //Compute histogram
   cvNormalizeHist( hist, 1.0 ); //Normalize it
   cvCalcHist( planes1, hist1, 0, 0 ); //Compute histogram
   cvNormalizeHist( hist1, 1.0 ); //Normalize it

   CvMat* sig1,*sig2;
   int numrows = h_bins*s_bins*v_bins;
   //Create matrices to store the signature in
   //
   sig1 = cvCreateMat(numrows, 4, CV_32FC1); 
   sig2 = cvCreateMat(numrows, 4, CV_32FC1); 
   int h,s,v;
   for( h = 0; h < h_bins; h++ ) 
   {
      for( s = 0; s < s_bins; s++ )
      {
         for( v=0; v < v_bins; v++)
         {
            float bin_val = cvQueryHistValue_3D( hist, h, s,v );
            
            cvSet2D(sig1,h*s_bins*v_bins + s*v_bins+v,0,cvScalar(bin_val)); //bin value
            cvSet2D(sig1,h*s_bins*v_bins + s*v_bins+v,1,cvScalar(h)); //Coord 1
            cvSet2D(sig1,h*s_bins*v_bins + s*v_bins+v,2,cvScalar(s)); //Coord 2
            cvSet2D(sig1,h*s_bins*v_bins + s*v_bins+v,3,cvScalar(v)); //Coord 3

            bin_val = cvQueryHistValue_3D( hist1, h, s,v );
            cvSet2D(sig2,h*s_bins*v_bins + s*v_bins+v,0,cvScalar(bin_val)); //bin value
            cvSet2D(sig2,h*s_bins*v_bins + s*v_bins+v,1,cvScalar(h)); //Coord 1
            cvSet2D(sig2,h*s_bins*v_bins + s*v_bins+v,2,cvScalar(s)); //Coord 2
            cvSet2D(sig2,h*s_bins*v_bins + s*v_bins+v,3,cvScalar(v)); //Coord 3

         }
      }
   }
    
   float emd = cvCalcEMD2(sig1,sig2,CV_DIST_L2);
   printf("相似度为:%3.1f%%",(1-emd)*100);

   cvNamedWindow( "Source1", 1 );
   cvMoveWindow("Source1", 0, 0);
   cvShowImage( "Source1", src );
   cvNamedWindow( "Source2", 1 );
   cvMoveWindow("Source2", 550, 0);
   cvShowImage( "Source2", src1 );
   cvWaitKey(0);

   return 0;
}



CalcEMD2
两个加权点集之间计算最小工作距离

float cvCalcEMD2( const CvArr* signature1, const CvArr* signature2, int distance_type,
                                  CvDistanceFunction distance_func=NULL, const CvArr* cost_matrix=NULL,
                                  CvArr* flow=NULL, float* lower_bound=NULL, void* userdata=NULL );
                                  typedef float (*CvDistanceFunction)(const float* f1, const float* f2, void* userdata);


signature1
第一个签名,大小为 size1×(dims+1) 的浮点数矩阵,每一行依次存储点的权重和点的坐标。矩阵允许只有一列(即仅有权重),如果使用用户自定义的代价矩阵。
signature2
第二个签名,与 signature1 的格式一样size2×(dims+1),尽管行数可以不同(列数要相同)。当一个额外的虚拟点加入 signature1 或 signature2 中的时候,权重也可不同。
distance_type
使用的准则, CV_DIST_L1, CV_DIST_L2, 和 CV_DIST_C 分别为标准的准则。 CV_DIST_USER 意味着使用用户自定义函数 distance_func 或预先计算好的代价矩阵 cost_matrix 。
distance_func
用户自定义的距离函数。用两个点的坐标计算两点之间的距离。
cost_matrix
自定义大小为 size1×size2 的代价矩阵。 cost_matrix 和 distance_func 两者至少有一个必须为 NULL. 而且,如果使用代价函数,下边界无法计算,因为它需要准则函数。
flow
产生的大小为 size1×size2 流矩阵(flow matrix): flowij 是从 signature1 的第 i 个点到 signature2 的第 j 个点的流(flow)。
lower_bound
可选的输入/输出参数:两个签名之间的距离下边界,是两个质心之间的距离。如果使用自定义代价矩阵,点集的所有权重不等,或者有签名只包含权重(即该签名矩阵只有单独一列),则下边界也许不会计算。用户必须初始化 *lower_bound. 如果质心之间的距离大于获等于 *lower_bound (这意味着签名之间足够远), 函数则不计算 EMD. 任何情况下,函数返回时 *lower_bound 都被设置为计算出来的质心距离。因此如果用户想同时计算质心距离和T EMD, *lower_bound 应该被设置为 0.
userdata
传输到自定义距离函数的可选数据指针
函数 cvCalcEMD2 计算两个加权点集之间的移动距离或距离下界。在 [RubnerSept98] 中所描述的其中一个应用就是图像提取得多维直方图比较。 EMD 是一个使用某种单纯形算法(simplex algorithm)来解决的交通问题。其计算复杂度在最坏情况下是指数形式的,但是平均而言它的速度相当快。对实的准则,下边界的计算可以更快(使用线性时间算法),且它可用来粗略确定两个点集是否足够远以至无法联系到同一个目标上

你可能感兴趣的:(Algorithm,算法,null,float,Matrix,distance)