EMD距离详细介绍已经在在这里已经给出。
思路:我们把一张图像的归一化的一维直方图作为signature的权值,也就是一般在比较两幅图像颜色直方图的EMD距离时,每一行的坐标一样,只是权重值不一样。
通过以下程序,就可以得到一幅图像的signature:
<pre name="code" class="cpp">#include<iostream> using namespace std; #include<opencv2\core\core.hpp> #include<opencv2\highgui\highgui.hpp> #include<opencv2\imgproc\imgproc.hpp> using namespace cv; int main(int argc,char* argv[]) { Mat image,imageHsv,hist,normalHist; image = imread(argv[1],1); if(argc !=2 || !image.data) { cerr << " No image!" <<endl; return -1; } //颜色空间的转换 cvtColor(image,imageHsv,CV_BGR2HSV); //一维直方图 int hbins = 90; int histSize[] = {hbins}; float hranges[] = {0.0,180.0}; const float* ranges[] = {hranges}; int channels[] ={0}; calcHist(&imageHsv,1,channels,Mat(),hist,1,histSize,ranges,true,false); normalize(hist,normalHist,1,0,CV_L1,CV_32F); Mat signature(hbins,2,CV_32FC1); normalHist.copyTo(signature.col(0)); //把直方图的bin的索引,作为signature的第二列 for( int r=0;r < hbins; r++) signature.at<float>(r,1) =float(r); return 0; }
第二步:做检索
<pre name="code" class="cpp">#include<iostream> #include<fstream> #include<map> #include<string> using namespace std; #include<opencv2\core\core.hpp> #include<opencv2\highgui\highgui.hpp> #include<opencv2\imgproc\imgproc.hpp> using namespace cv; Mat signature(const Mat & src); int main(int argc,char* argv[]) { //定义文件流,只能读取 ifstream inPutFile(argv[1],ios::in); if(! inPutFile) { cerr <<"File Open Erro !"<<endl; return -1; } //读取文件流中的每一行,并赋值给fileName,形成查询数据库 string fileName; Mat image,imageSignature,sourceSignature; vector<Mat> signatures; map<int,string> index;//图像的索引 index.clear(); int number = 0; signatures.clear(); while(getline(inPutFile,fileName)) { index.insert(pair<int,string>(number,fileName)); number++; image = imread(fileName,1); imageSignature = signature(image); signatures.push_back(imageSignature); } //待搜索的图像 number = 0; Mat imageSource = imread(argv[2],1); sourceSignature = signature(imageSource); vector<Mat>::iterator iter; map<float,int> distance; for(iter = signatures.begin();iter != signatures.end();iter ++) { distance.insert(pair<float,int>(EMD(sourceSignature,*iter,CV_DIST_L2,number),number)); number ++; } //显示距离最小的前五名的检索图像 number = 0; map<float,int>::iterator mapiter; for(mapiter = distance.begin();mapiter != distance.end() && number <5;mapiter++,number++) { string simage = index.find((*mapiter).second)->second; image = imread(simage,1); namedWindow(simage,1); imshow(simage,image); } waitKey(0); return 0; } Mat signature(const Mat & src) { Mat hsv,hist,normalHist; //颜色空间转换 cvtColor(src,hsv,CV_BGR2HSV); //一维直方图 int hbins = 90; int histSize[] = {hbins}; float hranges[] = {0.0,180.0}; const float* ranges[] = {hranges}; int channels[] ={0}; calcHist(&hsv,1,channels,Mat(),hist,1,histSize,ranges,true,false); normalize(hist,normalHist,1,0,CV_L1,CV_32F); Mat signature(hbins,2,CV_32FC1);; normalHist.copyTo(signature.col(0)); //把直方图bin的索引,作为signature的第二列 for( int r=0;r < hbins; r++) signature.at<float>(r,1) =float(r); return signature; }
检测图片:
我们选取y2作为检测图片:
结果: