FAST角点的本质
FAST (Features from Accelerated Segment Test) 算法的核心思想是:
判断某个像素点周围是否存在一段连续的亮或暗像素环(通常取 16 个像素组成的圆),如果有足够多连续的像素明显比中心点亮或暗,则这个点就是角点。
FAST 角点检测的本质是:检测亮度变化方向突变的点,也就是“局部区域亮度分布不连续”的位置。
换句话说:
如果像素处于平坦区域 → 周围像素亮度几乎相同 → 不是角点;
如果像素处于边缘上 → 一侧亮、一侧暗,但只有一边变化 → 不是角点;
如果像素处于角落 → 周围有两种以上方向的明显亮度变化 → 是角点。
-2k7e.png)
从Harris到SuperPoint: 一篇“简短”的角点检测算法总结 - 知乎
详细的论文解析可以看上面这篇文章,重点看FAST算法这一章,别的可以参考学习一下。
角点可以通俗理解成就是判断各种形状的角,像是三角形的三个角,正方体的八个角等等。
该小节简要讲说明FAST角点的本质,目的是为了下文讲他的算法时更好理解。
xFCoreScore函数
作用:定义计算 FAST 角点核心分数的函数。
void xFCoreScore(short int flag_d,int threshold, uchart core)
{
#pragma HLS INLINE
short int flag_d_min2[NUM-1];
short int flag_d_max2[NUM-1];
short int flag_d_min4[NUM-3];
short int flag_d_max4[NUM-3];
short int flag_d_min8[NUM-7];
short int flag_d_max8[NUM-7];
for(ap_uint<5> i=0;i<NUM-1;i++)
{
flag_d_min2[i] = __MIN(flag_d[i],flag_d[i+1]);
flag_d_max2[i] = __MAX(flag_d[i],flag_d[i+1]);
}
for(ap_uint<5> i=0;i<NUM-3;i++)
{
flag_d_min4[i] = __MIN(flag_d_min2[i],flag_d_min2[i+2]);
flag_d_max4[i] = __MAX(flag_d_max2[i],flag_d_max2[i+2]);
}
for(ap_uint<5> i=0;i<NUM-7;i++)
{
flag_d_min8[i] = __MIN(flag_d_min4[i],flag_d_min4[i+4]);
flag_d_max8[i] = __MAX(flag_d_max4[i],flag_d_max4[i+4]);
}
uchar_t a0= _threshold;
for(ap_uint<5> i=0;i<PSize;i+=2)
{
short int a=255;
if(PSize == 16) {
a = flag_d_min8[i+1];
}
// else {
// for(ap_uint<5> j=1;j<PSize/2+1;j++)
// {
// a=__MIN(a,flag_d[i+j]);
// }
// }
a0=__MAX(a0,__MIN(a,flag_d[i])); // a0 >= _threshold
a0=__MAX(a0,__MIN(a,flag_d[i+PSize/2+1]));
}
short int b0= -_threshold;
for(ap_uint<5> i=0;i<PSize;i+=2)
{
short int b=-255;
if(PSize == 16) {
b = flag_d_max8[i+1];
}
// } else {
// for(ap_uint<5> j=1;j<PSize/2+1;j++)
// {
// b=__MAX(b,flag_d[i+j]);
// }
// }
b0=__MIN(b0,__MAX(b,flag_d[i])); // b0 <= -_threshold
b0=__MIN(b0,__MAX(b,flag_d[i+PSize/2+1]));
}
*core = __MAX(a0,-b0)-1;
} // Core window score computation complete代码解析:
函数定义
flag_d:输入数组,存储 “中心像素与周围NUM个采样点的灰度差”(I_pixel - I_center,NUM通常为 16,对应 FAST-16 的 16 个离散采样点)
_threshold:FAST 角点检测的基础阈值(如 10),用于判断灰度差是否显著。
core:输出参数,存储计算得到的角点分数(uchar_t类型,0~255,分数越高角点越稳定)
硬件优化指令
#pragma HLS INLINE
作用:HLS(高层次综合)指令,将函数 “内联” 到调用处(无函数调用开销),适合硬件流水线设计(减少模块间延迟)。
多级极值金字塔数组定义
short int flag_d_min2[NUM-1];
short int flag_d_max2[NUM-1];
short int flag_d_min4[NUM-3];
short int flag_d_max4[NUM-3];
short int flag_d_min8[NUM-7];
short int flag_d_max8[NUM-7];定义 3 组数组,用于存储不同粒度的 “局部极值”(最小值min和最大值max),构建 “2 元素→4 元素→8 元素” 的极值金字塔。
假设NUM=16(FAST-16 的 16 个采样点):
flag_d_min2/max2:存储 15 组 “相邻 2 个采样点” 的极值(16-1=15);
flag_d_min4/max4:存储 13 组 “4 个采样点” 的极值(16-3=13);
flag_d_min8/max8:存储 9 组 “8 个采样点” 的极值(16-7=9)。
第一级:二元素极值运算
for(ap_uint<5> i=0;i<NUM-1;i++)
{
flag_d_min2[i] = __MIN(flag_d[i],flag_d[i+1]);
flag_d_max2[i] = __MAX(flag_d[i],flag_d[i+1]);
}作用:计算相邻 2 个采样点的最小 / 最大灰度差,压缩数据维度。
例:i=0时,flag_d_min2[0] = min(flag_d[0], flag_d[1])(第 0 和 1 个采样点的最小值)
硬件意义:15 个并行比较器同时工作,1 个时钟周期完成,替代逐个比较的低效方式。
第二级:四元素极值运算
for(ap_uint<5> i=0;i<NUM-3;i++)
{
flag_d_min4[i] = __MIN(flag_d_min2[i],flag_d_min2[i+2]);
flag_d_max4[i] = __MAX(flag_d_max2[i],flag_d_max2[i+2]);
}作用:基于 2 元素极值,计算 4 个采样点的最小 / 最大灰度差(覆盖更宽范围)
例:i=0时,flag_d_min4[0] = min(flag_d_min2[0], flag_d_min2[2]),而flag_d_min2[0]对应flag_d[0-1],flag_d_min2[2]对应flag_d[2-3],因此flag_d_min4[0]是flag_d[0-3]这 4 个点的最小值。
硬件意义:通过 “复用前级结果” 减少计算量,13 个并行比较器 1 周期完成。
第三级:八元素极值运算
for(ap_uint<5> i=0;i<NUM-7;i++)
{
flag_d_min8[i] = __MIN(flag_d_min4[i],flag_d_min4[i+4]);
flag_d_max8[i] = __MAX(flag_d_max4[i],flag_d_max4[i+4]);
}作用:基于 4 元素极值,计算 8 个采样点的最小 / 最大灰度差(覆盖更广范围)
例:i=0时,flag_d_min8[0] = min(flag_d_min4[0], flag_d_min4[4]),flag_d_min4[0]对应flag_d[0-3],flag_d_min4[4]对应flag_d[4-7],因此flag_d_min8[0]是flag_d[0-7]这 8 个点的最小值。
硬件意义:进一步扩大极值覆盖范围,为后续局部极值提取做准备。
亮角点最大阈值a0计算
uchar_t a0= _threshold;
初始化阈值,a0用于衡量 “中心像素比周围亮” 时,角点仍能被检测到的 “最大阈值”(初始值确保分数不低于基础阈值)
for(ap_uint<5> i=0;i<PSize;i+=2)
{
short int a=255;
if(PSize == 16) {
a = flag_d_min8[i+1];
}
// else {
// for(ap_uint<5> j=1;j<PSize/2+1;j++)
// {
// a=__MIN(a,flag_d[i+j]);
// }
// }上面的遍历 16 个采样点(步长 2,每次处理 2 个对称点),提取局部区域的最小灰度差a,注释内容我略过了。
a0=__MAX(a0,__MIN(a,flag_d[i])); // a0 >= _threshold
a0=__MAX(a0,__MIN(a,flag_d[i+PSize/2+1]));
}
更新a0,使其成为 “亮角点能承受的最大阈值”。
__MIN(a, flag_d[i]):取局部 8 点最小值a与当前点flag_d[i]的更小值(即该区域内 “最显著的灰度差”)
__MAX(a0, ...):保留所有区域中 “最显著的灰度差”(最大值),即a0越大,亮角点在更高阈值下仍有效。
暗角点最大阈值b0计算
short int b0= -_threshold;
for(ap_uint<5> i=0;i<PSize;i+=2)
{
short int b=-255;
if(PSize == 16) {
b = flag_d_max8[i+1];
}
// } else {
// for(ap_uint<5> j=1;j<PSize/2+1;j++)
// {
// b=__MAX(b,flag_d[i+j]);
// }
// }
b0=__MIN(b0,__MAX(b,flag_d[i])); // b0 <= -_threshold
b0=__MIN(b0,__MAX(b,flag_d[i+PSize/2+1]));
}亮角点和暗角点同理!也是先遍历后更新b0。
参考亮角点的解释去理解就行。
输出分数
*core = __MAX(a0,-b0)-1;
计算最终角点分数,存储到core中,__MAX(a0, -b0):取亮角点最大阈值a0与暗角点最大阈值(绝对值-b0)中的较大值,代表该角点 “能承受的最大阈值”
减 1:确保分数对应的阈值下,角点仍能被正确检测(避免临界情况)
总结
角点分数的核心意义是描述角点能承受的最大阈值,角点分数越高,角点在噪声或光照变化下的稳定性越强。
这种设计既贴合 FAST 角点的灰度差特性,又通过多级极值金字塔实现了硬件高效计算,为后续筛选强角点提供了量化依据。
ORB-SLAM3硬件加速项目系列

点击文章下方标签获取整个系列更新文章!