11/03/2014

OpenCV EMD(earth mover distance) example source code

EMD(earth mover distance) method is very good method to compare image similarity.
But processing time is slow.
For using the EMD compare, we should make signature value.
The EMD method compares two signatures value.

Firstly, we prepare histograms of 2 images.
And convert values of histrogram to signature.

A configuration of signature values is very simple.

bins value, x index, y index.
bins value, x index, y index.
bins value, x index, y index.
bins value, x index, y index.
bins value, x index, y index.
....

Of course this type is in case of 2d histogram.
More detail, see the source code.

In here I cannot explain earth mover distance algorithm.
please refer to internet information.

thank you.


origin images
 
result


...
#include < iostream>
#include < vector>

#include < stdio.h>      
#include < opencv2\opencv.hpp>    


#ifdef _DEBUG           
#pragma comment(lib, "opencv_core249d.lib")   
#pragma comment(lib, "opencv_imgproc249d.lib")   //MAT processing   
#pragma comment(lib, "opencv_highgui249d.lib")   
#else   
#pragma comment(lib, "opencv_core249.lib")   
#pragma comment(lib, "opencv_imgproc249.lib")      
#pragma comment(lib, "opencv_highgui249.lib")   
#endif   


using namespace cv;   
using namespace std;   
  
  
  
int main()   
{   

 //read 2 images for histogram comparing   
 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////   
 Mat imgA, imgB;   
 imgA = imread(".\\image1.jpg");   
 imgB = imread(".\\image2.jpg");   


 imshow("img1", imgA);
 imshow("img2", imgB);


 //variables preparing   
 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////   
 int hbins = 30, sbins = 32;    
 int channels[] = {0,  1};   
 int histSize[] = {hbins, sbins};   
 float hranges[] = { 0, 180 };   
 float sranges[] = { 0, 255 };   
 const float* ranges[] = { hranges, sranges};    

 Mat patch_HSV;   
 MatND HistA, HistB;   

 //cal histogram & normalization   
 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////   
 cvtColor(imgA, patch_HSV, CV_BGR2HSV);   
 calcHist( &patch_HSV, 1, channels,  Mat(), // do not use mask   
  HistA, 2, histSize, ranges,   
  true, // the histogram is uniform   
  false );   
 normalize(HistA, HistA,  0, 1, CV_MINMAX);   


 cvtColor(imgB, patch_HSV, CV_BGR2HSV);   
 calcHist( &patch_HSV, 1, channels,  Mat(),// do not use mask   
  HistB, 2, histSize, ranges,   
  true, // the histogram is uniform   
  false );   
 normalize(HistB, HistB, 0, 1, CV_MINMAX);   

 //compare histogram   
 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////   
 int numrows = hbins * sbins;

 //make signature
 Mat sig1(numrows, 3, CV_32FC1);
 Mat sig2(numrows, 3, CV_32FC1);

 //fill value into signature
 for(int h=0; h< hbins; h++)
 {
  for(int s=0; s< sbins; ++s)
  {
   float binval = HistA.at< float>(h,s);
   sig1.at< float>( h*sbins + s, 0) = binval;
   sig1.at< float>( h*sbins + s, 1) = h;
   sig1.at< float>( h*sbins + s, 2) = s;

   binval = HistB.at< float>(h,s);
   sig2.at< float>( h*sbins + s, 0) = binval;
   sig2.at< float>( h*sbins + s, 1) = h;
   sig2.at< float>( h*sbins + s, 2) = s;
  }
 }

 //compare similarity of 2images using emd.
 float emd = cv::EMD(sig1, sig2, CV_DIST_L2); //emd 0 is best matching. 
 printf("similarity %5.5f %%\n", (1-emd)*100 );
 
 waitKey(0);   

 return 0;   
}  

...

No comments:

Post a Comment