fasthessian.h和fasthessian.h主要完成關鍵點的檢測數組
一、創建fasthesian結構app
二、初始化fasthessian結構oop
三、創建DOH源碼分析
四、找出極值點ui
五、肯定關鍵點準確位置this
源碼分析:spa
/*********************************************************** * --- OpenSURF --- * * This library is distributed under the GNU GPL. Please * * use the contact form at http://www.chrisevansdev.com * * for more information. * * * * C. Evans, Research Into Robust Visual Features, * * MSc University of Bristol, 2008. * * * ************************************************************/ #include "integral.h" #include "ipoint.h" #include "utils.h" #include <vector> #include "responselayer.h" #include "fasthessian.h" using namespace std; //------------------------------------------------------- //! 不包含積分圖的fasthessian結構構建 //! Constructor without image FastHessian::FastHessian(std::vector<Ipoint> &ipts, const int octaves, const int intervals, const int init_sample, const float thresh) : ipts(ipts), i_width(0), i_height(0) { // Save parameter set saveParameters(octaves, intervals, init_sample, thresh); } //------------------------------------------------------- //! 包含積分圖的fasthessian結構構建 //! Constructor with image FastHessian::FastHessian(IplImage *img, std::vector<Ipoint> &ipts, const int octaves, const int intervals, const int init_sample, const float thresh) : ipts(ipts), i_width(0), i_height(0) { // Save parameter set saveParameters(octaves, intervals, init_sample, thresh); // Set the current image setIntImage(img); } //------------------------------------------------------- FastHessian::~FastHessian() { for (unsigned int i = 0; i < responseMap.size(); ++i) { delete responseMap[i]; } } //------------------------------------------------------- //! 初始化參數 //! Save the parameters void FastHessian::saveParameters(const int octaves, const int intervals, const int init_sample, const float thresh) { // Initialise variables with bounds-checked values this->octaves = (octaves > 0 && octaves <= 4 ? octaves : OCTAVES); this->intervals = (intervals > 0 && intervals <= 4 ? intervals : INTERVALS); this->init_sample = (init_sample > 0 && init_sample <= 6 ? init_sample : INIT_SAMPLE); this->thresh = (thresh >= 0 ? thresh : THRES); } //------------------------------------------------------- //! 設定積分圖像 //! Set or re-set the integral image source void FastHessian::setIntImage(IplImage *img) { // Change the source image this->img = img; i_height = img->height; i_width = img->width; } //------------------------------------------------------- //! Find the image features and write into vector of features void FastHessian::getIpoints() { // filter index map濾波器與尺度空間索引 static const int filter_map [OCTAVES][INTERVALS] = {{0,1,2,3}, {1,3,4,5}, {3,5,6,7}, {5,7,8,9}, {7,9,10,11}}; // 清空容器 // Clear the vector of exisiting ipts ipts.clear(); // 創建尺度空間 // Build the response map buildResponseMap(); // 獲得極值點 // Get the response layers ResponseLayer *b, *m, *t; for (int o = 0; o < octaves; ++o) for (int i = 0; i <= 1; ++i) { b = responseMap.at(filter_map[o][i]); m = responseMap.at(filter_map[o][i+1]); t = responseMap.at(filter_map[o][i+2]); // 取連續的三層,計算最上層的極值點,將最上層的每一個像素點與鄰近的26個像素點比較 // loop over middle response layer at density of the most // sparse layer (always top), to find maxima across scale and space for (int r = 0; r < t->height; ++r) { for (int c = 0; c < t->width; ++c) { if (isExtremum(r, c, t, m, b))// 是否爲極值點 { interpolateExtremum(r, c, t, m, b);//用插值法計算精確的極值點位置 } } } } } //------------------------------------------------------- //! 構建尺度空間 //! Build map of DoH responses void FastHessian::buildResponseMap() { // 高斯濾波核前四組尺寸大小 // Calculate responses for the first 4 octaves: // Oct1: 9, 15, 21, 27 // Oct2: 15, 27, 39, 51 // Oct3: 27, 51, 75, 99 // Oct4: 51, 99, 147,195 // Oct5: 99, 195,291,387 // 清除已經存在的層 // Deallocate memory and clear any existing response layers for(unsigned int i = 0; i < responseMap.size(); ++i) delete responseMap[i]; responseMap.clear(); // 獲得圖像的參數 // Get image attributes int w = (i_width / init_sample);//寬=原始圖像寬/原始抽樣倍數 int h = (i_height / init_sample);//高=原始圖像高/原始抽樣倍數 int s = (init_sample);//原始抽樣倍數 // 建立尺度空間全部層 // Calculate approximated determinant of hessian values if (octaves >= 1) { responseMap.push_back(new ResponseLayer(w, h, s, 9)); responseMap.push_back(new ResponseLayer(w, h, s, 15)); responseMap.push_back(new ResponseLayer(w, h, s, 21)); responseMap.push_back(new ResponseLayer(w, h, s, 27)); } if (octaves >= 2) { responseMap.push_back(new ResponseLayer(w/2, h/2, s*2, 39)); responseMap.push_back(new ResponseLayer(w/2, h/2, s*2, 51)); } if (octaves >= 3) { responseMap.push_back(new ResponseLayer(w/4, h/4, s*4, 75)); responseMap.push_back(new ResponseLayer(w/4, h/4, s*4, 99)); } if (octaves >= 4) { responseMap.push_back(new ResponseLayer(w/8, h/8, s*8, 147)); responseMap.push_back(new ResponseLayer(w/8, h/8, s*8, 195)); } if (octaves >= 5) { responseMap.push_back(new ResponseLayer(w/16, h/16, s*16, 291)); responseMap.push_back(new ResponseLayer(w/16, h/16, s*16, 387)); } // 提取每一層的hessian值及laplacian值 // Extract responses from the image for (unsigned int i = 0; i < responseMap.size(); ++i) { buildResponseLayer(responseMap[i]); } } //------------------------------------------------------- //! 計算尺度空間每層的hessian值及laplacian值(及跡的值 //! Calculate DoH responses for supplied layer void FastHessian::buildResponseLayer(ResponseLayer *rl) { float *responses = rl->responses; // response storage hessian值存儲數組 unsigned char *laplacian = rl->laplacian; // laplacian sign storage laplacian值存儲數組 int step = rl->step; // step size for this filter 濾波尺度倍數 int b = (rl->filter - 1) / 2; // border for this filter 高斯濾波核邊界 int l = rl->filter / 3; // lobe for this filter (filter size / 3) int w = rl->filter; // filter size 高斯濾波核的大小 float inverse_area = 1.f/(w*w); // normalisation factor 歸一化因子 float Dxx, Dyy, Dxy; // hessian矩陣中四個元素,Dxy和Dyx值同樣 //計算每一個像素點的hessian值及laplacian值 for(int r, c, ar = 0, index = 0; ar < rl->height; ++ar) { for(int ac = 0; ac < rl->width; ++ac, index++) { // 獲得像素在圖像中的座標位置 // get the image coordinates r = ar * step; c = ac * step; // 計算hessian成員值 // Compute response components Dxx = BoxIntegral(img, r - l + 1, c - b, 2*l - 1, w) - BoxIntegral(img, r - l + 1, c - l / 2, 2*l - 1, l)*3; Dyy = BoxIntegral(img, r - b, c - l + 1, w, 2*l - 1) - BoxIntegral(img, r - l / 2, c - l + 1, l, 2*l - 1)*3; Dxy = + BoxIntegral(img, r - l, c + 1, l, l) + BoxIntegral(img, r + 1, c - l, l, l) - BoxIntegral(img, r - l, c - l, l, l) - BoxIntegral(img, r + 1, c + 1, l, l); // 歸一化 // Normalise the filter responses with respect to their size Dxx *= inverse_area; Dyy *= inverse_area; Dxy *= inverse_area; // 保存 // Get the determinant of hessian response & laplacian sign responses[index] = (Dxx * Dyy - 0.81f * Dxy * Dxy); laplacian[index] = (Dxx + Dyy >= 0 ? 1 : 0); #ifdef RL_DEBUG // create list of the image coords for each response rl->coords.push_back(std::make_pair<int,int>(r,c)); #endif } } } //------------------------------------------------------- //! 極值點檢測,r,c像素點座標,t,m,b,尺度空間中連續的三層 //! Non Maximal Suppression function int FastHessian::isExtremum(int r, int c, ResponseLayer *t, ResponseLayer *m, ResponseLayer *b) { //計算邊界,檢測r/c是否越界 // bounds check int layerBorder = (t->filter + 1) / (2 * t->step); if (r <= layerBorder || r >= t->height - layerBorder || c <= layerBorder || c >= t->width - layerBorder) return 0; // 檢測hessian值是否大於閥值,若是小於,返回0 // check the candidate point in the middle layer is above thresh float candidate = m->getResponse(r, c, t); if (candidate < thresh) return 0; // 與附近26像素比較 for (int rr = -1; rr <=1; ++rr) { for (int cc = -1; cc <=1; ++cc) { // if any response in 3x3x3 is greater candidate not maximum if ( t->getResponse(r+rr, c+cc) >= candidate || ((rr != 0 || cc != 0) && m->getResponse(r+rr, c+cc, t) >= candidate) || b->getResponse(r+rr, c+cc, t) >= candidate ) return 0; } } return 1; } //------------------------------------------------------- //插值法逼近極值點準確位置,r、c像素點座標,t,m,b尺度空間連續三層 //! Interpolate scale-space extrema to subpixel accuracy to form an image feature. void FastHessian::interpolateExtremum(int r, int c, ResponseLayer *t, ResponseLayer *m, ResponseLayer *b) { // 高斯濾波核的尺度是不是按大小順序排列 // get the step distance between filters // check the middle filter is mid way between top and bottom int filterStep = (m->filter - b->filter); assert(filterStep > 0 && t->filter - m->filter == m->filter - b->filter); // 獲得極值點準確位置 // Get the offsets to the actual location of the extremum double xi = 0, xr = 0, xc = 0; interpolateStep(r, c, t, m, b, &xi, &xr, &xc );//插值法逼近真實極值點 // 該點是否有效逼近真實極值點 // If point is sufficiently close to the actual extremum if( fabs( xi ) < 0.5f && fabs( xr ) < 0.5f && fabs( xc ) < 0.5f ) { Ipoint ipt; ipt.x = static_cast<float>((c + xc) * t->step); ipt.y = static_cast<float>((r + xr) * t->step); ipt.scale = static_cast<float>((0.1333f) * (m->filter + xi * filterStep)); ipt.laplacian = static_cast<int>(m->getLaplacian(r,c,t)); ipts.push_back(ipt); } } //------------------------------------------------------- //! 插值法算出極值點誤差 //! Performs one step of extremum interpolation. void FastHessian::interpolateStep(int r, int c, ResponseLayer *t, ResponseLayer *m, ResponseLayer *b, double* xi, double* xr, double* xc ) { CvMat* dD, * H, * H_inv, X; double x[3] = { 0 }; dD = deriv3D( r, c, t, m, b );//三維偏導數計算 H = hessian3D( r, c, t, m, b );//三維hessian矩陣計算 H_inv = cvCreateMat( 3, 3, CV_64FC1 );//建立64位單精度3*3矩陣 cvInvert( H, H_inv, CV_SVD );//轉換矩陣格式 cvInitMatHeader( &X, 3, 1, CV_64FC1, x, CV_AUTOSTEP );//建立3*1矩陣頭 cvGEMM( H_inv, dD, -1, NULL, 0, &X, 0 ); cvReleaseMat( &dD ); cvReleaseMat( &H ); cvReleaseMat( &H_inv ); *xi = x[2];//三個方向誤差 *xr = x[1]; *xc = x[0]; } //------------------------------------------------------- //! 三維偏導數計算 //! Computes the partial derivatives in x, y, and scale of a pixel. CvMat* FastHessian::deriv3D(int r, int c, ResponseLayer *t, ResponseLayer *m, ResponseLayer *b) { CvMat* dI; double dx, dy, ds; dx = (m->getResponse(r, c + 1, t) - m->getResponse(r, c - 1, t)) / 2.0; dy = (m->getResponse(r + 1, c, t) - m->getResponse(r - 1, c, t)) / 2.0; ds = (t->getResponse(r, c) - b->getResponse(r, c, t)) / 2.0; dI = cvCreateMat( 3, 1, CV_64FC1 ); cvmSet( dI, 0, 0, dx ); cvmSet( dI, 1, 0, dy ); cvmSet( dI, 2, 0, ds ); return dI; } //------------------------------------------------------- //! 三維hessian矩陣計算 //! Computes the 3D Hessian matrix for a pixel. CvMat* FastHessian::hessian3D(int r, int c, ResponseLayer *t, ResponseLayer *m, ResponseLayer *b) { CvMat* H; double v, dxx, dyy, dss, dxy, dxs, dys; v = m->getResponse(r, c, t); dxx = m->getResponse(r, c + 1, t) + m->getResponse(r, c - 1, t) - 2 * v; dyy = m->getResponse(r + 1, c, t) + m->getResponse(r - 1, c, t) - 2 * v; dss = t->getResponse(r, c) + b->getResponse(r, c, t) - 2 * v; dxy = ( m->getResponse(r + 1, c + 1, t) - m->getResponse(r + 1, c - 1, t) - m->getResponse(r - 1, c + 1, t) + m->getResponse(r - 1, c - 1, t) ) / 4.0; dxs = ( t->getResponse(r, c + 1) - t->getResponse(r, c - 1) - b->getResponse(r, c + 1, t) + b->getResponse(r, c - 1, t) ) / 4.0; dys = ( t->getResponse(r + 1, c) - t->getResponse(r - 1, c) - b->getResponse(r + 1, c, t) + b->getResponse(r - 1, c, t) ) / 4.0; H = cvCreateMat( 3, 3, CV_64FC1 ); cvmSet( H, 0, 0, dxx ); cvmSet( H, 0, 1, dxy ); cvmSet( H, 0, 2, dxs ); cvmSet( H, 1, 0, dxy ); cvmSet( H, 1, 1, dyy ); cvmSet( H, 1, 2, dys ); cvmSet( H, 2, 0, dxs ); cvmSet( H, 2, 1, dys ); cvmSet( H, 2, 2, dss ); return H; } //-------------------------------------------------------