반응형
int main() { if (PROCEDURE == 1) return mainImage("IMG_4207.png"); if (PROCEDURE == 2) return mainVideo(); } //------------------------------------------------------- int mainImage(const char *filename) { // Declare Ipoints and other stuff IpVec ipts; IplImage *img=cvLoadImage(filename); // Detect and describe interest points in the image surfDetDes(img, ipts, false, 3, 4, 1, 0.0004f); // Draw the detected points drawIpoints(img, ipts); // Display the result showImage(img); return 0; }//-------------------------------------------------------
//! Library function builds vector of described interest points inline void surfDetDes(IplImage *img, /* image to find Ipoints in */ std::vector<Ipoint> &ipts, /* reference to vector of Ipoints */ bool upright = false, /* run in rotation invariant mode? */ int octaves = OCTAVES, /* number of octaves to calculate */ int intervals = INTERVALS, /* number of intervals per octave */ int init_sample = INIT_SAMPLE, /* initial sampling step */ float thres = THRES /* blob response threshold */) { // Create integral-image representation of the image IplImage *int_img = Integral(img); // Create Fast Hessian Object FastHessian fh(int_img, ipts, octaves, intervals, init_sample, thres); // Extract interest points and store in vector ipts fh.getIpoints(); // Create Surf Descriptor Object Surf des(int_img, ipts); // Extract the descriptors for the ipts des.getDescriptors(upright); // Deallocate the integral image cvReleaseImage(&int_img); }//-------------------------------------------------------
//! Constructor with image FastHessian::FastHessian(IplImage *img, std::vector<Ipoint> &ipts, const int octaves, const int intervals, const int init_sample, const float thres) : ipts(ipts), m_det(NULL), i_width(0), i_height(0) { // Initialise variables and construct Det array this->octaves = octaves; this->intervals = intervals; this->init_sample = init_sample; this->thres = thres; // Set the current image setIntImage(img); } //! Find the image features and write into vector of features void FastHessian::getIpoints() { // Clear the vector of exisiting ipts ipts.clear(); // Calculate approximated determinant of hessian values buildDet(); for(int o=0; o < octaves; o++) { // for each octave double the sampling step of the previous int step = init_sample * cvRound(pow(2.0f,o)); // determine border width for the largest filter for each ocave int border = (3 * cvRound(pow(2.0,o+1)*(intervals)+1) + 1)/2; // check for maxima across the scale space for(int i = 1; i < intervals-1; ++i) for(int r = (border); r < i_height - (border); r += step) for(int c = (border); c < i_width - (border); c += step) if(isExtremum(o, i, c, r)) interp_extremum(o,i,r,c); } }//-------------------------------------------------------
//! Calculate determinant of hessian responses void FastHessian::buildDet() { int lobe, border, step; float Dxx, Dyy, Dxy, scale; for(int o=0; o<octaves; o++) { // calculate filter border for this octave border = (3 * fRound(pow(2.0f,o+1)*(intervals)+1) + 1)/2; step = init_sample * fRound(pow(2.0f,o)); for(int i=0; i<intervals; i++) { // calculate lobe length (filter side length/3) lobe = fRound(pow(2.0f,o+1)*(i+1)+1); scale = 1.0f/pow((float)(3*lobe),2); for(int r=border; r<i_height-border; r+=step) { for(int c=border; c<i_width-border; c+=step) { Dyy = Area(img, c-(lobe-1), r-((3*lobe-1)/2), (2*lobe-1), lobe) -2*Area(img, c-(lobe-1), r-((lobe-1)/2), (2*lobe-1), lobe) +Area(img, c-(lobe-1), r+((lobe+1)/2), (2*lobe-1), lobe); Dxx = Area(img, c-((3*lobe-1)/2), r-(lobe-1), lobe, (2*lobe-1)) -2*Area(img, c-((lobe-1)/2), r-(lobe-1), lobe, (2*lobe-1)) +Area(img, c+((lobe+1)/2), r-(lobe-1), lobe, (2*lobe-1)); Dxy = Area(img, c-lobe, r-lobe, lobe, lobe) +Area(img, c+1, r+1, lobe, lobe) -Area(img, c-lobe, r+1, lobe, lobe) -Area(img, c+1, r-lobe, lobe, lobe); // Normalise the filter responses with respect to their size Dxx *= scale; Dyy *= scale; Dxy *= scale; // Get the sign of the laplacian int lap_sign = (Dxx+Dyy >= 0 ? 1 : -1); // Get the determinant of hessian response float res = (Dxx*Dyy - pow(0.9f*Dxy,2)); res = (res < thres ? 0 : lap_sign * res); // calculate approximated determinant of hessian value m_det[(o*intervals+i)*(i_width*i_height) + (r*i_width+c)] = res; } } } } }//-------------------------------------------------------
//! Non Maximal Suppression function int FastHessian::isExtremum(int octave, int interval, int c, int r) { float val = getVal(octave, interval, c, r); int step = init_sample * cvRound(pow(2.0f,octave)); // reject points with low response to the det of hessian function if(val < thres) return 0; // check for maximum for(int i = -1; i <= 1; i++ ) for(int j = -step; j <= step; j+=step ) for(int k = -step; k <= step; k+=step ) if (i != 0 || j != 0 || k != 0) if(getVal(octave, interval+i, c+j, r+k) > val) return 0; return 1; }
//Interpolates a scale-space extremum's location and scale to subpixel //accuracy to form an image feature. void FastHessian::interp_extremum(int octv, int intvl, int r, int c) { double xi = 0, xr = 0, xc = 0; int i = 0; int step = init_sample * cvRound(pow(2.0f,octv)); // Get the offsets to the actual location of the extremum interp_step( octv, intvl, r, c, &xi, &xr, &xc ); // If point is sufficiently close to the actual extremum if( fabs( xi ) <= 0.5 && fabs( xr ) <= 0.5 && fabs( xc ) <= 0.5 ) { // Create Ipoint and push onto Ipoints vector Ipoint ipt; ipt.x = (float) (c + step*xc); ipt.y = (float) (r + step*xr); ipt.scale = (float) ((1.2f/9.0f) * (3*(pow(2.0f, octv+1) * (intvl+xi+1)+1))); ipt.laplacian = getLaplacian(octv, intvl, c, r); ipts.push_back(ipt); } }
//Performs one step of extremum interpolation. void FastHessian::interp_step( octv, int intvl, int r, int c, double* xi, double* xr, double* xc ) { CvMat* dD, * H, * H_inv, X; double x[3] = { 0 }; dD = deriv_3D( octv, intvl, r, c ); H = hessian_3D( octv, intvl, r, c ); H_inv = cvCreateMat( 3, 3, CV_64FC1 ); cvInvert( H, H_inv, CV_SVD ); cvInitMatHeader( &X, 3, 1, CV_64FC1, x, CV_AUTOSTEP ); 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 in the DoG //scale space pyramid. CvMat* FastHessian::deriv_3D( int octv, int intvl, int r, int c ) { CvMat* dI; double dx, dy, ds; int step = init_sample * cvRound(pow(2.0f,octv)); dx = ( getValLowe(octv,intvl, r, c+step ) - getValLowe( octv,intvl, r, c-step ) ) / 2.0; dy = ( getValLowe( octv,intvl, r+step, c ) - getValLowe( octv,intvl, r-step, c ) ) / 2.0; ds = ( getValLowe( octv,intvl+1, r, c ) - getValLowe( octv,intvl-1, r, c ) ) / 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; }
//------------------------------------------------------- //Computes the 3D Hessian matrix for a pixel in the DoG scale space pyramid. CvMat* FastHessian::hessian_3D(int octv, int intvl, int r, int c ) { CvMat* H; double v, dxx, dyy, dss, dxy, dxs, dys; int step = init_sample * cvRound(pow(2.0f,octv)); v = getValLowe( octv,intvl, r, c ); dxx = ( getValLowe( octv,intvl, r, c+step ) + getValLowe( octv,intvl, r, c-step ) - 2 * v ); dyy = ( getValLowe( octv,intvl, r+step, c ) + getValLowe( octv,intvl, r-step, c ) - 2 * v ); dss = ( getValLowe( octv,intvl+1, r, c ) + getValLowe( octv,intvl-1, r, c ) - 2 * v ); dxy = ( getValLowe( octv,intvl, r+step, c+step ) - getValLowe( octv,intvl, r+step, c-step ) - getValLowe( octv,intvl, r-step, c+step ) + getValLowe( octv,intvl, r-step, c-step ) ) / 4.0; dxs = ( getValLowe( octv,intvl+1, r, c+step ) - getValLowe( octv,intvl+1, r, c-step ) - getValLowe( octv,intvl-1, r, c+step ) + getValLowe( octv,intvl-1, r, c-step ) ) / 4.0; dys = ( getValLowe( octv,intvl+1, r+step, c ) - getValLowe( octv,intvl+1, r-step, c ) - getValLowe( octv,intvl-1, r+step, c ) + getValLowe( octv,intvl-1, r-step, c ) ) / 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; }//------------------------------------------------------- //! Return the value of the approximated determinant of hessian inline float FastHessian::getValLowe(int o, int i, int r, int c) { return fabs(m_det[(o*intervals+i)*(i_width*i_height) + (r*i_width+c)]); }//------------------------------------------------------- //! Describe all features in the supplied vector void Surf::getDescriptors(bool upright) { // Check there are Ipoints to be described if (!ipts.size()) return; // Get the size of the vector for fixed loop bounds int ipts_size = ipts.size(); if (upright) { // U-SURF loop just gets descriptors for (unsigned int i = 0; i < ipts_size; ++i) { // Set the Ipoint to be described index = i; // Extract upright (i.e. not rotation invariant) descriptors getUprightDescriptor(); } } else { // Main SURF-64 loop assigns orientations and gets descriptors for (unsigned int i = 0; i < ipts_size; ++i) { // Set the Ipoint to be described index = i; // Assign Orientations and extract rotation invariant descriptors getOrientation(); getDescriptor(); } } }
//------------------------------------------------------- //! Assign the supplied Ipoint an orientation void Surf::getOrientation() { Ipoint *ipt = &ipts.at(index); float gauss, scale = ipt->scale; int s = cvRound(scale), r = cvRound(ipt->y), c = cvRound(ipt->x); std::vector<float> resX, resY, Ang; // calculate haar responses for points within radius of 6*scale for(int i = -6*s; i <= 6*s; i+=s) { for(int j = -6*s; j <= 6*s; j+=s) { if( i*i + j*j < 36*s*s ) { gauss = gaussian(i, j, 2.5f*s); resX.push_back( gauss * haarX(r+j, c+i, 4*s) ); resY.push_back( gauss * haarY(r+j, c+i, 4*s) ); Ang.push_back(getAngle(resX.back(), resY.back())); } } } // calculate the dominant direction float sumX, sumY; float max=0, old_max = 0, orientation = 0, old_orientation = 0; float ang1, ang2, ang; // loop slides pi/3 window around feature point for(ang1 = 0; ang1 < 2*pi; ang1+=0.2f) { ang2 = ( ang1+pi/3.0f > 2*pi ? ang1-5.0f*pi/3.0f : ang1+pi/3.0f); sumX = sumY = 0; for(unsigned int k = 0; k < Ang.size(); k++) { // get angle from the x-axis of the sample point ang = Ang.at(k); // determine whether the point is within the window if (ang1 < ang2 && ang1 < ang && ang < ang2) { sumX+=resX.at(k); sumY+=resY.at(k); } else if (ang2 < ang1 && ((ang > 0 && ang < ang2) || (ang > ang1 && ang < 2*pi) )) { sumX+=resX.at(k); sumY+=resY.at(k); } } // if the vector produced from this window is longer than all // previous vectors then this forms the new dominant direction if (sumX*sumX + sumY*sumY > max) { // store second largest orientation old_max = max; old_orientation = orientation; // store largest orientation max = sumX*sumX + sumY*sumY; orientation = getAngle(sumX, sumY); } } // check whether there are two dominant orientations based on 0.8 threshold if (old_max >= 0.8*max) { // assign second largest orientation and push copy onto vector ipt->orientation = old_orientation; ipts.push_back(*ipt); // Reset ipt to point to correct Ipoint in the vector ipt = &ipts.at(index); } // assign orientation of the dominant response vector ipt->orientation = orientation; } //------------------------------------------------------- //! Get the descriptor vector of the provided Ipoint void Surf::getDescriptor() { int y, x, count=0; float scale, *desc, dx, dy, mdx, mdy, co, si; float gauss, rx, ry, rrx, rry, sample_x, sample_y, len=0; Ipoint *ipt = &ipts.at(index); scale = ipt->scale; x = cvRound(ipt->x); y = cvRound(ipt->y); co = cos(ipt->orientation); si = sin(ipt->orientation); desc = ipt->descriptor; // Calculate descriptor for this interest point for (int i = -10; i < 10; i+=5) { for (int j = -10; j < 10; j+=5) { dx=dy=mdx=mdy=0; for (int k = i; k < i + 5; ++k) { for (int l = j; l < j + 5; ++l) { // Get coords of sample point on the rotated axis sample_x = cvRound(x + (-l*scale*si + k*scale*co)); sample_y = cvRound(y + ( l*scale*co + k*scale*si)); // Get the gaussian weighted x and y responses gauss = gaussian(k*scale, l*scale, 3.3f*scale); rx = gauss * haarX(sample_y, sample_x, 2*scale); ry = gauss * haarY(sample_y, sample_x, 2*scale); // Get the gaussian weighted x and y responses on rotated axis rrx = -rx*si + ry*co; rry = rx*co + ry*si; dx += rrx; dy += rry; mdx += fabs(rrx); mdy += fabs(rry); } } // add the values to the descriptor vector desc[count++] = dx; desc[count++] = dy; desc[count++] = mdx; desc[count++] = mdy; // store the current length^2 of the vector len += dx*dx + dy*dy + mdx*mdx + mdy*mdy; } } // convert to unit vector len = sqrt(len); for( i = 0; i < 64; i++) desc[i] /= len; }
//------------------------------------------------------- //! Get the upright descriptor vector of the provided Ipoint void Surf::getUprightDescriptor() { int y, x, count=0; float scale, *desc, dx, dy, mdx, mdy; float gauss, rx, ry, len = 0.0f; Ipoint *ipt = &ipts.at(index); scale = ipt->scale; y = cvRound(ipt->y); x = cvRound(ipt->x); desc = ipt->descriptor; // Calculate descriptor for this interest point for (int i = -10; i < 10; i+=5) { for (int j = -10; j < 10; j+=5) { dx=dy=mdx=mdy=0; for (int k = i; k < i + 5; ++k) { for (int l = j; l < j + 5; ++l) { // get Gaussian weighted x and y responses gauss = gaussian(k*scale, l*scale, 3.3f*scale); rx = gauss * haarX(k*scale+y, l*scale+x, 2*scale); ry = gauss * haarY(k*scale+y, l*scale+x, 2*scale); dx += rx; dy += ry; mdx += fabs(rx); mdy += fabs(ry); } } // add the values to the descriptor vector desc[count++] = dx; desc[count++] = dy; desc[count++] = mdx; desc[count++] = mdy; // store the current length^2 of the vector len += dx*dx + dy*dy + mdx*mdx + mdy*mdy; } } // convert to unit vector len = sqrt(len); for(i = 0; i < 64; i++) desc[i] /= len; }
반응형
'Programming > MFC-C++' 카테고리의 다른 글
[코드 최적화] C와 C++의 속도와 성능 비교 (0) | 2012.12.06 |
---|---|
SURF 중요 코드 (0) | 2012.11.12 |
AR 구현 관련 자료 (0) | 2012.11.06 |
[Kinect] 설치 방법 (0) | 2012.05.10 |
[Kinect] 자료 모음 (0) | 2012.05.10 |