//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 }