00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include <iostream>
00025 #include <cfloat>
00026
00027 #include <boost/thread/thread.hpp>
00028
00029 #include <stdlib.h>
00030
00031 #include "KeyPoint.h"
00032 #include "KeyPointDetector.h"
00033 #include "BoxFilter.h"
00034 #include "MathStuff.h"
00035
00036 #include "threadpool.hpp"
00037
00038 using namespace parallelsurf;
00039
00040 const double parallelsurf::KeyPointDetector::kBaseSigma = 1.2;
00041
00042 KeyPointDetector::KeyPointDetector ( Image& iImage, boost::threadpool::pool &iThreadPool ) : _image( iImage ), _threadPool ( iThreadPool )
00043 {
00044
00045 _maxScales = 5;
00046 _maxOctaves = 4;
00047
00048 _scoreThreshold = 0.2;
00049
00050 _initialBoxFilterSize = 3;
00051 _scaleOverlap = 3;
00052 }
00053
00054
00055 void KeyPointDetector::detectKeyPoints ( KeyPointInsertor& iInsertor )
00056 {
00057
00058 double *** aSH = new double**[_maxScales];
00059
00060 for ( int s = 0; s < _maxScales; ++s )
00061 aSH[s] = Image::AllocateImage ( _image.getWidth(), _image.getHeight() );
00062
00063
00064 int * aBorderSize = new int[_maxScales];
00065
00066 boost::mutex aInsertorMutex;
00067
00068
00069 for ( int o = 0; o < _maxOctaves; ++o )
00070 {
00071
00072 int aPixelStep = 1 << o;
00073 int aOctaveWidth = _image.getWidth() / aPixelStep;
00074 int aOctaveHeight = _image.getHeight() / aPixelStep;
00075
00076
00077 for ( int s = 0; s < _maxScales; ++s )
00078 {
00079 aBorderSize[s] = getBorderSize ( o, s );
00080 }
00081
00082 ComputeHelper helper = { _image, aSH, o, aOctaveWidth, aOctaveHeight, aPixelStep, aBorderSize, _scoreThreshold, _initialBoxFilterSize, _maxScales, aInsertorMutex };
00083
00084
00085 for ( int s = 0; s < _maxScales; ++s )
00086 {
00087 _threadPool.schedule ( boost::bind ( &ComputeHelper::calcDet, boost::ref ( helper ), s, getFilterSize ( o, s ) ) );
00088 }
00089 _threadPool.wait();
00090
00091
00092 for ( int s = 1; s < ( _maxScales - 1 ); s += 2 )
00093 {
00094 _threadPool.schedule ( boost::bind ( &ComputeHelper::detect, boost::ref ( helper ), s, boost::ref ( iInsertor ) ) );
00095 }
00096 _threadPool.wait();
00097 }
00098
00099
00100 for ( int s = 0; s < _maxScales; ++s )
00101 Image::DeallocateImage ( aSH[s], _image.getHeight() );
00102 }
00103
00104 bool KeyPointDetector::ComputeHelper::fineTuneExtrema ( double *** iSH, int iX, int iY, int iS,
00105 double& oX, double& oY, double& oS, double& oScore,
00106 int iOctaveWidth, int iOctaveHeight, int iBorder )
00107 {
00108
00109 const int kMaxFineTuneIters = 6;
00110
00111
00112 int aX = iX;
00113 int aY = iY;
00114 int aS = iS;
00115
00116 int aShiftX = 0;
00117 int aShiftY = 0;
00118
00119
00120 double aDx = 0, aDy = 0, aDs = 0;
00121
00122
00123 double aV[3];
00124
00125 for ( int aIter = 0; aIter < kMaxFineTuneIters; ++aIter )
00126 {
00127
00128 aX += aShiftX;
00129 aY += aShiftY;
00130
00131
00132 double aM[3][3];
00133
00134
00135 aDx = ( iSH[aS ][aY ][aX+1] - iSH[aS ][aY ][aX-1] ) * 0.5;
00136 aDy = ( iSH[aS ][aY+1][aX ] - iSH[aS ][aY-1][aX ] ) * 0.5;
00137 aDs = ( iSH[aS+1][aY ][aX ] - iSH[aS-1][aY ][aX ] ) * 0.5;
00138
00139 aV[0] = - aDx;
00140 aV[1] = - aDy;
00141 aV[2] = - aDs;
00142
00143
00144 aM[0][0] = iSH[aS ][aY ][aX-1] - 2.0 * iSH[aS][aY][aX] + iSH[aS ][aY ][aX+1];
00145 aM[1][1] = iSH[aS ][aY-1][aX ] - 2.0 * iSH[aS][aY][aX] + iSH[aS ][aY+1][aX ];
00146 aM[2][2] = iSH[aS-1][aY ][aX ] - 2.0 * iSH[aS][aY][aX] + iSH[aS+1][aY ][aX ];
00147
00148 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;
00149 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;
00150 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;
00151
00152
00153 if ( !Math::SolveLinearSystem33 ( aV, aM ) )
00154 {
00155 return false;
00156 }
00157
00158
00159 if ( aIter < kMaxFineTuneIters - 1 )
00160 {
00161 aShiftX = 0;
00162 aShiftY = 0;
00163
00164 if ( aV[0] > 0.6 && aX < ( int ) ( iOctaveWidth - iBorder - 2 ) )
00165 aShiftX++;
00166 else if ( aV[0] < -0.6 && aX > ( int ) iBorder + 1 )
00167 aShiftX--;
00168
00169 if ( aV[1] > 0.6 && aY < ( int ) ( iOctaveHeight - iBorder - 2 ) )
00170 aShiftY++;
00171 else if ( aV[1] < -0.6 && aY > ( int ) iBorder + 1 )
00172 aShiftY--;
00173
00174 if ( aShiftX == 0 && aShiftY == 0 )
00175 break;
00176 }
00177 }
00178
00179
00180 oScore = iSH[aS][aY][aX] + 0.5 * ( aDx * aV[0] + aDy * aV[1] + aDs * aV[2] );
00181
00182
00183 if ( Math::Abs ( aV[0] ) > 1.5 || Math::Abs ( aV[1] ) > 1.5 || Math::Abs ( aV[2] ) > 1.5 )
00184 return false;
00185
00186
00187 oX = aX + aV[0];
00188
00189 oY = aY + aV[1];
00190
00191 oS = iS + aV[2];
00192
00193 return true;
00194 }
00195
00196 int KeyPointDetector::getFilterSize ( int iOctave, int iScale )
00197 {
00198
00199
00200
00201 int aScaleShift = 2 << iOctave;
00202 return _initialBoxFilterSize + ( aScaleShift - 2 ) * ( _maxScales - _scaleOverlap ) + aScaleShift * iScale;
00203 }
00204
00205 int KeyPointDetector::getBorderSize ( int iOctave, int iScale )
00206 {
00207 int aScaleShift = 2 << iOctave;
00208
00209 if ( iScale <= 2 )
00210 {
00211 int aMult = ( iOctave == 0 ? 1 : 2 );
00212 return ( getFilterSize ( iOctave, 1 ) + aMult * aScaleShift ) * 3 / aScaleShift + 1;
00213 }
00214
00215 return getFilterSize ( iOctave, iScale ) * 3 / aScaleShift + 1;
00216 }
00217
00218 bool KeyPointDetector::ComputeHelper::calcTrace ( Image& iImage,
00219 double iX,
00220 double iY,
00221 double iScale,
00222 int& oTrace )
00223 {
00224 int aRX = Math::Round ( iX );
00225 int aRY = Math::Round ( iY );
00226
00227 BoxFilter aBox ( 3*iScale, iImage );
00228
00229 if ( !aBox.checkBounds ( aRX, aRY ) )
00230 return false;
00231
00232 aBox.setY ( aRY );
00233
00234 double aTrace = aBox.getDxxWithX ( aRX ) + aBox.getDyyWithX ( aRX );
00235
00236 oTrace = ( aTrace <= 0.0 ? -1 : 1 );
00237
00238 return true;
00239 }
00240
00241
00242 void KeyPointDetector::ComputeHelper::calcDet ( int s, int filterSize )
00243 {
00244
00245 BoxFilter aBoxFilter ( filterSize, _image );
00246
00247
00248 const int aBS = _borderSize[ s ];
00249
00250
00251 int aEy = _octaveHeight - aBS;
00252 int aEx = _octaveWidth - aBS;
00253
00254 int aYPS = aBS * _pixelStep;
00255
00256 for ( int y = aBS; y < aEy; ++y )
00257 {
00258 aBoxFilter.setY ( aYPS );
00259 int aXPS = aBS * _pixelStep;
00260
00261 for ( int x = aBS; x < aEx; ++x )
00262 {
00263 _scaleHessian[s][y][x] = aBoxFilter.getDetWithX ( aXPS );
00264 aXPS += _pixelStep;
00265 }
00266
00267 aYPS += _pixelStep;
00268 }
00269 }
00270
00271 void KeyPointDetector::ComputeHelper::detect ( int s, KeyPointInsertor& iInsertor )
00272 {
00273 int aMaxReachableScale = s + 2;
00274 if ( aMaxReachableScale >= _maxScales )
00275 {
00276 aMaxReachableScale = _maxScales - 1;
00277 }
00278 const int aBS = _borderSize[ aMaxReachableScale ];
00279
00280 double aTab[8];
00281
00282
00283
00284
00285 for ( int aYIt = aBS + 1; aYIt < _octaveHeight - aBS - 2; aYIt += 2 )
00286 {
00287 for ( int aXIt = aBS + 1; aXIt < _octaveWidth - aBS - 2; aXIt += 2 )
00288 {
00289
00290
00291
00292 aTab[0] = _scaleHessian[s] [aYIt] [aXIt];
00293 aTab[1] = _scaleHessian[s] [aYIt] [aXIt+1];
00294 aTab[2] = _scaleHessian[s] [aYIt+1][aXIt];
00295 aTab[3] = _scaleHessian[s] [aYIt+1][aXIt+1];
00296 aTab[4] = _scaleHessian[s+1][aYIt] [aXIt];
00297 aTab[5] = _scaleHessian[s+1][aYIt] [aXIt+1];
00298 aTab[6] = _scaleHessian[s+1][aYIt+1][aXIt];
00299 aTab[7] = _scaleHessian[s+1][aYIt+1][aXIt+1];
00300
00301
00302 int a04 = ( aTab[0] > aTab[4] ? 0 : 4 );
00303 int a15 = ( aTab[1] > aTab[5] ? 1 : 5 );
00304 int a26 = ( aTab[2] > aTab[6] ? 2 : 6 );
00305 int a37 = ( aTab[3] > aTab[7] ? 3 : 7 );
00306 int a0426 = ( aTab[a04] > aTab[a26] ? a04 : a26 );
00307 int a1537 = ( aTab[a15] > aTab[a37] ? a15 : a37 );
00308 int aMaxIdx = ( aTab[a0426] > aTab[a1537] ? a0426 : a1537 );
00309
00310
00311 double aApproxThres = _scoreThreshold * 0.8;
00312
00313 double aScore = aTab[aMaxIdx];
00314
00315
00316 if ( aScore < aApproxThres )
00317 continue;
00318
00319
00320
00321
00322
00323
00324 int aXShift = 2 * ( aMaxIdx & 1 ) - 1;
00325 int aXAdj = aXIt + ( aMaxIdx & 1 );
00326
00327 aMaxIdx >>= 1;
00328
00329 int aYShift = 2 * ( aMaxIdx & 1 ) - 1;
00330 int aYAdj = aYIt + ( aMaxIdx & 1 );
00331
00332 aMaxIdx >>= 1;
00333
00334 int aSShift = 2 * ( aMaxIdx & 1 ) - 1;
00335 int aSAdj = s + ( aMaxIdx & 1 );
00336
00337
00338 if ( aSAdj == ( int ) _maxScales - 1 )
00339 continue;
00340
00341 if ( ( _scaleHessian[aSAdj + aSShift][aYAdj - aYShift][aXAdj - 1] > aScore ) ||
00342 ( _scaleHessian[aSAdj + aSShift][aYAdj - aYShift][aXAdj ] > aScore ) ||
00343 ( _scaleHessian[aSAdj + aSShift][aYAdj - aYShift][aXAdj + 1] > aScore ) ||
00344 ( _scaleHessian[aSAdj + aSShift][aYAdj ][aXAdj - 1] > aScore ) ||
00345 ( _scaleHessian[aSAdj + aSShift][aYAdj ][aXAdj ] > aScore ) ||
00346 ( _scaleHessian[aSAdj + aSShift][aYAdj ][aXAdj + 1] > aScore ) ||
00347 ( _scaleHessian[aSAdj + aSShift][aYAdj + aYShift][aXAdj - 1] > aScore ) ||
00348 ( _scaleHessian[aSAdj + aSShift][aYAdj + aYShift][aXAdj ] > aScore ) ||
00349 ( _scaleHessian[aSAdj + aSShift][aYAdj + aYShift][aXAdj + 1] > aScore ) ||
00350
00351 ( _scaleHessian[aSAdj][ aYAdj + aYShift ][aXAdj - 1] > aScore ) ||
00352 ( _scaleHessian[aSAdj][ aYAdj + aYShift ][aXAdj] > aScore ) ||
00353 ( _scaleHessian[aSAdj][ aYAdj + aYShift ][aXAdj + 1] > aScore ) ||
00354 ( _scaleHessian[aSAdj][ aYAdj ][aXAdj + aXShift] > aScore ) ||
00355 ( _scaleHessian[aSAdj][ aYAdj - aYShift ][aXAdj + aXShift] > aScore ) ||
00356
00357 ( _scaleHessian[aSAdj - aSShift][ aYAdj + aYShift ][aXAdj - 1] > aScore ) ||
00358 ( _scaleHessian[aSAdj - aSShift][ aYAdj + aYShift ][aXAdj] > aScore ) ||
00359 ( _scaleHessian[aSAdj - aSShift][ aYAdj + aYShift ][aXAdj + 1] > aScore ) ||
00360 ( _scaleHessian[aSAdj - aSShift][ aYAdj ][aXAdj + aXShift] > aScore ) ||
00361 ( _scaleHessian[aSAdj - aSShift][ aYAdj - aYShift ][aXAdj + aXShift] > aScore )
00362 )
00363 continue;
00364
00365
00366 double aX = aXAdj;
00367 double aY = aYAdj;
00368 double aS = aSAdj;
00369
00370
00371
00372 if ( !fineTuneExtrema ( _scaleHessian, aXAdj, aYAdj, aSAdj, aX, aY, aS, aScore, _octaveWidth, _octaveHeight, _borderSize[aSAdj] ) )
00373 {
00374 continue;
00375 }
00376
00377
00378 if ( aScore < _scoreThreshold )
00379 {
00380 continue;
00381 }
00382
00383
00384 aX *= _pixelStep;
00385
00386 aY *= _pixelStep;
00387
00388 aS = ( ( 2 * aS * _pixelStep ) + _initialBoxFilterSize + ( _pixelStep - 1 ) * _maxScales ) / 3.0;
00389
00390
00391 int aTrace;
00392
00393 if ( !calcTrace ( _image, aX, aY, aS, aTrace ) )
00394 {
00395 continue;
00396 }
00397
00398
00399 _insertorMutex.lock();
00400 iInsertor ( KeyPoint ( aX, aY, aS * kBaseSigma, aScore, aTrace ) );
00401 _insertorMutex.unlock();
00402 }
00403 }
00404 }