【OpenCV】SIFT原理与源码分析:关键点描述
《SIFT原理与源码分析》系列文章索引:http://www.cnblogs.com/tianyalu/p/5467813.html
SIFT描述子h(x,y,θ)是对关键点附近邻域内高斯图像梯度统计的结果,是一个三维矩阵,但通常用一个矢量来表示。矢量通过对三维矩阵按一定规律排列得到。
描述子采样区域


源码
Point pt(cvRound(ptf.x), cvRound(ptf.y));
//计算余弦,正弦,CV_PI/180:将角度值转化为幅度值
float cos_t = cosf(ori*(float)(CV_PI/));
float sin_t = sinf(ori*(float)(CV_PI/));
float bins_per_rad = n / .f;
float exp_scale = -.f/(d * d * 0.5f); //d:SIFT_DESCR_WIDTH 4
float hist_width = SIFT_DESCR_SCL_FCTR * scl; // SIFT_DESCR_SCL_FCTR: 3
// scl: size*0.5f
// 计算图像区域半径mσ(d+1)/2*sqrt(2)
// 1.4142135623730951f 为根号2
int radius = cvRound(hist_width * 1.4142135623730951f * (d + ) * 0.5f);
cos_t /= hist_width;
sin_t /= hist_width;
区域坐标轴旋转

源码
//计算采样区域点坐标旋转
for( i = -radius, k = ; i <= radius; i++ )
for( j = -radius; j <= radius; j++ )
{
/*
Calculate sample's histogram array coords rotated relative to ori.
Subtract 0.5 so samples that fall e.g. in the center of row 1 (i.e.
r_rot = 1.5) have full weight placed in row 1 after interpolation.
*/
float c_rot = j * cos_t - i * sin_t;
float r_rot = j * sin_t + i * cos_t;
float rbin = r_rot + d/ - 0.5f;
float cbin = c_rot + d/ - 0.5f;
int r = pt.y + i, c = pt.x + j; if( rbin > - && rbin < d && cbin > - && cbin < d &&
r > && r < rows - && c > && c < cols - )
{
float dx = (float)(img.at<short>(r, c+) - img.at<short>(r, c-));
float dy = (float)(img.at<short>(r-, c) - img.at<short>(r+, c));
X[k] = dx; Y[k] = dy; RBin[k] = rbin; CBin[k] = cbin;
W[k] = (c_rot * c_rot + r_rot * r_rot)*exp_scale;
k++;
}
}
计算采样区域梯度直方图

源码
//计算梯度直方图
for( k = ; k < len; k++ )
{
float rbin = RBin[k], cbin = CBin[k];
float obin = (Ori[k] - ori)*bins_per_rad;
float mag = Mag[k]*W[k]; int r0 = cvFloor( rbin );
int c0 = cvFloor( cbin );
int o0 = cvFloor( obin );
rbin -= r0;
cbin -= c0;
obin -= o0; //n为SIFT_DESCR_HIST_BINS:8,即将360°分为8个区间
if( o0 < )
o0 += n;
if( o0 >= n )
o0 -= n; // histogram update using tri-linear interpolation
// 双线性插值
float v_r1 = mag*rbin, v_r0 = mag - v_r1;
float v_rc11 = v_r1*cbin, v_rc10 = v_r1 - v_rc11;
float v_rc01 = v_r0*cbin, v_rc00 = v_r0 - v_rc01;
float v_rco111 = v_rc11*obin, v_rco110 = v_rc11 - v_rco111;
float v_rco101 = v_rc10*obin, v_rco100 = v_rc10 - v_rco101;
float v_rco011 = v_rc01*obin, v_rco010 = v_rc01 - v_rco011;
float v_rco001 = v_rc00*obin, v_rco000 = v_rc00 - v_rco001; int idx = ((r0+)*(d+) + c0+)*(n+) + o0;
hist[idx] += v_rco000;
hist[idx+] += v_rco001;
hist[idx+(n+)] += v_rco010;
hist[idx+(n+)] += v_rco011;
hist[idx+(d+)*(n+)] += v_rco100;
hist[idx+(d+)*(n+)+] += v_rco101;
hist[idx+(d+)*(n+)] += v_rco110;
hist[idx+(d+)*(n+)+] += v_rco111;
}
关键点描述源码
// SIFT关键点特征描述
// SIFT描述子是关键点领域高斯图像提取统计结果的一种表示
static void calcSIFTDescriptor( const Mat& img, Point2f ptf, float ori, float scl,
int d, int n, float* dst ) {
Point pt(cvRound(ptf.x), cvRound(ptf.y));
//计算余弦,正弦,CV_PI/180:将角度值转化为幅度值
float cos_t = cosf(ori*(float)(CV_PI/));
float sin_t = sinf(ori*(float)(CV_PI/));
float bins_per_rad = n / .f;
float exp_scale = -.f/(d * d * 0.5f); //d:SIFT_DESCR_WIDTH 4
float hist_width = SIFT_DESCR_SCL_FCTR * scl; // SIFT_DESCR_SCL_FCTR: 3
// scl: size*0.5f
// 计算图像区域半径mσ(d+1)/2*sqrt(2)
// 1.4142135623730951f 为根号2
int radius = cvRound(hist_width * 1.4142135623730951f * (d + ) * 0.5f);
cos_t /= hist_width;
sin_t /= hist_width; int i, j, k, len = (radius*+)*(radius*+), histlen = (d+)*(d+)*(n+);
int rows = img.rows, cols = img.cols; AutoBuffer<float> buf(len* + histlen);
float *X = buf, *Y = X + len, *Mag = Y, *Ori = Mag + len, *W = Ori + len;
float *RBin = W + len, *CBin = RBin + len, *hist = CBin + len; //初始化直方图
for( i = ; i < d+; i++ )
{
for( j = ; j < d+; j++ )
for( k = ; k < n+; k++ )
hist[(i*(d+) + j)*(n+) + k] = .;
} //计算采样区域点坐标旋转
for( i = -radius, k = ; i <= radius; i++ )
for( j = -radius; j <= radius; j++ )
{
/*
Calculate sample's histogram array coords rotated relative to ori.
Subtract 0.5 so samples that fall e.g. in the center of row 1 (i.e.
r_rot = 1.5) have full weight placed in row 1 after interpolation.
*/
float c_rot = j * cos_t - i * sin_t;
float r_rot = j * sin_t + i * cos_t;
float rbin = r_rot + d/ - 0.5f;
float cbin = c_rot + d/ - 0.5f;
int r = pt.y + i, c = pt.x + j; if( rbin > - && rbin < d && cbin > - && cbin < d &&
r > && r < rows - && c > && c < cols - )
{
float dx = (float)(img.at<short>(r, c+) - img.at<short>(r, c-));
float dy = (float)(img.at<short>(r-, c) - img.at<short>(r+, c));
X[k] = dx; Y[k] = dy; RBin[k] = rbin; CBin[k] = cbin;
W[k] = (c_rot * c_rot + r_rot * r_rot)*exp_scale;
k++;
}
} len = k;
fastAtan2(Y, X, Ori, len, true);
magnitude(X, Y, Mag, len);
exp(W, W, len); //计算梯度直方图
for( k = ; k < len; k++ )
{
float rbin = RBin[k], cbin = CBin[k];
float obin = (Ori[k] - ori)*bins_per_rad;
float mag = Mag[k]*W[k]; int r0 = cvFloor( rbin );
int c0 = cvFloor( cbin );
int o0 = cvFloor( obin );
rbin -= r0;
cbin -= c0;
obin -= o0; //n为SIFT_DESCR_HIST_BINS:8,即将360°分为8个区间
if( o0 < )
o0 += n;
if( o0 >= n )
o0 -= n; // histogram update using tri-linear interpolation
// 双线性插值
float v_r1 = mag*rbin, v_r0 = mag - v_r1;
float v_rc11 = v_r1*cbin, v_rc10 = v_r1 - v_rc11;
float v_rc01 = v_r0*cbin, v_rc00 = v_r0 - v_rc01;
float v_rco111 = v_rc11*obin, v_rco110 = v_rc11 - v_rco111;
float v_rco101 = v_rc10*obin, v_rco100 = v_rc10 - v_rco101;
float v_rco011 = v_rc01*obin, v_rco010 = v_rc01 - v_rco011;
float v_rco001 = v_rc00*obin, v_rco000 = v_rc00 - v_rco001; int idx = ((r0+)*(d+) + c0+)*(n+) + o0;
hist[idx] += v_rco000;
hist[idx+] += v_rco001;
hist[idx+(n+)] += v_rco010;
hist[idx+(n+)] += v_rco011;
hist[idx+(d+)*(n+)] += v_rco100;
hist[idx+(d+)*(n+)+] += v_rco101;
hist[idx+(d+)*(n+)] += v_rco110;
hist[idx+(d+)*(n+)+] += v_rco111;
} // finalize histogram, since the orientation histograms are circular
// 最后确定直方图,目标方向直方图是圆的
for( i = ; i < d; i++ )
for( j = ; j < d; j++ )
{
int idx = ((i+)*(d+) + (j+))*(n+);
hist[idx] += hist[idx+n];
hist[idx+] += hist[idx+n+];
for( k = ; k < n; k++ )
dst[(i*d + j)*n + k] = hist[idx+k];
}
// copy histogram to the descriptor,
// apply hysteresis thresholding
// and scale the result, so that it can be easily converted
// to byte array
float nrm2 = ;
len = d*d*n;
for( k = ; k < len; k++ )
nrm2 += dst[k]*dst[k];
float thr = std::sqrt(nrm2)*SIFT_DESCR_MAG_THR;
for( i = , nrm2 = ; i < k; i++ )
{
float val = std::min(dst[i], thr);
dst[i] = val;
nrm2 += val*val;
}
nrm2 = SIFT_INT_DESCR_FCTR/std::max(std::sqrt(nrm2), FLT_EPSILON);
for( k = ; k < len; k++ )
{
dst[k] = saturate_cast<uchar>(dst[k]*nrm2);
}
}
至此SIFT描述子生成,SIFT算法也基本完成了~参见《SIFT原理与源码分析》
【OpenCV】SIFT原理与源码分析:关键点描述的更多相关文章
- 【OpenCV】SIFT原理与源码分析:关键点搜索与定位
<SIFT原理与源码分析>系列文章索引:http://www.cnblogs.com/tianyalu/p/5467813.html 由前一步<DoG尺度空间构造>,我们得到了 ...
- OpenCV SIFT原理与源码分析
http://blog.csdn.net/xiaowei_cqu/article/details/8069548 SIFT简介 Scale Invariant Feature Transform,尺度 ...
- 【OpenCV】SIFT原理与源码分析:DoG尺度空间构造
原文地址:http://blog.csdn.net/xiaowei_cqu/article/details/8067881 尺度空间理论 自然界中的物体随着观测尺度不同有不同的表现形态.例如我们形 ...
- 【OpenCV】SIFT原理与源码分析:方向赋值
<SIFT原理与源码分析>系列文章索引:http://www.cnblogs.com/tianyalu/p/5467813.html 由前一篇<关键点搜索与定位>,我们已经找到 ...
- 【OpenCV】SIFT原理与源码分析
SIFT简介 Scale Invariant Feature Transform,尺度不变特征变换匹配算法,是由David G. Lowe在1999年(<Object Recognition f ...
- OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波
http://blog.csdn.net/chenyusiyuan/article/details/8710462 OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波 201 ...
- ConcurrentHashMap实现原理及源码分析
ConcurrentHashMap实现原理 ConcurrentHashMap源码分析 总结 ConcurrentHashMap是Java并发包中提供的一个线程安全且高效的HashMap实现(若对Ha ...
- HashMap和ConcurrentHashMap实现原理及源码分析
HashMap实现原理及源码分析 哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表, ...
- (转)ReentrantLock实现原理及源码分析
背景:ReetrantLock底层是基于AQS实现的(CAS+CHL),有公平和非公平两种区别. 这种底层机制,很有必要通过跟踪源码来进行分析. 参考 ReentrantLock实现原理及源码分析 源 ...
随机推荐
- 百度地图之自动提示--autoComplete
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- mongo复杂操作
相比关系型数据库, Array [1,2,3,4,5] 和 Object { 'name':'DragonFire' } 是MongoDB 比较特殊的类型了 特殊在哪里呢?在他们的操作上又有什么需要注 ...
- python爬取淘宝华为手机
import re from selenium import webdriver from selenium.common.exceptions import TimeoutException fro ...
- hdu - 6277,2018CCPC湖南全国邀请赛B题,找规律,贪心找最优.
题意: 给出N个小时,分配这些小时去写若干份论文,若用1小时写一份论文,该论文会被引用A次,新写一篇论文的话,全面的论文会被新论文引用一次. 找最大的H,H是指存在H遍论文,而且这些论文各被引用大于H ...
- 小数第n位:高精度
小数第n位 问题描述 我们知道,整数做除法时,有时得到有限小数,有时得到无限循环小数. 如果我们把有限小数的末尾加上无限多个0,它们就有了统一的形式. 本题的任务是:在上面的约定下,求整数除法小数点后 ...
- Visual Studio 调试时无法命中断点
1.查看代码优化是否勾选,如有去掉勾选 2.确保是在Debug模式下设置的断点 3.确保在启动时未修改代码即“要求源文件和原始版本完全匹配” 4.DLL的引用问题
- 《Linux内核与分析》第五周
20135130王川东 一.给MenuOS增加time和time-asm命令 命令:1.强制删除:rm menu -rf 2.克隆:git clone (后跟需要克隆数据所在的位置) 3.自动编译,自 ...
- MySql 8 命令
1-创建用户 create user 用户名@'%' identified by '密码'; create user 用户名@'localhost' identified by '密码'; 2-授 ...
- HDU 5855 Less Time, More profit 最大权闭合子图
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5855 Less Time, More profit Time Limit: 2000/1000 MS ...
- Alpha-6
前言 失心疯病源6 团队代码管理github 站立会议 队名:PMS 530雨勤(组长) 今天完成了那些任务 18:30~20:30 完成blob类下关于预测车辆下一个位置的函数 代码签入github ...