📄 sift.cpp
字号:
fast_abs(b[0]) < 1.5 && fast_abs(b[1]) < 1.5 && fast_abs(b[2]) < 1.5 && xn >= 0 && xn <= ow-1 && yn >= 0 && yn <= oh-1 && sn >= smin && sn <= smax ) { diter->o = o ; diter->ix = x ; diter->iy = y ; diter->is = s ; diter->x = xn * xperiod ; diter->y = yn * xperiod ; diter->s = sn ; diter->sigma = getScaleFromIndex(o,sn) ; ++diter ; } } } // next candidate keypoint // prepare for next octave keypoints.resize( diter - keypoints.begin() ) ; nValidatedKeypoints = keypoints.size() ; } // refine block } // next octave}// ===================================================================// computeKeypointOrientations()// -------------------------------------------------------------------/** @brief Compute modulus and phase of the gradient ** ** The function computes the modulus and the angle of the gradient of ** the specified octave @a o. The result is stored in a temporary ** internal buffer accessed by computeKeypointDescriptor() and ** computeKeypointOrientations(). ** ** The SIFT detector provides keypoint with scale index s in the ** range @c smin+1 and @c smax-2. As such, the buffer contains only ** these levels. ** ** If called mutliple time on the same data, the function exits ** immediately. ** ** @param o octave of interest. **/voidSift::prepareGrad(int o){ int const ow = getOctaveWidth(o) ; int const oh = getOctaveHeight(o) ; int const xo = 1 ; int const yo = ow ; int const so = oh*ow ; if( ! tempIsGrad || tempOctave != o ) { // compute dx/dy for(int s = smin+1 ; s <= smax-2 ; ++s) { for(int y = 1 ; y < oh-1 ; ++y ) { pixel_t* src = getLevel(o, s) + xo + yo*y ; pixel_t* end = src + ow - 1 ; pixel_t* grad = 2 * (xo + yo*y + (s - smin -1)*so) + temp ; while(src != end) { VL::float_t Gx = 0.5 * ( *(src+xo) - *(src-xo) ) ; VL::float_t Gy = 0.5 * ( *(src+yo) - *(src-yo) ) ; VL::float_t m = fast_sqrt( Gx*Gx + Gy*Gy ) ; VL::float_t t = fast_mod_2pi( fast_atan2(Gy, Gx) + VL::float_t(2*M_PI) ); *grad++ = pixel_t( m ) ; *grad++ = pixel_t( t ) ; ++src ; } } } } tempIsGrad = true ; tempOctave = o ;}/** @brief Compute the orientation(s) of a keypoint ** ** The function computes the orientation of the specified keypoint. ** The function returns up to four different orientations, obtained ** as strong peaks of the histogram of gradient orientations (a ** keypoint can theoretically generate more than four orientations, ** but this is very unlikely). ** ** @remark The function needs to compute the gradient modululs and ** orientation of the Gaussian scale space octave to which the ** keypoint belongs. The result is cached, but discarded if different ** octaves are visited. Thereofre it is much quicker to evaluate the ** keypoints in their natural octave order. ** ** The keypoint must lie within the scale space. In particular, the ** scale index is supposed to be in the range @c smin+1 and @c smax-1 ** (this is from the SIFT detector). If this is not the case, the ** computation is silently aborted and no orientations are returned. ** ** @param angles buffers to store the resulting angles. ** @param keypoint keypoint to process. ** @return number of orientations found. **/intSift::computeKeypointOrientations(VL::float_t angles [4], Keypoint keypoint){ int const nbins = 36 ; VL::float_t const winFactor = 1.5 ; VL::float_t hist [nbins] ; // octave int o = keypoint.o ; VL::float_t xperiod = getOctaveSamplingPeriod(o) ; // offsets to move in the Gaussian scale space octave const int ow = getOctaveWidth(o) ; const int oh = getOctaveHeight(o) ; const int xo = 2 ; const int yo = xo * ow ; const int so = yo * oh ; // keypoint fractional geometry VL::float_t x = keypoint.x / xperiod ; VL::float_t y = keypoint.y / xperiod ; VL::float_t sigma = keypoint.sigma / xperiod ; // shall we use keypoints.ix,iy,is here? int xi = ((int) (x+0.5)) ; int yi = ((int) (y+0.5)) ; int si = keypoint.is ; VL::float_t const sigmaw = winFactor * sigma ; int W = (int) floor(3.0 * sigmaw) ; // skip the keypoint if it is out of bounds if(o < omin || o >=omin+O || xi < 0 || xi > ow-1 || yi < 0 || yi > oh-1 || si < smin+1 || si > smax-2 ) { std::cerr<<"!"<<std::endl ; return 0 ; } // make sure that the gradient buffer is filled with octave o prepareGrad(o) ; // clear the SIFT histogram std::fill(hist, hist + nbins, 0) ; // fill the SIFT histogram pixel_t* pt = temp + xi * xo + yi * yo + si * (so - smin -1) ;#undef at#define at(dx,dy) (*(pt + (dx)*xo + (dy)*yo)) for(int ys = std::max(-W, 1-yi) ; ys <= std::min(+W, oh -2 -yi) ; ++ys) { for(int xs = std::max(-W, 1-xi) ; xs <= std::min(+W, ow -2 -xi) ; ++xs) { VL::float_t dx = xi + xs - x; VL::float_t dy = yi + ys - y; VL::float_t r2 = dx*dx + dy*dy ; // limit to a circular window if(r2 >= W*W+0.5) continue ; VL::float_t wgt = VL::fast_expn( r2 / (2*sigmaw*sigmaw) ) ; VL::float_t mod = *(pt + xs*xo + ys*yo) ; VL::float_t ang = *(pt + xs*xo + ys*yo + 1) ; // int bin = (int) floor( nbins * ang / (2*M_PI) ) ; int bin = (int) floor( nbins * ang / (2*M_PI) ) ; hist[bin] += mod * wgt ; } } // smooth the histogram#if defined VL_LOWE_STRICT // Lowe's version apparently has a little issue with orientations // around + or - pi, which we reproduce here for compatibility for (int iter = 0; iter < 6; iter++) { VL::float_t prev = hist[nbins/2] ; for (int i = nbins/2-1; i >= -nbins/2 ; --i) { int const j = (i + nbins) % nbins ; int const jp = (i - 1 + nbins) % nbins ; VL::float_t newh = (prev + hist[j] + hist[jp]) / 3.0; prev = hist[j] ; hist[j] = newh ; } }#else // this is slightly more correct for (int iter = 0; iter < 6; iter++) { VL::float_t prev = hist[nbins-1] ; VL::float_t first = hist[0] ; int i ; for (i = 0; i < nbins - 1; i++) { VL::float_t newh = (prev + hist[i] + hist[(i+1) % nbins]) / 3.0; prev = hist[i] ; hist[i] = newh ; } hist[i] = (prev + hist[i] + first)/3.0 ; }#endif // find the histogram maximum VL::float_t maxh = * std::max_element(hist, hist + nbins) ; // find peaks within 80% from max int nangles = 0 ; for(int i = 0 ; i < nbins ; ++i) { VL::float_t h0 = hist [i] ; VL::float_t hm = hist [(i-1+nbins) % nbins] ; VL::float_t hp = hist [(i+1+nbins) % nbins] ; // is peak? if( h0 > 0.8*maxh && h0 > hm && h0 > hp ) { // quadratic interpolation // VL::float_t di = -0.5 * (hp-hm) / (hp+hm-2*h0) ; VL::float_t di = -0.5 * (hp-hm) / (hp+hm-2*h0) ; VL::float_t th = 2*M_PI*(i+di+0.5)/nbins ; angles [ nangles++ ] = th ; } } return nangles ;}// ===================================================================// computeKeypointDescriptor()// -------------------------------------------------------------------namespace Detail {/** Normalizes in norm L_2 a descriptor. */voidnormalize_histogram(VL::float_t* L_begin, VL::float_t* L_end){ VL::float_t* L_iter ; VL::float_t norm = 0.0 ; for(L_iter = L_begin; L_iter != L_end ; ++L_iter) norm += (*L_iter) * (*L_iter) ; norm = fast_sqrt(norm) ; for(L_iter = L_begin; L_iter != L_end ; ++L_iter) *L_iter /= norm ;}}/** @brief SIFT descriptor ** ** The function computes the descriptor of the keypoint @a keypoint. ** The function fills the buffer @a descr_pt which must be large ** enough. The funciton uses @a angle0 as rotation of the keypoint. ** By calling the function multiple times, different orientations can ** be evaluated. ** ** @remark The function needs to compute the gradient modululs and ** orientation of the Gaussian scale space octave to which the ** keypoint belongs. The result is cached, but discarded if different ** octaves are visited. Thereofre it is much quicker to evaluate the ** keypoints in their natural octave order. ** ** The function silently abort the computations of keypoints without ** the scale space boundaries. See also siftComputeOrientations(). **/voidSift::computeKeypointDescriptor(VL::float_t* descr_pt, Keypoint keypoint, VL::float_t angle0){ /* The SIFT descriptor is a three dimensional histogram of the position * and orientation of the gradient. There are NBP bins for each spatial * dimesions and NBO bins for the orientation dimesion, for a total of * NBP x NBP x NBO bins. * * The support of each spatial bin has an extension of SBP = 3sigma * pixels, where sigma is the scale of the keypoint. Thus all the bins * together have a support SBP x NBP pixels wide . Since weighting and * interpolation of pixel is used, another half bin is needed at both * ends of the extension. Therefore, we need a square window of SBP x * (NBP + 1) pixels. Finally, since the patch can be arbitrarly rotated, * we need to consider a window 2W += sqrt(2) x SBP x (NBP + 1) pixels * wide. */ // octave int o = keypoint.o ; VL::float_t xperiod = getOctaveSamplingPeriod(o) ; // offsets to move in Gaussian scale space octave const int ow = getOctaveWidth(o) ; const int oh = getOctaveHeight(o) ; const int xo = 2 ; const int yo = xo * ow ; const int so = yo * oh ; // keypoint fractional geometry VL::float_t x = keypoint.x / xperiod; VL::float_t y = keypoint.y / xperiod ; VL::float_t sigma = keypoint.sigma / xperiod ; VL::float_t st0 = sinf( angle0 ) ; VL::float_t ct0 = cosf( angle0 ) ; // shall we use keypoints.ix,iy,is here? int xi = ((int) (x+0.5)) ; int yi = ((int) (y+0.5)) ; int si = keypoint.is ; const VL::float_t magnif = 3.0f ; const int NBO = 8 ; const int NBP = 4 ; const VL::float_t SBP = magnif * sigma ; const int W = (int) floor (sqrt(2.0) * SBP * (NBP + 1) / 2.0 + 0.5) ; /* Offsets to move in the descriptor. */ /* Use Lowe's convention. */ const int binto = 1 ; const int binyo = NBO * NBP ; const int binxo = NBO ; // const int bino = NBO * NBP * NBP ; int bin ; // check bounds if(o < omin || o >=omin+O || xi < 0 || xi > ow-1 || yi < 0 || yi > oh-1 || si < smin+1 || si > smax-2 ) return ; // make sure gradient buffer is up-to-date prepareGrad(o) ; std::fill( descr_pt, descr_pt + NBO*NBP*NBP, 0 ) ; /* Center the scale space and the descriptor on the current keypoint. * Note that dpt is pointing to the bin of center (SBP/2,SBP/2,0). */ pixel_t const * pt = temp + xi*xo + yi*yo + (si - smin - 1)*so ; VL::float_t * dpt = descr_pt + (NBP/2) * binyo + (NBP/2) * binxo ; #define atd(dbinx,dbiny,dbint) *(dpt + (dbint)*binto + (dbiny)*binyo + (dbinx)*binxo) /* * Process pixels in the intersection of the image rectangle * (1,1)-(M-1,N-1) and the keypoint bounding box. */ for(int dyi = std::max(-W, 1-yi) ; dyi <= std::min(+W, oh-2-yi) ; ++dyi) { for(int dxi = std::max(-W, 1-xi) ; dxi <= std::min(+W, ow-2-xi) ; ++dxi) { // retrieve VL::float_t mod = *( pt + dxi*xo + dyi*yo + 0 ) ; VL::float_t angle = *( pt + dxi*xo + dyi*yo + 1 ) ; VL::float_t theta = fast_mod_2pi(-angle + angle0) ; // lowe compatible ? // fractional displacement VL::float_t dx = xi + dxi - x; VL::float_t dy = yi + dyi - y; // get the displacement normalized w.r.t. the keypoint // orientation and extension. VL::float_t nx = ( ct0 * dx + st0 * dy) / SBP ; VL::float_t ny = (-st0 * dx + ct0 * dy) / SBP ; VL::float_t nt = NBO * theta / (2*M_PI) ; // Get the gaussian weight of the sample. The gaussian window // has a standard deviation equal to NBP/2. Note that dx and dy // are in the normalized frame, so that -NBP/2 <= dx <= NBP/2. VL::float_t const wsigma = NBP/2 ; VL::float_t win = VL::fast_expn((nx*nx + ny*ny)/(2.0 * wsigma * wsigma)) ; // The sample will be distributed in 8 adjacent bins. // We start from the ``lower-left'' bin. int binx = fast_floor( nx - 0.5 ) ; int biny = fast_floor( ny - 0.5 ) ; int bint = fast_floor( nt ) ; VL::float_t rbinx = nx - (binx+0.5) ; VL::float_t rbiny = ny - (biny+0.5) ; VL::float_t rbint = nt - bint ; int dbinx ; int dbiny ; int dbint ; // Distribute the current sample into the 8 adjacent bins for(dbinx = 0 ; dbinx < 2 ; ++dbinx) { for(dbiny = 0 ; dbiny < 2 ; ++dbiny) { for(dbint = 0 ; dbint < 2 ; ++dbint) { if( binx+dbinx >= -(NBP/2) && binx+dbinx < (NBP/2) && biny+dbiny >= -(NBP/2) && biny+dbiny < (NBP/2) ) { VL::float_t weight = win * mod * fast_abs (1 - dbinx - rbinx) * fast_abs (1 - dbiny - rbiny) * fast_abs (1 - dbint - rbint) ; atd(binx+dbinx, biny+dbiny, (bint+dbint) % NBO) += weight ; } } } } } } /* Normalize the histogram to L2 unit length. */ Detail::normalize_histogram(descr_pt, descr_pt + NBO*NBP*NBP) ; /* Truncate at 0.2. */ for(bin = 0; bin < NBO*NBP*NBP ; ++bin) { if (descr_pt[bin] > 0.2) descr_pt[bin] = 0.2; } /* Normalize again. */ Detail::normalize_histogram(descr_pt, descr_pt + NBO*NBP*NBP) ;}// namespace VL}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -