FAST角点检测 HLS代码解析(ⅱ)

作者:阿白叔 发布时间: 2025-10-23 阅读量:26 评论数:0

FAST角点的本质

FAST (Features from Accelerated Segment Test) 算法的核心思想是:

 

判断某个像素点周围是否存在一段连续的亮或暗像素环(通常取 16 个像素组成的圆),如果有足够多连续的像素明显比中心点亮或暗,则这个点就是角点。

 

FAST 角点检测的本质是:检测亮度变化方向突变的点,也就是“局部区域亮度分布不连续”的位置。

换句话说:

 

如果像素处于平坦区域 → 周围像素亮度几乎相同 → 不是角点;

 

如果像素处于边缘上 → 一侧亮、一侧暗,但只有一边变化 → 不是角点;

 

如果像素处于角落 → 周围有两种以上方向的明显亮度变化 → 是角点。

 

从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_centerNUM通常为 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硬件加速项目系列

image-dtx3.png

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

文章doc版链接【金山文档 | WPS云文档】 FAST角点检测 HLS代码解析

评论