opensurf具体过程分析

源码下载地址: http://opensurf1.googlecode.com/files/OpenSURFcpp.zip

具体函数调用即surflib里面的surfDetDes函数。本文就如下代码段作个分析

 void surfDetDes(IplImage *img,  /* 检测兴趣点的图像 image to find Ipoints in */
					   std::vector<Ipoint> &ipts, /* 兴趣点向量的引用reference to vector of Ipoints */
					   bool upright, /*是否是旋转不变模式 run in rotation invariant mode? */
					   int octaves, /* 高斯金字塔的组number of octaves to calculate */
					   int intervals, /* 高斯金字塔每组的层number of intervals per octave层 */
					   int init_sample,  /* 初始抽样步骤 initial sampling step */
					   float 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();

	//创建Surf描述子对象  Create Surf Descriptor Object
	Surf des(int_img, ipts);

	// 提取ipts的描述子 Extract the descriptors for the ipts
	des.getDescriptors(upright);

	// Deallocate the integral image
	cvReleaseImage(&int_img);
}

首先是创建积分图像(IplImage *Integral(IplImage *source)),也就是说在积分图像中的每个像素点的值即该点的积分值,也就是以该点为右下角,图像原点为左上角的矩形区域内所有像素的总和。

积分过程具体如下,表1假设为 data数据,表2为需要生成的积分图i_data,首先对 i_data 第一行赋值,即相同位置 data同行 前面像素累加。对于第二行,则为相同位置data同行 前面像素累加再 加上 i_data中上一行同列的像素值。
表1
0123
4567
表2
00+1=10+1+2=30+1+2+3=6
45+4+1=106+5+4+3=187+6+5+4+6=28

积分图构造完毕后,接着是创建快速海森矩阵FastHessian
首先调用构造函数创建对象fh,主要是保证参数有效性以及初始化图像参数。
 

主要提取特征点函数:fh.getIpoints(),主要过程如下:

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 i = 0; i < octaves; ++i) //第几组
	  for (int j = 0; j <= 1; ++j) //第几列
	  {
		b = responseMap.at(filter_map[i][j]);//0指向filter9
		m = responseMap.at(filter_map[i][j+1]);//15
		t = responseMap.at(filter_map[i][j+2]);//21

		// loop over middle response layer at density of the most 
		// sparse layer (always top), to find maxima across scale and space
		for (int h = 0; h < t->height; ++h)
		{
		  for (int w = 0; w < t->width; ++w)
		  {
			if (isExtremum(h, w, t, m, b))
			{
			  interpolateExtremum(h, w, t, m, b);
			}
		  }
		}
	  }
}
首先初始化filter_map,如下所示共12个filtersize,与 filter_map[][]正好对应
9,15,21,27,39,51,75,99,147,195,291,387

然后调用buildResponseMap():

主要执行操作responseMap.push_back(new ResponseLayer(w,   h,   s,   9));  共执行12次,即每种size的fiter。

ResponseLayer类的构造函数如下:

 ResponseLayer(int width, int height, int step, int filter)
  {
    assert(width > 0 && height > 0);
    
    this->width = width;
    this->height = height;
    this->step = step;//采样因子
    this->filter = filter;//盒子滤波的大小

    responses = new float[width*height];//存放每个大小的filer下的图像像素点的海森矩阵的行列式值
    laplacian = new unsigned char[width*height];//存放laplacian标识符,判断是暗背景上的亮斑还是亮背景的暗斑

    memset(responses,0,sizeof(float)*width*height);
    memset(laplacian,0,sizeof(unsigned char)*width*height);
  }
通过buildResponseLayer(ResponseLayer * rl)函数计算海森矩阵的值

void FastHessian::buildResponseLayer(ResponseLayer *rl)
{
  float *responses = rl->responses;         // response storage
  unsigned char *laplacian = rl->laplacian; // laplacian sign storage
  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;

  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; 

      // Compute response components
	  //整个区域-3倍中间区域,即权值为2的区域
      Dxx = BoxIntegral(img, r - l + 1, c - b, 2*l - 1, w)//BoxIntegral(积分图,起点行,起点列,高度,宽度):求矩形区域内的积分,即像素总和A+D-B-C
          - 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);//Laplacian标识符
}

其中Dxx、Dyy、Dxy的计算说明如下,以filtersize=9为例,b=4,l=3,w=9,假设中心红点处的坐标值为为(r,c)=(4,4),则整体区域的起点为(0,2)

Dyy=整个区域(2个黄色+绿色)-3*绿色

这样就计算出了每一层的所有像素点的det(Happrox)=dxx*dyy-(0.9*dxy)2,下面开始判断当前点是否是极值点。

代码部分回到getIpoints()4个for循环嵌套,抽取每组(共octaves组)相邻的3层(每组分别为4层),所以总共能抽取2次,即i=0;i<=1的情况。

在判断极值点的时候分别用到了isExtremum():非最大值抑制和interpolateExtremum()两个函数,



  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值