1 #include "PanoDetector.h"
2 #include <iostream>
3 #include <fstream>
4 #include <boost/foreach.hpp>
5
6 #include <time.h>
7
8
9 #include "zthread/Runnable.h"
10 #include "zthread/PoolExecutor.h"
11 #include "Utils.h"
12 #include "Tracer.h"
13
14
15
16
17
18 #ifndef srandom
19 #define srandom srand
20 #endif
21
22 using namespace std;
23 using namespace ZThread;
24
PanoDetector()25 PanoDetector::PanoDetector() : _extendedSurf(true), _outputFile("default0.oto"), _surfScoreThreshold(1000),
26 _sieve1Width(10), _sieve1Height(10), _sieve1Size(10),
27 _kdTreeSearchSteps(40), _kdTreeSecondDistance(0.15), _sieve2Width(5), _sieve2Height(5),
28 _sieve2Size(1), _test(false), _cores(utils::getCPUCount()), _ransacIters(1000), _ransacDistanceThres(25),
29 _minimumMatches(4), _linearMatch(false), _linearMatchLen(1), _scale(0.5)
30 {
31
32 }
33
34
35
checkData()36 bool PanoDetector::checkData()
37 {
38 // test linear match data
39 if (_linearMatchLen < 1)
40 {
41 std::cout << "Linear match length must be at least 1." << std::endl;
42 return false;
43 }
44
45
46 // check the test mode
47 if (_test)
48 {
49 if (_files.size() != 2)
50 {
51 std::cout << "In test mode you must provide exactly 2 images." << std::endl;
52 return false;
53 }
54 }
55
56
57
58
59 return true;
60 }
61
62
printDetails()63 void PanoDetector::printDetails()
64 {
65 //cout << "\tNumber of keys : " << _numKeys << endl;
66 //cout << "\tExtended SURF : " << (_extendedSurf ? "yes":"no") << endl;
67 cout << "Output file : " << _outputFile << endl;
68 cout << "Number of CPU : " << _cores << endl << endl;
69 cout << "Input image options" << endl;
70 cout << " Scale factor : " << _scale << endl;
71 cout << "SURF Options" << endl;
72 cout << " Extended : " << (_extendedSurf?"yes":"no") << endl;
73 cout << " Score threshold : " << _surfScoreThreshold << endl;
74 cout << "Sieve 1 Options" << endl;
75 cout << " Width : " << _sieve1Width << endl;
76 cout << " Height : " << _sieve1Height << endl;
77 cout << " Size : " << _sieve1Size << endl;
78 cout << " ==> Maximum keypoints per image : " << _sieve1Size * _sieve1Height * _sieve1Width << endl;
79 cout << "KDTree Options" << endl;
80 cout << " Search steps : " << _kdTreeSearchSteps << endl;
81 cout << " Second match distance : " << _kdTreeSecondDistance << endl;
82 cout << "Matching Options" << endl;
83 cout << " Mode : " << (_linearMatch?"Linear match":"All pairs");
84 if (_linearMatch)
85 cout << " with length of " << _linearMatchLen << " image" << endl;
86 else
87 cout << endl;
88 cout << " Distance threshold : " << _ransacDistanceThres << endl;
89 cout << "RANSAC Options" << endl;
90 cout << " Iterations : " << _ransacIters << endl;
91 cout << " Distance threshold : " << _ransacDistanceThres << endl;
92 cout << "Sieve 2 Options" << endl;
93 cout << " Width : " << _sieve2Width << endl;
94 cout << " Height : " << _sieve2Height << endl;
95 cout << " Size : " << _sieve2Size << endl;
96 cout << " ==> Maximum matches per image pair : " << _sieve2Size * _sieve2Height * _sieve2Width << endl;
97
98 cout << "Input Files :" << endl;
99 BOOST_FOREACH(string& aF, _files)
100 cout << " - " << aF << endl;
101
102
103
104 }
105
106 // definition of a runnable class for ImgData
107 class ImgDataRunnable : public Runnable
108 {
109 public:
ImgDataRunnable(PanoDetector::ImgData & iImageData,const PanoDetector & iPanoDetector)110 ImgDataRunnable(PanoDetector::ImgData& iImageData, const PanoDetector& iPanoDetector) :
111 _imgData(iImageData), _panoDetector(iPanoDetector) {};
112
run()113 void run()
114 {
115 if (!PanoDetector::AnalyzeImage(_imgData, _panoDetector)) return;
116 PanoDetector::FindKeyPointsInImage(_imgData, _panoDetector);
117 PanoDetector::FilterKeyPointsInImage(_imgData, _panoDetector);
118 PanoDetector::MakeKeyPointDescriptorsInImage(_imgData, _panoDetector);
119 PanoDetector::BuildKDTreesInImage(_imgData, _panoDetector);
120 PanoDetector::FreeMemoryInImage(_imgData, _panoDetector);
121 }
122 private:
123 const PanoDetector& _panoDetector;
124 PanoDetector::ImgData& _imgData;
125 };
126
127 // definition of a runnable class for MatchData
128 class MatchDataRunnable : public Runnable
129 {
130 public:
MatchDataRunnable(PanoDetector::MatchData & iMatchData,const PanoDetector & iPanoDetector)131 MatchDataRunnable(PanoDetector::MatchData& iMatchData, const PanoDetector& iPanoDetector) :
132 _matchData(iMatchData), _panoDetector(iPanoDetector) {};
133
run()134 void run()
135 {
136 PanoDetector::FindMatchesInPair(_matchData, _panoDetector);
137 PanoDetector::RansacMatchesInPair(_matchData, _panoDetector);
138 PanoDetector::FilterMatchesInPair(_matchData, _panoDetector);
139 }
140 private:
141 const PanoDetector& _panoDetector;
142 PanoDetector::MatchData& _matchData;
143 };
144
145
run()146 void PanoDetector::run()
147 {
148 // init the random time generator
149 srandom((unsigned int)time(NULL));
150 PoolExecutor aExecutor(_cores);
151
152 // 1. prepare images
153 TRACE_INFO(endl<< "--- Analyze Images ---" << endl);
154 prepareImages();
155
156 // 2. run analysis of images
157 try
158 {
159 for (ImgDataIt_t aB = _filesData.begin(); aB != _filesData.end(); ++aB)
160 aExecutor.execute(new ImgDataRunnable(aB->second, *this));
161
162 aExecutor.wait();
163 }
164 catch(Synchronization_Exception& e)
165 {
166 TRACE_ERROR(e.what() << endl);
167 return;
168 }
169
170 // check if the load of images succeed.
171 if (!checkLoadSuccess())
172 {
173 TRACE_INFO("One or more images failed to load. Exiting.");
174 return;
175 }
176
177 // 3. prepare matches
178 prepareMatches();
179
180 // 4. find matches
181 TRACE_INFO(endl<< "--- Find matches ---" << endl);
182 try
183 {
184 BOOST_FOREACH(MatchData& aMD, _matchesData)
185 aExecutor.execute(new MatchDataRunnable(aMD, *this));
186
187 aExecutor.wait();
188 }
189 catch(Synchronization_Exception& e)
190 {
191 TRACE_ERROR(e.what() << endl);
192 return;
193 }
194
195 // 5. write output
196 TRACE_INFO(endl<< "--- Write output ---" << endl);
197 writeOutput();
198
199 }
200
prepareImages()201 void PanoDetector::prepareImages()
202 {
203 // search keypoints for each image
204 for (unsigned int aFileN = 0; aFileN < _files.size(); ++aFileN)
205 {
206 // insert an element in the map
207 _filesData.insert(make_pair(_files[aFileN], ImgData()));
208
209 // get the data
210 ImgData& aImgData = _filesData[_files[aFileN]];
211
212 // set the name
213 aImgData._name = _files[aFileN];
214
215 // give a number
216 aImgData._number = aFileN;
217
218 // analyze this image
219 //TIMETRACE("--> Analyze", AnalyzeImage(aImgData, *this));
220 }
221 }
222
checkLoadSuccess()223 bool PanoDetector::checkLoadSuccess()
224 {
225 for (unsigned int aFileN = 0; aFileN < _files.size(); ++aFileN)
226 {
227 ImgData& aID = _filesData[_files[aFileN]];
228 if (aID._loadFail)
229 return false;
230 }
231 return true;
232 }
233
234
prepareMatches()235 void PanoDetector::prepareMatches()
236 {
237 int aLen = _files.size();
238 if (_linearMatch)
239 aLen = _linearMatchLen;
240
241 if (aLen >= _files.size())
242 aLen = _files.size() - 1;
243
244 for (unsigned int i1 = 0; i1 < _files.size(); ++i1)
245 {
246 int aEnd = i1 + 1 + aLen;
247 if (_files.size() < aEnd)
248 aEnd = _files.size();
249
250 for (unsigned int i2 = (i1+1); i2 < aEnd; ++i2)
251 {
252 // create a new entry in the matches map
253 _matchesData.push_back(MatchData());
254
255 MatchData& aM = _matchesData.back();
256 aM._i1_name = _files[i1];
257 aM._i2_name = _files[i2];
258 aM._i1 = &(_filesData[aM._i1_name]);
259 aM._i2 = &(_filesData[aM._i2_name]);
260 }
261 }
262 }
263
264
265
266
267