Hugin trunk 0.1
Loading...
Searching...
No Matches
KeyPointDetector.cpp
Go to the documentation of this file.
1/*
2* Copyright (C) 2007-2008 Anael Orlinski
3*
4* This file is part of Panomatic.
5*
6* Panomatic is free software; you can redistribute it and/or modify
7* it under the terms of the GNU General Public License as published by
8* the Free Software Foundation; either version 2 of the License, or
9* (at your option) any later version.
10*
11* Panomatic is distributed in the hope that it will be useful,
12* but WITHOUT ANY WARRANTY; without even the implied warranty of
13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14* GNU General Public License for more details.
15*
16* You should have received a copy of the GNU General Public License
17* along with Panomatic; if not, write to the Free Software
18* <http://www.gnu.org/licenses/>.
19*/
20
21#include <iostream>
22
23#include "KeyPoint.h"
24#include "KeyPointDetector.h"
25#include "BoxFilter.h"
26#include "MathStuff.h"
27
28namespace lfeat
29{
30const double KeyPointDetector::kBaseSigma = 1.2;
31
33{
34 // initialize default values
35 _maxScales = 5; // number of scales : 9x9, 15x15, 21x21, 27x27, ...
36 _maxOctaves = 4; // number of octaves
37
38 _scoreThreshold = 1000;
39
41 _scaleOverlap = 3;
42
43}
44
46{
47 // allocate lots of memory for the scales
48 double** * aSH = new double**[_maxScales];
49 for (unsigned int s = 0; s < _maxScales; ++s)
50 {
51 aSH[s] = Image::AllocateImage(iImage.getWidth(), iImage.getHeight());
52 }
53
54 // init the border size
55 unsigned int* aBorderSize = new unsigned int[_maxScales];
56
57 unsigned int aMaxima = 0;
58
59 // base size + 3 times first increment for step back
60 // for the first octave 9x9, 15x15, 21x21, 27x27, 33x33
61 // for the second 21x21, 33x33, 45x45 ...
62
63 // go through all the octaves
64 for (unsigned int o = 0; o < _maxOctaves; ++o)
65 {
66 // calculate the pixel step on the image, and the image size
67 unsigned int aPixelStep = 1 << o; // 2^aOctaveIt
68 int aOctaveWidth = iImage.getWidth() / aPixelStep; // integer division
69 int aOctaveHeight = iImage.getHeight() / aPixelStep; // integer division
70
71 // fill each scale matrices
72 for (unsigned int s = 0; s < _maxScales; ++s)
73 {
74 // create a box filter of the correct size.
76
77 // calculate the border for this scale
79
80 // fill the hessians
83
85 for (int y = aBorderSize[s]; y < aEy; ++y)
86 {
87 aBoxFilter.setY(aYPS);
89 for (int x = aBorderSize[s]; x < aEx; ++x)
90 {
91 aSH[s][y][x] = aBoxFilter.getDetWithX(aXPS);
93 }
95 }
96 }
97
98 // detect the feature points with a 3x3x3 neighborhood non-maxima suppression
99 for (unsigned int aSIt = 1; aSIt < (_maxScales - 1); aSIt += 2)
100 {
101 const int aBS = aBorderSize[aSIt + 1];
102 for (int aYIt = aBS + 1; aYIt < aOctaveHeight - aBS - 1; aYIt += 2)
103 {
104 for (int aXIt = aBS + 1; aXIt < aOctaveWidth - aBS - 1; aXIt += 2)
105 {
106 // find the maximum in the 2x2x2 cube
107 double aTab[8];
108
109 // get the values in a
110 aTab[0] = aSH[aSIt][aYIt][aXIt];
111 aTab[1] = aSH[aSIt][aYIt][aXIt + 1];
112 aTab[2] = aSH[aSIt][aYIt + 1][aXIt];
113 aTab[3] = aSH[aSIt][aYIt + 1][aXIt + 1];
114 aTab[4] = aSH[aSIt + 1][aYIt][aXIt];
115 aTab[5] = aSH[aSIt + 1][aYIt][aXIt + 1];
116 aTab[6] = aSH[aSIt + 1][aYIt + 1][aXIt];
117 aTab[7] = aSH[aSIt + 1][aYIt + 1][aXIt + 1];
118
119 // find the max index without using a loop.
120 unsigned int a04 = (aTab[0] > aTab[4] ? 0 : 4);
121 unsigned int a15 = (aTab[1] > aTab[5] ? 1 : 5);
122 unsigned int a26 = (aTab[2] > aTab[6] ? 2 : 6);
123 unsigned int a37 = (aTab[3] > aTab[7] ? 3 : 7);
124 unsigned int a0426 = (aTab[a04] > aTab[a26] ? a04 : a26);
125 unsigned int a1537 = (aTab[a15] > aTab[a37] ? a15 : a37);
126 unsigned int aMaxIdx = (aTab[a0426] > aTab[a1537] ? a0426 : a1537);
127
128 // calculate approximate threshold
129 double aApproxThres = _scoreThreshold * 0.8;
130
131 double aScore = aTab[aMaxIdx];
132
133 // check found point against threshold
134 if (aScore < aApproxThres)
135 {
136 continue;
137 }
138
139 // verify that other missing points in the 3x3x3 cube are also below treshold
140 int aXShift = 2 * (aMaxIdx & 1) - 1;
141 int aXAdj = aXIt + (aMaxIdx & 1);
142 aMaxIdx >>= 1;
143
144 int aYShift = 2 * (aMaxIdx & 1) - 1;
145 int aYAdj = aYIt + (aMaxIdx & 1);
146 aMaxIdx >>= 1;
147
148 int aSShift = 2 * (aMaxIdx & 1) - 1;
149 int aSAdj = aSIt + (aMaxIdx & 1);
150
151 // skip too high scale ajusting
152 if (aSAdj == (int)_maxScales - 1)
153 {
154 continue;
155 }
156
157 if ((aSH[aSAdj + aSShift][aYAdj - aYShift][aXAdj - 1] > aScore) ||
159 (aSH[aSAdj + aSShift][aYAdj - aYShift][aXAdj + 1] > aScore) ||
160 (aSH[aSAdj + aSShift][aYAdj][aXAdj - 1] > aScore) ||
161 (aSH[aSAdj + aSShift][aYAdj][aXAdj] > aScore) ||
162 (aSH[aSAdj + aSShift][aYAdj][aXAdj + 1] > aScore) ||
163 (aSH[aSAdj + aSShift][aYAdj + aYShift][aXAdj - 1] > aScore) ||
165 (aSH[aSAdj + aSShift][aYAdj + aYShift][aXAdj + 1] > aScore) ||
166
167 (aSH[aSAdj][aYAdj + aYShift][aXAdj - 1] > aScore) ||
168 (aSH[aSAdj][aYAdj + aYShift][aXAdj] > aScore) ||
169 (aSH[aSAdj][aYAdj + aYShift][aXAdj + 1] > aScore) ||
170 (aSH[aSAdj][aYAdj][aXAdj + aXShift] > aScore) ||
172
173 (aSH[aSAdj - aSShift][aYAdj + aYShift][aXAdj - 1] > aScore) ||
175 (aSH[aSAdj - aSShift][aYAdj + aYShift][aXAdj + 1] > aScore) ||
178 )
179 {
180 continue;
181 }
182
183 // fine tune the location
184 double aX = aXAdj;
185 double aY = aYAdj;
186 double aS = aSAdj;
187
189 {
190 if (aX<aBorderSize[aSAdj + 1] || aX>aOctaveWidth - aBorderSize[aSAdj + 1] - 1)
191 {
192 continue;
193 };
194 if (aY<aBorderSize[aSAdj + 1] || aY>aOctaveHeight - aBorderSize[aSAdj + 1] - 1)
195 {
196 continue;
197 };
198 };
199 // try to fine tune, restore the values if it failed
200 // if the returned value is true, keep the point, else drop it.
202 {
203 continue;
204 }
205
206 // recheck the updated score
208 {
209 continue;
210 }
211
212 //if (aScore > 1e10)
213 //{
214 // //continue;
215 // std::cout << "big big score" << std::endl;
216 //}
217
218 // adjust the values
219 aX *= aPixelStep;
220 aY *= aPixelStep;
221 aS = ((2 * aS * aPixelStep) + _initialBoxFilterSize + (aPixelStep - 1) * _maxScales) / 3.0; // this one was hard to guess...
222
223 // store the point
224 int aTrace;
225 if (!calcTrace(iImage, aX, aY, aS, aTrace))
226 {
227 continue;
228 }
229
230 aMaxima++;
231
232 // do something with the keypoint depending on the insertor
234
235 }
236 }
237 }
238 }
239
240 // deallocate memory of the scale images
241 for (unsigned int s = 0; s < _maxScales; ++s)
242 {
243 Image::DeallocateImage(aSH[s], iImage.getHeight());
244 }
245 delete[]aSH;
246 delete[]aBorderSize;
247}
248
249bool KeyPointDetector::fineTuneExtrema(double** * iSH, unsigned int iX, unsigned int iY, unsigned int iS,
250 double& oX, double& oY, double& oS, double& oScore,
251 unsigned int iOctaveWidth, unsigned int iOctaveHeight, unsigned int iBorder)
252{
253 // maximum fine tune iterations
254 const unsigned int kMaxFineTuneIters = 6;
255
256 // shift from the initial position for X and Y (only -1 or + 1 during the iterations).
257 int aX = iX;
258 int aY = iY;
259 int aS = iS;
260
261 int aShiftX = 0;
262 int aShiftY = 0;
263
264 // current deviations
265 double aDx = 0, aDy = 0, aDs = 0;
266
267 //result vector
268 double aV[3]; //(x,y,s)
269
270 for (unsigned int aIter = 0; aIter < kMaxFineTuneIters; ++aIter)
271 {
272 // update the extrema position
273 aX += aShiftX;
274 aY += aShiftY;
275
276 // create the problem matrix
277 double aM[3][3]; //symetric, no ordering problem.
278
279 // fill the result vector with gradient from pixels differences (negate to prepare system solve)
280 aDx = (iSH[aS][aY][aX + 1] - iSH[aS][aY][aX - 1]) * 0.5;
281 aDy = (iSH[aS][aY + 1][aX] - iSH[aS][aY - 1][aX]) * 0.5;
282 aDs = (iSH[aS + 1][aY][aX] - iSH[aS - 1][aY][aX]) * 0.5;
283
284 aV[0] = -aDx;
285 aV[1] = -aDy;
286 aV[2] = -aDs;
287
288 // fill the matrix with values of the hessian from pixel differences
289 aM[0][0] = iSH[aS][aY][aX - 1] - 2.0 * iSH[aS][aY][aX] + iSH[aS][aY][aX + 1];
290 aM[1][1] = iSH[aS][aY - 1][aX] - 2.0 * iSH[aS][aY][aX] + iSH[aS][aY + 1][aX];
291 aM[2][2] = iSH[aS - 1][aY][aX] - 2.0 * iSH[aS][aY][aX] + iSH[aS + 1][aY][aX];
292
293 aM[0][1] = aM[1][0] = (iSH[aS][aY + 1][aX + 1] + iSH[aS][aY - 1][aX - 1] - iSH[aS][aY + 1][aX - 1] - iSH[aS][aY - 1][aX + 1]) * 0.25;
294 aM[0][2] = aM[2][0] = (iSH[aS + 1][aY][aX + 1] + iSH[aS - 1][aY][aX - 1] - iSH[aS + 1][aY][aX - 1] - iSH[aS - 1][aY][aX + 1]) * 0.25;
295 aM[1][2] = aM[2][1] = (iSH[aS + 1][aY + 1][aX] + iSH[aS - 1][aY - 1][aX] - iSH[aS + 1][aY - 1][aX] - iSH[aS - 1][aY + 1][aX]) * 0.25;
296
297 // solve the linear system. results are in aV. exit with error if a problem happened
299 {
300 return false;
301 }
302
303
304 // ajust the shifts with the results and stop if no significant change
305
306 if (aIter < kMaxFineTuneIters - 1)
307 {
308 aShiftX = 0;
309 aShiftY = 0;
310
311 if (aV[0] > 0.6 && aX < (int)(iOctaveWidth - iBorder - 2))
312 {
313 aShiftX++;
314 }
315 else if (aV[0] < -0.6 && aX > (int)iBorder + 1)
316 {
317 aShiftX--;
318 }
319
320 if (aV[1] > 0.6 && aY < (int)(iOctaveHeight - iBorder - 2))
321 {
322 aShiftY++;
323 }
324 else if (aV[1] < -0.6 && aY > (int)iBorder + 1)
325 {
326 aShiftY--;
327 }
328
329 if (aShiftX == 0 && aShiftY == 0)
330 {
331 break;
332 }
333 }
334 }
335
336 // update the score
337 oScore = iSH[aS][aY][aX] + 0.5 * (aDx * aV[0] + aDy * aV[1] + aDs * aV[2]);
338
339 // reject too big deviation in last step (unfinished job).
340 if (std::abs(aV[0]) > 1.5 || std::abs(aV[1]) > 1.5 || std::abs(aV[2]) > 1.5)
341 {
342 return false;
343 }
344
345 // put the last deviation (not integer :) to the output
346 oX = aX + aV[0];
347 oY = aY + aV[1];
348 oS = iS + aV[2];
349
350 return true;
351}
352
353unsigned int KeyPointDetector::getFilterSize(unsigned int iOctave, unsigned int iScale)
354{
355 unsigned int aScaleShift = 2 << iOctave;
357}
358
359unsigned int KeyPointDetector::getBorderSize(unsigned int iOctave, unsigned int iScale)
360{
361 unsigned int aScaleShift = 2 << iOctave;
362 if (iScale <= 2)
363 {
364 unsigned int aMult = (iOctave == 0 ? 1 : 2);
365 return (getFilterSize(iOctave, 1) + aMult * aScaleShift) * 3 / aScaleShift + 1;
366 }
367 return getFilterSize(iOctave, iScale) * 3 / aScaleShift + 1;
368}
369
371 double iX,
372 double iY,
373 double iScale,
374 int& oTrace)
375{
376 unsigned int aRX = hugin_utils::roundi(iX);
377 unsigned int aRY = hugin_utils::roundi(iY);
378
380
381 if (!aBox.checkBounds(aRX, aRY))
382 {
383 return false;
384 }
385
386 aBox.setY(aRY);
387 double aTrace = aBox.getDxxWithX(aRX) + aBox.getDyyWithX(aRX);
388 oTrace = (aTrace <= 0.0 ? -1 : 1);
389
390 return true;
391}
392
393} // namespace lfeat
static void DeallocateImage(double **iImagePtr, unsigned int iHeight)
Definition Image.cpp:102
static double ** AllocateImage(unsigned int iWidth, unsigned int iHeight)
Definition Image.cpp:88
bool fineTuneExtrema(double ***iSH, unsigned int iX, unsigned int iY, unsigned int iS, double &oX, double &oY, double &oS, double &oScore, unsigned int iOctaveWidth, unsigned int iOctaveHeight, unsigned int iBorder)
void detectKeypoints(Image &iImage, KeyPointInsertor &iInsertor)
unsigned int _initialBoxFilterSize
unsigned int getBorderSize(unsigned int iOctave, unsigned int iScale)
unsigned int getFilterSize(unsigned int iOctave, unsigned int iScale)
static const double kBaseSigma
bool calcTrace(Image &iImage, double iX, double iY, double iScale, int &oTrace)
int roundi(T x)
Definition hugin_math.h:73
static bool SolveLinearSystem33(double *solution, double sq[3][3])
Definition MathStuff.cpp:24
std::vector< deghosting::BImagePtr > threshold(const std::vector< deghosting::FImagePtr > &inputImages, const double threshold, const uint16_t flags)
Threshold function used for creating alpha masks for images.
Definition threshold.h:41