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作为检測图片:
结果: