📄 sift.cpp
字号:
filter = 0 ; if( octaves ) { for(int o = 0 ; o < O ; ++o) { delete [] octaves[ o ] ; } delete [] octaves ; } octaves = 0 ; if( temp ) { delete [] temp ; } temp = 0 ; }// ===================================================================// getKeypoint// -------------------------------------------------------------------/** @brief Get keypoint from position and scale ** ** The function returns a keypoint with a given position and ** scale. Note that the keypoint structure contains fields that make ** sense only in conjunction with a specific scale space. Therefore ** the keypoint structure should be re-calculated whenever the filter ** is applied to a new image, even if the parameters @a x, @a y and ** @a sigma do not change. ** ** @param x x coordinate of the center. ** @peram y y coordinate of the center. ** @param sigma scale. ** @return Corresponing keypoint. **/Sift::KeypointSift::getKeypoint(VL::float_t x, VL::float_t y, VL::float_t sigma) const{ // keypoints are restricted to have // * si in the range smin+1 smax-2 // * o in the range omin,omin+O-1 // // Depending on the values of smin and smax, often the same // keypoint can have multiple equivalent indexes si,o. In this // case we choose the one with biggest index o (save computation). // // In addition, we relax a bit the requirements on si. We start by // letting si vary in the range smin,smax-1 and we compute both o // and si. Then we clamp si to the range smin+1,smax-2. This allows // us to be more consistent with the way SIFT descriptors are // usually generated (indeed for the SIFT detector si is always in // the range smin+1,smax-2, but in some cases round(s) != s because // of the quadratic interpolation in scale). /* We do this in steps. Let phi=log2(sigma/sigma0) 1) find max o : o+smin/S < phi, i.e. o=floor(phi+smin/S). 2) clamp this vlaue to the range [omin,omin+O-1] 3) compute the fractional scale index s = S(phi-o) 4) round the fractional scale index to get si = round(s) 5) clamp si to the range [smin+1,smax-2] */ int o,ix,iy,is ; VL::float_t s,phi ; phi = log2(sigma/sigma0) ; o = fast_floor( phi + VL::float_t(smin)/S ) ; o = std::min(o,omin+O-1) ; o = std::max(o,omin) ; s = S*(phi-o) ; is = int(s + 0.5) ; is = std::max(is,smax-2) ; is = std::min(is,smin+1) ; VL::float_t per = getOctaveSamplingPeriod(o) ; ix = int(x * per + 0.5) ; iy = int(y * per + 0.5) ; Keypoint key ; key.o = o ; key.ix = ix ; key.iy = iy ; key.is = is ; key.x = x ; key.y = y ; key.s = s ; key.sigma = sigma ; return key ;}// ===================================================================// process()// -------------------------------------------------------------------/** @brief Compute Gaussian Scale Space ** ** The method computes the Gaussian scale space of the specified ** image. The scale space data is managed internally and can be ** accessed by means of getOctave() and getLevel(). ** ** @remark Calling this method will delete the list of keypoints ** constructed by detectKeypoints(). ** ** @param _im_pt pointer to image data. ** @param _width image width. ** @param _height image height . **/voidSift::process(const pixel_t* _im_pt, int _width, int _height){ using namespace Detail ; width = _width ; height = _height ; prepareBuffers() ; VL::float_t sigmak = powf(2.0f, 1.0 / S) ; VL::float_t dsigma0 = sigma0 * sqrt (1.0f - 1.0f / (sigmak*sigmak) ) ; // ----------------------------------------------------------------- // Make pyramid base // ----------------------------------------------------------------- if( omin < 0 ) { copyAndUpsampleRows(temp, _im_pt, width, height ) ; copyAndUpsampleRows(octaves[0], temp, height, 2*width ) ; for(int o = omin + 1 ; o < 0 ; ++o) { copyAndUpsampleRows(temp, octaves[0], width << -o, height << -o) ; copyAndUpsampleRows(octaves[0], temp, height << -o, 2*(width << -o)) ; } } else if( omin > 0 ) { copyAndDownsample(octaves[0], _im_pt, width, height, 1 << omin) ; } else { copy(octaves[0], _im_pt, width, height) ; } { VL::float_t sa = sigma0 * powf(sigmak, smin) ; VL::float_t sb = sigman / powf(2.0f, omin) ; // review this if( sa > sb ) { VL::float_t sd = sqrt ( sa*sa - sb*sb ) ; smooth( octaves[0], temp, octaves[0], getOctaveWidth(omin), getOctaveHeight(omin), sd ) ; } } // ----------------------------------------------------------------- // Make octaves // ----------------------------------------------------------------- for(int o = omin ; o < omin+O ; ++o) { // Prepare octave base if( o > omin ) { int sbest = std::min(smin + S, smax) ; copyAndDownsample(getLevel(o, smin ), getLevel(o-1, sbest), getOctaveWidth(o-1), getOctaveHeight(o-1), 2 ) ; VL::float_t sa = sigma0 * powf(sigmak, smin ) ; VL::float_t sb = sigma0 * powf(sigmak, sbest - S ) ; if(sa > sb ) { VL::float_t sd = sqrt ( sa*sa - sb*sb ) ; smooth( getLevel(o,0), temp, getLevel(o,0), getOctaveWidth(o), getOctaveHeight(o), sd ) ; } } // Make other levels for(int s = smin+1 ; s <= smax ; ++s) { VL::float_t sd = dsigma0 * powf(sigmak, s) ; smooth( getLevel(o,s), temp, getLevel(o,s-1), getOctaveWidth(o), getOctaveHeight(o), sd ) ; } }}/** @brief Sift detector ** ** The function runs the SIFT detector on the stored Gaussian scale ** space (see process()). The detector consists in three steps ** ** - local maxima detection; ** - subpixel interpolation; ** - rejection of weak keypoints (@a threhsold); ** - rejection of keypoints on edge-like structures (@a edgeThreshold). ** ** As they are found, keypoints are added to an internal list. This ** list can be accessed by means of the member functions ** getKeypointsBegin() and getKeypointsEnd(). The list is ordered by ** octave, which is usefult to speed-up computeKeypointOrientations() ** and computeKeypointDescriptor(). **/voidSift::detectKeypoints(VL::float_t threshold, VL::float_t edgeThreshold){ keypoints.clear() ; int nValidatedKeypoints = 0 ; // Process one octave per time for(int o = omin ; o < omin + O ; ++o) { int const xo = 1 ; int const yo = getOctaveWidth(o) ; int const so = getOctaveWidth(o) * getOctaveHeight(o) ; int const ow = getOctaveWidth(o) ; int const oh = getOctaveHeight(o) ; VL::float_t xperiod = getOctaveSamplingPeriod(o) ; // ----------------------------------------------------------------- // Difference of Gaussians // ----------------------------------------------------------------- pixel_t* dog = temp ; tempIsGrad = false ; { pixel_t* pt = dog ; for(int s = smin ; s <= smax-1 ; ++s) { pixel_t* srca = getLevel(o, s ) ; pixel_t* srcb = getLevel(o, s+1) ; pixel_t* enda = srcb ; while( srca != enda ) { *pt++ = *srcb++ - *srca++ ; } } } // ----------------------------------------------------------------- // Find points of extremum // ----------------------------------------------------------------- { pixel_t* pt = dog + xo + yo + so ; for(int s = smin+1 ; s <= smax-2 ; ++s) { for(int y = 1 ; y < oh - 1 ; ++y) { for(int x = 1 ; x < ow - 1 ; ++x) { pixel_t v = *pt ; // assert( (pt - x*xo - y*yo - (s-smin)*so) - dog == 0 ) ; #define CHECK_NEIGHBORS(CMP,SGN) \ ( v CMP ## = SGN 0.8 * threshold && \ v CMP *(pt + xo) && \ v CMP *(pt - xo) && \ v CMP *(pt + so) && \ v CMP *(pt - so) && \ v CMP *(pt + yo) && \ v CMP *(pt - yo) && \ \ v CMP *(pt + yo + xo) && \ v CMP *(pt + yo - xo) && \ v CMP *(pt - yo + xo) && \ v CMP *(pt - yo - xo) && \ \ v CMP *(pt + xo + so) && \ v CMP *(pt - xo + so) && \ v CMP *(pt + yo + so) && \ v CMP *(pt - yo + so) && \ v CMP *(pt + yo + xo + so) && \ v CMP *(pt + yo - xo + so) && \ v CMP *(pt - yo + xo + so) && \ v CMP *(pt - yo - xo + so) && \ \ v CMP *(pt + xo - so) && \ v CMP *(pt - xo - so) && \ v CMP *(pt + yo - so) && \ v CMP *(pt - yo - so) && \ v CMP *(pt + yo + xo - so) && \ v CMP *(pt + yo - xo - so) && \ v CMP *(pt - yo + xo - so) && \ v CMP *(pt - yo - xo - so) ) if( CHECK_NEIGHBORS(>,+) || CHECK_NEIGHBORS(<,-) ) { Keypoint k ; k.ix = x ; k.iy = y ; k.is = s ; keypoints.push_back(k) ; } pt += 1 ; } pt += 2 ; } pt += 2*yo ; } } // ----------------------------------------------------------------- // Refine local maxima // ----------------------------------------------------------------- { // refine KeypointsIter siter ; KeypointsIter diter ; for(diter = siter = keypointsBegin() + nValidatedKeypoints ; siter != keypointsEnd() ; ++siter) { int x = int( siter->ix ) ; int y = int( siter->iy ) ; int s = int( siter->is ) ; VL::float_t Dx=0,Dy=0,Ds=0,Dxx=0,Dyy=0,Dss=0,Dxy=0,Dxs=0,Dys=0 ; VL::float_t b [3] ; pixel_t* pt ; int dx = 0 ; int dy = 0 ; // must be exec. at least once for(int iter = 0 ; iter < 5 ; ++iter) { VL::float_t A[3*3] ; x += dx ; y += dy ; pt = dog + xo * x + yo * y + so * (s - smin) ;#define at(dx,dy,ds) (*( pt + (dx)*xo + (dy)*yo + (ds)*so))#define Aat(i,j) (A[(i)+(j)*3]) /* Compute the gradient. */ Dx = 0.5 * (at(+1,0,0) - at(-1,0,0)) ; Dy = 0.5 * (at(0,+1,0) - at(0,-1,0)); Ds = 0.5 * (at(0,0,+1) - at(0,0,-1)) ; /* Compute the Hessian. */ Dxx = (at(+1,0,0) + at(-1,0,0) - 2.0 * at(0,0,0)) ; Dyy = (at(0,+1,0) + at(0,-1,0) - 2.0 * at(0,0,0)) ; Dss = (at(0,0,+1) + at(0,0,-1) - 2.0 * at(0,0,0)) ; Dxy = 0.25 * ( at(+1,+1,0) + at(-1,-1,0) - at(-1,+1,0) - at(+1,-1,0) ) ; Dxs = 0.25 * ( at(+1,0,+1) + at(-1,0,-1) - at(-1,0,+1) - at(+1,0,-1) ) ; Dys = 0.25 * ( at(0,+1,+1) + at(0,-1,-1) - at(0,-1,+1) - at(0,+1,-1) ) ; /* Solve linear system. */ Aat(0,0) = Dxx ; Aat(1,1) = Dyy ; Aat(2,2) = Dss ; Aat(0,1) = Aat(1,0) = Dxy ; Aat(0,2) = Aat(2,0) = Dxs ; Aat(1,2) = Aat(2,1) = Dys ; b[0] = - Dx ; b[1] = - Dy ; b[2] = - Ds ; // Gauss elimination for(int j = 0 ; j < 3 ; ++j) { // look for leading pivot VL::float_t maxa = 0 ; VL::float_t maxabsa = 0 ; int maxi = -1 ; int i ; for(i = j ; i < 3 ; ++i) { VL::float_t a = Aat(i,j) ; VL::float_t absa = fabsf( a ) ; if ( absa > maxabsa ) { maxa = a ; maxabsa = absa ; maxi = i ; } } // singular? if( maxabsa < 1e-10f ) { b[0] = 0 ; b[1] = 0 ; b[2] = 0 ; break ; } i = maxi ; // swap j-th row with i-th row and // normalize j-th row for(int jj = j ; jj < 3 ; ++jj) { std::swap( Aat(j,jj) , Aat(i,jj) ) ; Aat(j,jj) /= maxa ; } std::swap( b[j], b[i] ) ; b[j] /= maxa ; // elimination for(int ii = j+1 ; ii < 3 ; ++ii) { VL::float_t x = Aat(ii,j) ; for(int jj = j ; jj < 3 ; ++jj) { Aat(ii,jj) -= x * Aat(j,jj) ; } b[ii] -= x * b[j] ; } } // backward substitution for(int i = 2 ; i > 0 ; --i) { VL::float_t x = b[i] ; for(int ii = i-1 ; ii >= 0 ; --ii) { b[ii] -= x * Aat(ii,i) ; } } /* If the translation of the keypoint is big, move the keypoint * and re-iterate the computation. Otherwise we are all set. */ dx= ((b[0] > 0.6 && x < ow-2) ? 1 : 0 ) + ((b[0] < -0.6 && x > 1 ) ? -1 : 0 ) ; dy= ((b[1] > 0.6 && y < oh-2) ? 1 : 0 ) + ((b[1] < -0.6 && y > 1 ) ? -1 : 0 ) ; /* std::cout<<x<<","<<y<<"="<<at(0,0,0) <<"(" <<at(0,0,0)+0.5 * (Dx * b[0] + Dy * b[1] + Ds * b[2])<<")" <<" "<<std::flush ; */ if( dx == 0 && dy == 0 ) break ; } /* std::cout<<std::endl ; */ // Accept-reject keypoint { VL::float_t val = at(0,0,0) + 0.5 * (Dx * b[0] + Dy * b[1] + Ds * b[2]) ; VL::float_t score = (Dxx+Dyy)*(Dxx+Dyy) / (Dxx*Dyy - Dxy*Dxy) ; VL::float_t xn = x + b[0] ; VL::float_t yn = y + b[1] ; VL::float_t sn = s + b[2] ; if(fast_abs(val) > threshold && score < (edgeThreshold+1)*(edgeThreshold+1)/edgeThreshold && score >= 0 &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -