반응형
File List
o Main.cpp
o integral.cpp
o fasthessian.cpp
o surf.cpp
o surflib.h
o utils.cpp
o ipoint.h
o fasthessian.h
o utils.h
o surf.h
Main.cpp
#include "surflib.h"
//-------------------------------------------------------
// Define PROCEDURE as:
// - 1 and supply image path to run on static image
// - 2 to capture from a webcam
#define PROCEDURE 1
//-------------------------------------------------------
int mainImage(const char *filename);
int mainVideo(void);
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;
}
//-------------------------------------------------------
int mainVideo(void)
{
// Initialise capture device
CvCapture* capture = cvCaptureFromCAM( CV_CAP_ANY );
if(!capture) error("No Capture");
// Create a window
cvNamedWindow("OpenSURF", CV_WINDOW_AUTOSIZE );
// Declare Ipoints and other stuff
IpVec ipts;
IplImage *img=NULL;
// Main capture loop
while( 1 )
{
// Grab frame from the capture source
img = cvQueryFrame(capture);
// Detect and describe interest points in the image
surfDetDes(img, ipts, false, 3, 4, 2, 0.002f);
// Draw the detected points
drawIpoints(img, ipts);
// Draw the FPS figure
drawFPS(img);
// Display the result
cvShowImage("OpenSURF", img);
// If ESC key pressed exit loop
if( (cvWaitKey(10) & 255) == 27 ) break;
}
// Release the capture device
cvReleaseCapture( &capture );
cvDestroyWindow( "OpenSURF" );
return 0;
}
//-------------------------------------------------------
integral.cpp
#include "cv.h"
#include "highgui.h"
#include "integral.h"
#include "utils.h"
//! Computes the integral image of image img. Assumes source image to be a
//! 32-bit floating point. Returns IplImage of 32-bit float form.
IplImage *Integral(IplImage *source)
{
// convert the image to single channel 32f
IplImage *img = getGray(source);
IplImage *int_img = cvCreateImage(cvGetSize(img), IPL_DEPTH_32F, 1);
// set up variables for data access
int height = img->height;
int width = img->width;
int step = img->widthStep/sizeof(float);
float *data = (float *) img->imageData;
float *i_data = (float *) int_img->imageData;
// calculate integral image values
for(int i=0; i<height; i++)
{
float rs = 0.0f;
for(int j=0; j<width; j++)
{
// cumulative row sum
rs = rs+data[i*step+j];
// integral image sum
if (i*step+j >= step)
{
i_data[i*step+j] = i_data[(i-1)*step+j]+rs;
}
else
{
// these values computed for first row only
i_data[i*step+j] = rs;
}
}
}
// release the gray image
cvReleaseImage(&img);
// return the integral image
return int_img;
}
//-------------------------------------------------------
//! Computes the sum of pixels within the rectangle specified by the top-left start
//! co-ordinate (x,y) with width w and height h.
float Area(IplImage *img, int x, int y, int w, int h)
{
float *data = (float *) img->imageData;
int step = img->widthStep/sizeof(float);
int x1=x-1, y1=y-1, x2=x1+w, y2=y1+h;
// if all values are within bounds return BR + TL - (BL + TR)
if (x1>=0 && y1 >=0 && x2<img->width && y2<img->height)
{
return data[y2*step+x2] + data[y1*step+x1]
-(data[y2*step+x1] + data[y1*step+x2]);
}
else
return 0;
}
fasthessian.cpp
#include "cv.h"
#include "integral.h"
#include "fasthessian.h"
#include "ipoint.h"
#include "utils.h"
#include <vector>
#include <iostream>
using namespace std;
//! Destructor
FastHessian::~FastHessian()
{
// free the det array
if (m_det) delete [] m_det;
}
//-------------------------------------------------------
//! Constructor without image
FastHessian::FastHessian(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;
}
//-------------------------------------------------------
//! 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);
}
//-------------------------------------------------------
//! Set or re-set the integral image source
void FastHessian::setIntImage(IplImage *img)
{
// Change the source image
this->img = img;
// Redefine width, height and det map only if image has changed size
if (img->width != i_width || img->height != i_height)
{
i_width = img->width;
i_height = img->height;
// Allocate space for determinant of hessian pyramid
if (m_det) delete [] m_det;
m_det = new float [octaves*intervals*i_width*i_height];
memset(m_det,0,sizeof(m_det));
}
}
//-------------------------------------------------------
//! 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;
}
//-------------------------------------------------------
//! Return the value of the approximated determinant of hessian
inline float FastHessian::getVal(int o, int i, int c, int r)
{
return fabs(m_det[(o*intervals+i)*(i_width*i_height) + (r*i_width+c)]);
}
//-------------------------------------------------------
//! Return the sign of the laplacian (trace of the hessian)
inline int FastHessian::getLaplacian(int o, int i, int c, int r)
{
float res = (m_det[(o*intervals+i)*(i_width*i_height) + (r*i_width+c)]);
return (res >= 0 ? 1 : -1);
}
//-------------------------------------------------------
//! Round an int to a float
inline int FastHessian::fRound(float flt)
{
return (int) floor(flt+0.5f);
}
//-------------------------------------------------------
//! 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)]);
}
//-------------------------------------------------------
//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( int 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;
}
//-------------------------------------------------------
surf.cpp
#include "cv.h"
#include "highgui.h"
#include "integral.h"
#include "surf.h"
#include "utils.h"
#include <fstream>
#include <iostream>
using namespace std;
const float pi = float(CV_PI);
//! Destructor
Surf::~Surf()
{
}
//-------------------------------------------------------
//! Constructor
Surf::Surf(IplImage *img, IpVec &ipts)
: ipts(ipts)
{
this->img = img;
}
//-------------------------------------------------------
//! 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;
}
//-------------------------------------------------------
//! Calculate the value of the 2d gaussian at x,y
inline float Surf::gaussian(int x, int y, float sig)
{
return 1.0f/(2.0f*pi*sig*sig) * exp( -(x*x+y*y)/(2.0f*sig*sig));
}
//-------------------------------------------------------
//! Calculate the value of the 2d gaussian at x,y
inline float Surf::gaussian(float x, float y, float sig)
{
return 1.0f/(2.0f*pi*sig*sig) * exp( -(x*x+y*y)/(2.0f*sig*sig));
}
//-------------------------------------------------------
//! Calculate Haar wavelet responses in x direction
inline float Surf::haarX(int row, int column, int s)
{
return Area(img, column, row-s/2, s/2, s)
-1 * Area(img, column-s/2, row-s/2, s/2, s);
}
//-------------------------------------------------------
//! Calculate Haar wavelet responses in y direction
inline float Surf::haarY(int row, int column, int s)
{
return Area(img, column-s/2, row, s, s/2)
-1 * Area(img, column-s/2, row-s/2, s, s/2);
}
//-------------------------------------------------------
//! Get the angle from the +ve x-axis of the vector given by (X Y)
float Surf::getAngle(float X, float Y)
{
if(X >= 0 && Y >= 0)
return atan(Y/X);
if(X < 0 && Y >= 0)
return pi - atan(-Y/X);
if(X < 0 && Y < 0)
return pi + atan(Y/X);
if(X >= 0 && Y < 0)
return 2*pi - atan(-Y/X);
return 0;
}
surflib.h
#ifndef SURFLIB_H
#define SURFLIB_H
#include "cv.h"
#include "highgui.h"
#include "integral.h"
#include "fasthessian.h"
#include "surf.h"
#include "ipoint.h"
#include "utils.h"
// typedef away STL mess!
typedef std::vector<Ipoint> IpVec;
//! 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);
}
//! Library function builds vector of interest points
inline void surfDet(IplImage *img, /* image to find Ipoints in */
std::vector<Ipoint> &ipts, /* reference to vector of Ipoints */
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();
// Deallocate the integral image
cvReleaseImage(&int_img);
}
//! Library function describes interest points in vector
inline void surfDes(IplImage *img, /* image to find Ipoints in */
std::vector<Ipoint> &ipts, /* reference to vector of Ipoints */
bool upright = false) /* run in rotation invariant mode? */
{
// Create integral image representation of the image
IplImage *int_img = Integral(img);
// 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);
}
#endif
utils.cpp
#include "cv.h"
#include "highgui.h"
#include "utils.h"
#include <iostream>
#include <fstream>
#include <time.h>
using namespace std;
//-------------------------------------------------------
//! Display error message and terminate program
void error(char *msg)
{
cout << "\nError: " << msg;
getchar();
exit(0);
}
//-------------------------------------------------------
//! Show the provided image and wait for keypress
void showImage(IplImage *img)
{
cvNamedWindow("Surf", CV_WINDOW_AUTOSIZE);
cvShowImage("Surf", img);
cvWaitKey(0);
}
//-------------------------------------------------------
//! Show the provided image in titled window and wait for keypress
void showImage(char *title, IplImage *img)
{
cvNamedWindow(title, CV_WINDOW_AUTOSIZE);
cvShowImage(title, img);
cvWaitKey(0);
}
//-------------------------------------------------------
// Convert image to single channel 32F
IplImage* getGray(IplImage *img)
{
IplImage* gray8, * gray32;
gray8 = cvCreateImage( cvGetSize(img), IPL_DEPTH_8U, 1 );
gray32 = cvCreateImage( cvGetSize(img), IPL_DEPTH_32F, 1 );
if( img->nChannels == 1 )
gray8 = (IplImage *) cvClone( img );
else
cvCvtColor( img, gray8, CV_BGR2GRAY );
cvConvertScale( gray8, gray32, 1.0 / 255.0, 0 );
cvReleaseImage( &gray8 );
return gray32;
}
//-------------------------------------------------------
//! Draw all the Ipoints in the provided vector
void drawIpoints(IplImage *img, vector<Ipoint> &ipts, int tailSize)
{
Ipoint *ipt;
float s, o;
int r1, c1, r2, c2, lap;
for(unsigned int i = 0; i < ipts.size(); i++)
{
ipt = &ipts.at(i);
s = ((9.0f/1.2f) * ipt->scale) / 3.0f;
o = ipt->orientation;
lap = ipt->laplacian;
r1 = cvRound(ipt->y);
c1 = cvRound(ipt->x);
c2 = cvRound(s * cos(o)) + c1;
r2 = cvRound(s * sin(o)) + r1;
// Green line indicates orientation
cvLine(img, cvPoint(c1, r1), cvPoint(c2, r2), cvScalar(0, 255, 0));
if (lap >= 0)
{ // Blue circles indicate light blobs on dark backgrounds
cvCircle(img, cvPoint(c1,r1), cvRound(s), cvScalar(255, 0, 0),1);
}
else
{ // Red circles indicate light blobs on dark backgrounds
cvCircle(img, cvPoint(c1,r1), cvRound(s), cvScalar(0, 0, 255),1);
}
// Draw motion from ipoint dx and dy
if (tailSize)
{
cvLine(img, cvPoint(c1,r1),
cvPoint(int(c1+ipt->dx*tailSize), int(r1+ipt->dy*tailSize)),
cvScalar(255,255,255), 1);
}
}
}
//-------------------------------------------------------
//! Draw a single feature on the image
void drawIpoint(IplImage *img, Ipoint &ipt)
{
float s, o;
int r1, c1, r2, c2, lap;
s = ((9.0f/1.2f) * ipt.scale) / 3.0f;
s*=3;
o = ipt.orientation;
lap = ipt.laplacian;
r1 = cvRound(ipt.y);
c1 = cvRound(ipt.x);
c2 = cvRound(s * cos(o)) + c1;
r2 = cvRound(s * sin(o)) + r1;
// Green line indicates orientation
cvLine(img, cvPoint(c1, r1), cvPoint(c2, r2), cvScalar(0, 255, 0));
if (lap >= 0)
{ // Blue circles indicate light blobs on dark backgrounds
cvCircle(img, cvPoint(c1,r1), cvRound(s), cvScalar(255, 0, 0),1);
}
else
{ // Red circles indicate light blobs on dark backgrounds
cvCircle(img, cvPoint(c1,r1), cvRound(s), cvScalar(0, 0, 255),1);
}
}
//-------------------------------------------------------
//! Draw a single feature on the image
void drawPoint(IplImage *img, Ipoint &ipt)
{
float s, o;
int r1, c1;
s = 4;
o = ipt.orientation;
r1 = cvRound(ipt.y);
c1 = cvRound(ipt.x);
cvCircle(img, cvPoint(c1,r1), cvRound(s), cvScalar(0, 255, 0), -1);
cvCircle(img, cvPoint(c1,r1), cvRound(s+1), cvScalar(255, 0,0), 2);
}
//-------------------------------------------------------
//! Draw a single feature on the image
void drawPoints(IplImage *img, vector<Ipoint> &ipts)
{
float s, o;
int r1, c1;
for(unsigned int i = 0; i < ipts.size(); i++)
{
s = 10;
o = ipts[i].orientation;
r1 = cvRound(ipts[i].y);
c1 = cvRound(ipts[i].x);
cvCircle(img, cvPoint(c1,r1), cvRound(s), cvScalar(0, 255, 0), -1);
cvCircle(img, cvPoint(c1,r1), cvRound(s+1), cvScalar(255, 0,0), 2);
}
}
//-------------------------------------------------------
//! Draw descriptor windows around Ipoints in the provided vector
void drawWindows(IplImage *img, vector<Ipoint> &ipts)
{
Ipoint *ipt;
float s, o, cd, sd;
int x, y;
CvPoint2D32f src[4];
for(int i = 0; i < cvRound(ipts.size()); i++)
{
ipt = &ipts.at(i);
s = (10 * ipt->scale);
o = ipt->orientation;
y = cvRound(ipt->y);
x = cvRound(ipt->x);
cd = cos(o);
sd = sin(o);
src[0].x=sd*s+cd*s+x; src[0].y=-cd*s+sd*s+y;
src[1].x=sd*s+cd*-s+x; src[1].y=-cd*s+sd*-s+y;
src[2].x=sd*-s+cd*-s+x; src[2].y=-cd*-s+sd*-s+y;
src[3].x=sd*-s+cd*s+x; src[3].y=-cd*-s+sd*s+y;
// Draw orientation line
cvLine(img, cvPoint(cvRound(x), cvRound(y)),
cvPoint(cvRound(s*cd + x), cvRound(s*sd + y)), cvScalar(0, 255, 0),1);
// Draw box window around the point
cvLine(img, cvPoint(cvRound(src[0].x), cvRound(src[0].y)),
cvPoint(cvRound(src[1].x), cvRound(src[1].y)), cvScalar(255, 0, 0),2);
cvLine(img, cvPoint(cvRound(src[1].x), cvRound(src[1].y)),
cvPoint(cvRound(src[2].x), cvRound(src[2].y)), cvScalar(255, 0, 0),2);
cvLine(img, cvPoint(cvRound(src[2].x), cvRound(src[2].y)),
cvPoint(cvRound(src[3].x), cvRound(src[3].y)), cvScalar(255, 0, 0),2);
cvLine(img, cvPoint(cvRound(src[3].x), cvRound(src[3].y)),
cvPoint(cvRound(src[0].x), cvRound(src[0].y)), cvScalar(255, 0, 0),2);
}
}
//-------------------------------------------------------
// Draw the FPS figure on the image (requires at least 2 calls)
void drawFPS(IplImage *img)
{
static clock_t t;
char fps_text[20];
CvFont font;
cvInitFont(&font,CV_FONT_HERSHEY_SIMPLEX|CV_FONT_ITALIC, 1.0,1.0,0,2);
// Add fps figure
float fps = (1.0f/(clock()-t) * CLOCKS_PER_SEC);
// Update variables
t=clock();
// Get the figure as a string
sprintf(fps_text,"FPS: %.2f",fps);
// Draw the string on the image
cvPutText (img,fps_text,cvPoint(10,25), &font, cvScalar(255,255,0));
}
//-------------------------------------------------------
//! Save the SURF features to file
void saveSurf(char *filename, vector<Ipoint> &ipts)
{
ofstream outfile(filename);
// output descriptor length
outfile << "64\n";
outfile << ipts.size() << "\n";
// create output line as: scale x y des
for(unsigned int i=0; i < ipts.size(); i++)
{
outfile << ipts.at(i).scale << " ";
outfile << ipts.at(i).x << " ";
outfile << ipts.at(i).y << " ";
for(int j=0; j<64; j++)
outfile << ipts.at(i).descriptor[j] << " ";
outfile << "\n";
}
outfile.close();
}
//-------------------------------------------------------
//! Load the SURF features from file
void loadSurf(char *filename, vector<Ipoint> &ipts)
{
int count;
float temp;
ifstream infile(filename);
// output descriptor length
infile >> count;
infile >> count;
for (int i = 0; i < count; i++)
{
Ipoint ipt;
infile >> ipt.x;
infile >> ipt.y;
infile >> temp;
ipt.scale = temp;
ipt.laplacian = 1;
for (int j = 0; j < 3; j++)
infile >> temp;
for (j = 0; j < 64; j++)
infile >> ipt.descriptor[j];
ipts.push_back(ipt);
}
}
ipoint.h
#ifndef IPOINT_H
#define IPOINT_H
class Ipoint {
public:
//! Destructor
~Ipoint() {};
//! Constructor
Ipoint() : orientation(0) {};
//! Coordinates of the detected interest point
float x, y;
//! Detected scale
float scale;
//! Orientation measured anti-clockwise from +ve x-axis
float orientation;
//! Sign of laplacian for fast matching purposes
int laplacian;
//! Vector of descriptor components
float descriptor[64];
//! Placeholds for point motion (can be used for frame to frame motion analysis)
float dx, dy;
//! Used to store cluster index
int clusterIndex;
};
#endif
fasthessian.h
#ifndef FASTHESSIAN_H
#define FASTHESSIAN_H
#include "cv.h"
#include "integral.h"
#include "ipoint.h"
#include <vector>
static const int OCTAVES = 3;
static const int INTERVALS = 4;
static const float THRES = 0.002f;
static const int INIT_SAMPLE = 2;
class FastHessian {
public:
//! Destructor
~FastHessian();
//! Constructor without image
FastHessian(std::vector<Ipoint> &ipts,
const int octaves = OCTAVES,
const int intervals = INTERVALS,
const int init_sample = INIT_SAMPLE,
const float thres = THRES);
//! Constructor with image
FastHessian(IplImage *img,
std::vector<Ipoint> &ipts, int octaves = OCTAVES,
const int intervals = INTERVALS,
const int init_sample = INIT_SAMPLE,
const float thres = THRES);
//! Set or re-set the integral image source
void setIntImage(IplImage *img);
//! Find the image features and write into vector of features
void getIpoints();
private:
//---------------- Private Functions -----------------//
//! Calculate determinant of hessian responses
void buildDet();
//! Non Maximal Suppression function
int isExtremum(int octave, int interval, int column, int row);
//! Return the value of the approximated determinant of hessian
inline float getVal(int octave, int interval, int column, int row);
//! Return the sign of the laplacian (trace of the hessian)
inline int getLaplacian(int o, int i, int c, int r);
//! Round an int to a float
inline int fRound(float flt);
//! Interpolation functions - adapted from Lowe's SIFT interpolation
void interp_extremum(int octv, int intvl, int r, int c);
void interp_step( int octv, int intvl, int r, int c, double* xi, double* xr, double* xc );
CvMat* deriv_3D( int octv, int intvl, int r, int c );
CvMat* hessian_3D(int octv, int intvl, int r, int c );
inline float getValLowe(int octave, int interval, int column, int row);
//---------------- Private Variables -----------------//
//! Pointer to the integral Image, and its attributes
IplImage *img;
int i_width, i_height;
//! Reference to vector of features passed from outside
std::vector<Ipoint> &ipts;
//! Number of Octaves
int octaves;
//! Number of Intervals per octave
int intervals;
//! Initial sampling step for Ipoint detection
int init_sample;
//! Threshold value for blob resonses
float thres;
//! Array stack of determinant of hessian values
float *m_det;
};
#endif
utils.h
#ifndef UTILS_H #define UTILS_H #include "cv.h" #include "ipoint.h" #include <vector> //! Display error message and terminate program void error(char *msg); //! Show the provided image and wait for keypress void showImage(IplImage *img); //! Show the provided image in titled window and wait for keypress void showImage(char *title, IplImage *img); // Convert image to single channel 32F IplImage* getGray(IplImage *img); //! Draw a single feature on the image void drawIpoint(IplImage *img, Ipoint &ipt); //! Draw all the Ipoints in the provided vector void drawIpoints(IplImage *img, std::vector<Ipoint> &ipts, int tailSize = 0); //! Draw descriptor windows around Ipoints in the provided vector void drawWindows(IplImage *img, std::vector<Ipoint> &ipts); // Draw the FPS figure on the image (requires at least 2 calls) void drawFPS(IplImage *img); //! Draw a Point at feature location void drawPoint(IplImage *img, Ipoint &ipt); //! Draw a Point at all features void drawPoints(IplImage *img, std::vector<Ipoint> &ipts); //! Save the SURF features to file void saveSurf(char *filename, std::vector<Ipoint> &ipts); //! Load the SURF features from file void loadSurf(char *filename, std::vector<Ipoint> &ipts); #endif
surf.h
#ifndef SURF_H
#define SURF_H
#include "cv.h"
#include "ipoint.h"
#include "integral.h"
#include <vector>
typedef std::vector<Ipoint> IpVec;
class Surf {
public:
//! Destructor
~Surf();
//! Standard Constructor (img is an integral image)
Surf(IplImage *img, std::vector<Ipoint> &ipts);
//! Describe all features in the supplied vector
void getDescriptors(bool upright);
private:
//---------------- Private Functions -----------------//
//! Assign the current Ipoint an orientation
void getOrientation();
//! Get the descriptor vector of the current Ipoint
void getDescriptor();
//! Get the upright descriptor vector of the current Ipoint
void getUprightDescriptor();
//! Calculate the value of the 2d gaussian at x,y
inline float gaussian(int x, int y, float sig);
inline float gaussian(float x, float y, float sig);
//! Calculate Haar wavelet responses in x and y directions
inline float haarX(int row, int column, int size);
inline float haarY(int row, int column, int size);
//! Get the angle from the +ve x-axis of the vector given by [X Y]
float getAngle(float X, float Y);
//---------------- Private Variables -----------------//
//! Integral image where Ipoints have been detected
IplImage *img;
//! Ipoints vector
IpVec &ipts;
//! Index of current Ipoint in the vector
int index;
};
#endif
반응형
'Programming > MFC-C++' 카테고리의 다른 글
| [코드 네이밍] Coding Naming Rules (0) | 2012.12.06 |
|---|---|
| [코드 최적화] C와 C++의 속도와 성능 비교 (0) | 2012.12.06 |
| SURF(Speed up Robust Features) Code (0) | 2012.11.12 |
| AR 구현 관련 자료 (0) | 2012.11.06 |
| [Kinect] 설치 방법 (0) | 2012.05.10 |