1. 程式人生 > >c++圖像檢索(coarse to fine)

c++圖像檢索(coarse to fine)

elements iterator namespace load size red cond private 轉換

  //SLAM 相關,需要用到,於是寫了一個...這裏只實現了course==,不過想達到fine,也是分分鐘可以實現的,哈哈
1
#include <opencv2/core/core.hpp> 2 #include <opencv2/imgproc/imgproc.hpp> 3 #include <opencv2/highgui/highgui.hpp> 4 #include <iostream> 5 #include <cassert> 6 #include <stdlib.h> 7 #include <vector> 8
#include <string> 9 #include <iomanip> 10 #include <algorithm> 11 #include <queue> 12 #include <memory> 13 14 using namespace cv; 15 using namespace std; 16 17 class ColorHistogram 18 { 19 private: 20 int histSize[3]; 21 float hranges[2
]; 22 const float* ranges[3]; 23 int channels[3]; 24 Mat reduce; 25 public: 26 27 //構造函數 28 ColorHistogram() 29 { 30 histSize[0]= histSize[1]= histSize[2]= 64; 31 hranges[0] = 0.0; 32 hranges[1] = 255.0; 33 ranges[0] = hranges;
34 ranges[1] = hranges; 35 ranges[2] = hranges; 36 channels[0] = 0; 37 channels[1] = 1; 38 channels[2] = 2; 39 } 40 41 //計算彩色圖像直方圖 42 Mat getHistogram(const Mat& image) 43 { 44 Mat hist; 45 46 //BGR直方圖 47 hranges[0]= 0.0; 48 hranges[1]= 255.0; 49 channels[0]= 0; 50 channels[1]= 1; 51 channels[2]= 2; 52 53 //計算 54 calcHist(&image,1,channels,Mat(),hist,3,histSize,ranges); 55 return hist; 56 } 57 58 //計算顏色的直方圖 59 Mat getHueHistogram(const Mat &image) 60 { 61 Mat hist; 62 Mat hue; 63 //轉換到HSV空間 64 cvtColor(image,hue,CV_BGR2HSV); 65 66 //設置1維直方圖使用的參數 67 hranges[0] = 0.0; 68 hranges[1] = 180.0; 69 channels[0] = 0; 70 //計算直方圖 71 calcHist(&hue,1,channels,Mat(),hist,1,histSize,ranges); 72 return hist; 73 74 } 75 76 //減少顏色 77 Mat colorReduce(const Mat &image,int div = 64) 78 { 79 int n = static_cast<int>(log(static_cast<double>(div))/log(2.0)); 80 uchar mask = 0xFF<<n; 81 Mat_<Vec3b>::const_iterator it = image.begin<Vec3b>(); 82 Mat_<Vec3b>::const_iterator itend = image.end<Vec3b>(); 83 //設置輸出圖像 84 Mat result(image.rows,image.cols,image.type()); 85 Mat_<Vec3b>::iterator itr = result.begin<Vec3b>(); 86 for(;it != itend;++it,++itr) 87 { 88 (*itr)[0] = ((*it)[0]&mask) + div/2; 89 (*itr)[1] = ((*it)[1]&mask) + div/2; 90 (*itr)[2] = ((*it)[2]&mask) + div/2; 91 } 92 return result; 93 } 94 Mat getReduceHistogram(const Mat& image){ 95 96 reduce = colorReduce(image,32); 97 return getHistogram(reduce); 98 } 99 100 101 }; 102 103 104 class ImageComparator 105 { 106 private: 107 Mat reference; 108 Mat input; 109 Mat refH; 110 Mat inputH; 111 112 ColorHistogram hist; 113 int div; 114 public: 115 ImageComparator():div(32){} 116 117 void setColorReducation(int factor) 118 { 119 div = factor; 120 } 121 122 int getColorReduction() 123 { 124 return div; 125 } 126 127 void setRefrenceImage(const Mat &image) 128 { 129 reference = hist.colorReduce(image,div); 130 refH = hist.getHistogram(reference); 131 132 } 133 void setRefrenceHist(const Mat &hist1) 134 { 135 136 refH = hist1; 137 138 } 139 double compare(const Mat &image) 140 { 141 input = hist.colorReduce(image,div); 142 inputH = hist.getHistogram(input); 143 return compareHist(refH,inputH,CV_COMP_INTERSECT); 144 } 145 double comparehist(const Mat &inputH){ 146 147 return compareHist(refH,inputH,CV_COMP_INTERSECT); 148 } 149 150 }; 151 struct Node { 152 double value; 153 int idx; 154 Node (double v, int i): value(v), idx(i) {} 155 friend bool operator > (const struct Node &n1, const struct Node &n2) { 156 return n1.value > n2.value; 157 } 158 }; 159 160 161 162 class Getsimilarsulotin{ 163 public: 164 //KF的集合 165 vector<Mat>& _scenebase; 166 //待查詢圖片 167 Mat _referenceMat; 168 //結果 169 vector<pair<vector<pair<Mat,int>>,double> > res_hist_and_id_of_pic_and_scores; 170 //需要的分數最大的類的個數 171 //int _Nclass; 172 //每個可能圖片的分數 173 vector<vector<double> > imgsscores; 174 //圖像比較的對像 175 shared_ptr<ImageComparator> imgcompare=make_shared<ImageComparator>(); 176 public: 177 Getsimilarsulotin(vector<Mat>& scenebase,Mat & referenceMat):_scenebase(scenebase){ 178 _referenceMat=referenceMat.clone(); 179 imgcompare->setRefrenceImage(_referenceMat); 180 } 181 182 /* 183 * 輸入:scenebase是一個vector,裏面放的是KF的hist 184 * Ncalss最終幾個輸出分數最大的類 185 * referenceMat是帶查詢的圖片 186 * 輸出:res_hist_and_id_of_pic_and_scores是輸出(分數越小的在越後面) 187 * 其中每個元素是一個pair<類,類的分數> 188 * 類是一個一維的數組,每個元素是一個pair<hist,index> 189 * 這裏index的產生是由scenebase的順序決定的 190 */ 191 void getMostsimilar( ) 192 { 193 194 const int nImages=_scenebase.size(); 195 cout<<"start clustering..."<<endl; 196 //存放類的用二維vector存放聚類結果 197 vector<vector<pair<Mat,int>> > resofclu; 198 199 200 int startid=0; 201 vector<pair<Mat,int>> clutemp; 202 while(startid<nImages){ 203 clutemp.clear(); 204 205 Mat referenceM=_scenebase[startid]; 206 clutemp.push_back(make_pair(referenceM,startid)); 207 208 int iterid=startid+1; 209 if (iterid>=nImages){ 210 break; 211 } 212 ImageComparator* imgcompare=new(ImageComparator); 213 imgcompare->setRefrenceHist(referenceM); 214 for (;iterid<nImages;iterid++){ 215 216 if(imgcompare->comparehist(_scenebase[iterid])>0.7*imgcompare->comparehist(_scenebase[startid])){ 217 clutemp.push_back(make_pair(_scenebase[iterid],iterid)); 218 } 219 else{ 220 break; 221 } 222 } 223 resofclu.push_back(clutemp); 224 cout<<"the class has "<<clutemp.size()<<" elements"<<endl; 225 startid=iterid; 226 delete imgcompare; 227 } 228 cout<<"Done! we get "<<resofclu.size()<<" classes"<<endl; 229 230 cout<<"then we average of classes"<<endl; 231 232 233 //用於存放類的中心 234 vector<Mat> meanRes; 235 const int nclass=resofclu.size(); 236 // meanRes.resize(nclass); 237 //int iii=0; 238 for(auto resclass:resofclu){ 239 Mat Matmean=resofclu[0][0].first.clone(); 240 Matmean=Matmean*0.0; 241 for(auto sMat:resclass){ 242 Matmean=Matmean+sMat.first; 243 } 244 Matmean=Matmean+0.001; 245 Matmean=Matmean*(1.0/double(resclass.size())); 246 meanRes.push_back(Matmean); 247 } 248 249 cout<<"now we test...."<<endl; 250 251 vector<double> meanScores; 252 priority_queue<Node, vector<Node>, greater<Node>> minheap; 253 //做一個大小為_Nclass的最小堆,找出分數最大的類 254 const int _Nclass=1; 255 for (int i=0;i<_Nclass;i++){ 256 double scores=imgcompare->comparehist(meanRes[i]); 257 meanScores.push_back(scores); 258 Node Notemp(scores,i); 259 minheap.push(Notemp); 260 } 261 for(int i=_Nclass;i<nclass;i++){ 262 //當前的node 263 double scores=imgcompare->comparehist(meanRes[i]); 264 meanScores.push_back(scores); 265 Node Noteamp(scores,i); 266 // cout<<Noteamp.value<<endl; 267 if(minheap.top().value<Noteamp.value){ 268 //將這個大的數放進去 269 minheap.push(Noteamp); 270 //將堆頂最小的數彈出 271 minheap.pop(); 272 }else{ 273 continue; 274 } 275 } 276 277 cout<<"we have get the class with the maxinum score is the "<<minheap.top().idx<<"th class..."<<endl; 278 double maxscore=minheap.top().value; 279 int maxscoreindex=minheap.top().idx; 280 for(int i=0;i<nclass;i++){ 281 if(i==maxscoreindex){continue;} 282 if (meanScores[i]>0.9*maxscore){ 283 minheap.push(Node(meanScores[i],i)); 284 } 285 } 286 int _Sclass=minheap.size(); 287 cout<<"we find totally the other classes with scores > 0.9* maxscore,and the number of which is "<<_Sclass<<endl; 288 res_hist_and_id_of_pic_and_scores.resize(_Sclass); 289 for(int i=0;i<_Sclass;i++){ 290 cout<<"the score is "<< minheap.top().value<<" and the idx is "<<minheap.top().idx<<endl; 291 //最小的放最後 292 res_hist_and_id_of_pic_and_scores[_Sclass-1-i]=(make_pair(resofclu[minheap.top().idx],minheap.top().value)); 293 minheap.pop(); 294 } 295 296 297 298 299 } 300 301 //求取每個圖片與但前reference的score 302 void solvescores(){ 303 for(auto lei_and_score:res_hist_and_id_of_pic_and_scores){ 304 vector<double> scoretemp; 305 scoretemp.clear(); 306 for(auto leitemp:lei_and_score.first){ 307 scoretemp.push_back(imgcompare->comparehist(leitemp.first)); 308 309 } 310 imgsscores.push_back(scoretemp); 311 } 312 313 } 314 315 vector<vector<double> >& getscores(){ 316 return imgsscores; 317 318 319 } 320 vector<pair<vector<pair<Mat,int>>,double> > getres(){ 321 return res_hist_and_id_of_pic_and_scores; 322 } 323 324 325 }; 326 327 void showtheimage(const string& strPath,const Node& nodett){ 328 string strPrefix=strPath+"image_2/"; 329 stringstream ss; 330 ss<<setfill(0)<<setw(6)<<nodett.idx; 331 imshow("my value is"+to_string(nodett.value)+";my index is"+to_string(nodett.idx),imread(strPrefix+ss.str()+".png")); 332 333 } 334 void LoadImages(const string& strPath,const int n,vector<string>& vstrimage){ 335 string strPrefix=strPath+"image_2/"; 336 vstrimage.resize(n); 337 for(int i=0;i<n;i++){ 338 stringstream ss; 339 ss<<setfill(0)<<setw(6)<<i; 340 vstrimage[i]=strPrefix+ss.str()+".png"; 341 } 342 343 } 344 int main(int argc,char** argv) { 345 if(argc!=3){ 346 cerr<<endl<<"Usage: ./main pathtoimage numberofimages"<<endl; 347 } 348 349 350 //load image 351 352 vector<string> vstrimage; 353 LoadImages(string(argv[1]),stoi(string(argv[2])),vstrimage); 354 const int nImages=vstrimage.size(); 355 356 cout<<"start creating database...."<<endl; 357 //場景庫 358 vector<Mat> scenebase; 359 scenebase.resize(nImages); 360 Mat imtemp; 361 ColorHistogram histsolver; 362 int ii=0; 363 for(auto sPath:vstrimage){ 364 imtemp=imread(sPath); 365 Mat histtemp=histsolver.getReduceHistogram(imtemp); 366 scenebase[ii]=histtemp; 367 ii++; 368 } 369 cout<<"the database has been created..."<<"and the size of it is "<<scenebase.size()<<endl; 370 371 //待查詢圖片 372 Mat imtest=imread("../image_2/000030.png"); 373 imshow("im the reference",imtest); 374 //保存的結果 375 vector<pair<vector<pair<Mat,int>>,double> > res; 376 vector<vector<double> > imagescores; 377 //求解 378 shared_ptr<Getsimilarsulotin> gesolution=make_shared<Getsimilarsulotin>(scenebase,imtest); 379 gesolution->getMostsimilar(); 380 res=gesolution->getres(); 381 gesolution->solvescores(); 382 imagescores=gesolution->getscores(); 383 //res[0].first 可以查詢類 384 //res[0].second 可以查詢該類的分數 385 //(res[0].first)[0].first 可以查詢類的一個元素的hist 386 //(res[0].first)[0].second 可以查詢hist的index 387 //demo for 輸出結果 388 vector<Node> resofpics; 389 390 int ix=0; 391 for(auto lei_and_score:res){ 392 int iy=0; 393 cout<<"類的分數是 :"<<lei_and_score.second<<endl<<"該類中的index有這些"<<endl; 394 for(auto hist_and_index:lei_and_score.first){ 395 cout<<"index= "<<hist_and_index.second<<" "<<"score= "<<imagescores[ix][iy]<<endl; 396 397 iy++; 398 } 399 ix++; 400 } 401 402 403 404 waitKey(0); 405 return 0; 406 }

c++圖像檢索(coarse to fine)