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