拓冰建站拓冰建站
首页 / 资讯中心 / 正文

OpenCV FAST 角点检测算法:原理、Python 实现与源码级深度解析

OpenCV FAST 角点检测算法原理、Python 实现与源码级深度解析【免费下载链接】opencvOpen Source Computer Vision Library项目地址: https://gitcode.com/GitHub_Trending/opencv31/opencvFASTFeatures from Accelerated Segment Test是实时视觉应用中最重要的角点检测器之一。本文基于 OpenCV 官方 Python 教程py_fast.markdown完整讲解 FAST 的圆环测试原理、高速预测试、机器学习优化与非极大值抑制给出可直接运行的cv.FastFeatureDetector_create()检测与绘图代码并结合当前仓库中 modules/features/src/fast.cpp 的实现细节查找表加速、SIMD 预测试、HAL 替换、OpenCL 路径、NMS 邻域比较与回归测试帮助你在掌握 API 用法的同时理解其底层性能来源。为什么需要 FAST实时场景的取舍传统的特征检测器如 Harris、Shi-Tomasi 等精度良好但从实时应用角度看速度不够快。官方教程给出的典型场景是 SLAMSimultaneous Localization and Mapping同步定位与建图移动机器人这类设备计算资源有限却要求每一帧都快速给出大量特征点。为此Edward Rosten 与 Tom Drummond 在 2006 年论文 Machine learning for high-speed corner detection2010 年修订中提出了 FAST 算法。它的核心思想是只用整数加减法和比较就能判断一个像素是不是角点不需要做图像导数、矩阵运算天然适合流水线化与 SIMD 加速。FAST 特征检测基本算法16 像素圆环测试算法按以下步骤对每个候选像素进行判断选出图像中待判断的像素 $p$其灰度值为 $I_p$。选出合适的阈值 $t$。考虑该像素周围的一个由 16 个像素组成的圆环下图中 1–16 编号的环形位置中心为 $p$如果在这 16 个像素中存在 $n$ 个连续的像素全部亮于 $I_p t$或全部暗于 $I_p - t$则 $p$ 是角点。论文中 $n$ 取 12。为进一步提速论文提出了高速测试high-speed test只检查环上的 4 个像素1、5、9、13 位置。若 $p$ 是角点则这 4 个像素中至少 3 个必须亮于 $I_p t$ 或暗于 $I_p - t$否则 $p$ 一定不是角点直接排除。只有通过了快速预测试的候选像素才会进入完整的 16 像素段测试。这个高速测试可以排除绝大多数非角点候选是 FAST 快于其他角点检测器的关键。但它也有几个弱点对 $n 12$ 时排除能力不足所选 4 个像素并非最优效率取决于提问顺序与角点分布高速测试的结果被丢弃相邻位置可能检测出多个重复特征点。前三点用机器学习方法解决第四点用非极大值抑制解决。用机器学习训练检测器2010 年的改进版 FAST 用决策树学习来组织判断顺序步骤如下选取一组训练图像最好来自目标应用域。对每张图像运行 FAST 算法找出特征点。对每个特征点把其周围 16 个像素存储为一个向量汇总所有图像得到特征向量集合 $P$。这 16 个像素中的任意像素记为 $x$只有三种状态依据这些状态把 $P$ 划分为 $P_d$、$P_s$、$P_b$ 三个子集。定义布尔变量 $K_p$$p$ 是角点为真否则为假。使用 ID3 算法决策树分类器以 $K_p$ 作为真实类别的知识对每个子集查询选择能使 $K_p$ 熵获得最多信息的 $x$ 作为下一次测试的像素。递归地对所有子集应用上述过程直到熵为零。这样构造出的决策树即可在其他图像中用于快速角点检测——像素检查顺序不再是写死的 1、5、9、13而是按信息增益最优动态排列。非极大值抑制NMS在相邻位置检测到多个兴趣点是另一个问题用非极大值抑制解决对所有检测到的特征点计算得分函数 $V$$V$ 是中心像素 $p$ 与周围 16 个像素灰度之差的绝对值之和。对两个相邻关键点比较各自的 $V$ 值。丢弃 $V$ 值较低的那个。小结FAST 比其他已有角点检测器快数倍但它对高噪声不鲁棒且结果依赖于阈值 $t$ 的选择。OpenCV 中的 FAST 检测器OpenCV 提供了两个入口自由函数cv::FAST()和特征检测器类FastFeatureDetector。在 modules/features/include/opencv2/features.hpp 中可以看到其定义class CV_EXPORTS_W FastFeatureDetector : public Feature2D { public: enum DetectorType { TYPE_5_8 0, TYPE_7_12 1, TYPE_9_16 2 }; CV_WRAP static PtrFastFeatureDetector create( int threshold10, bool nonmaxSuppressiontrue, FastFeatureDetector::DetectorType typeFastFeatureDetector::TYPE_9_16 ); CV_WRAP virtual void setThreshold(int threshold) 0; CV_WRAP virtual int getThreshold() const 0; CV_WRAP virtual void setNonmaxSuppression(bool f) 0; CV_WRAP virtual bool getNonmaxSuppression() const 0; CV_WRAP virtual void setType(FastFeatureDetector::DetectorType type_) 0; CV_WRAP virtual FastFeatureDetector::DetectorType getType() const CV 0; }; CV_EXPORTS void FAST( InputArray image, CV_OUT std::vectorKeyPoint keypoints, int threshold, bool nonmaxSuppressiontrue, FastFeatureDetector::DetectorType typeFastFeatureDetector::TYPE_9_16 );可调参数说明参数默认值含义threshold10中心像素与环形邻域像素灰度差的阈值 $t$有效范围 0–255源码中会做std::min(std::max(threshold, 0), 255)钳制见 fast.cpp。值越大越严格的角点才通过检测到的关键点越少nonmaxSuppressiontrue是否应用非极大值抑制抑制后会去掉同一角点附近的冗余点typeTYPE_9_16邻域类型对应三种圆环模式cv.FAST_FEATURE_DETECTOR_TYPE_5_8、cv.FAST_FEATURE_DETECTOR_TYPE_7_12、cv.FAST_FEATURE_DETECTOR_TYPE_9_16其中type的命名来自论文中TYPE_m_n的含义m表示连续像素长度角点判定需要连续超过 $m$ 个相同状态的环像素n表示实际检查的环像素数。TYPE_9_16即16 像素圆环中连续 9 个 8同侧像素是最常用也最严格的模式TYPE_5_8只检查 8 像素环速度最快但误报更多。三种类型在源码中分别映射到模板实例FAST_t8、FAST_t12、FAST_t16见 fast.cpp。完整 Python 示例下面的示例代码继承自官方教程使用仓库自带的数据图 samples/data/blox.jpg对比开启与关闭非极大值抑制两种模式下的检测效果import numpy as np import cv2 as cv from matplotlib import pyplot as plt # 读取灰度图blox.jpg 位于 opencv_root/samples/data/blox.jpg img cv.imread(blox.jpg, cv.IMREAD_GRAYSCALE) # 用默认参数创建 FAST 检测器 # 默认threshold10, nonmaxSuppressionTrue, typeTYPE_9_16 fast cv.FastFeatureDetector_create() # 检测并绘制关键点 kp fast.detect(img, None) img2 cv.drawKeypoints(img, kp, None, color(255, 0, 0)) # 打印当前全部默认参数 print(Threshold: {}.format(fast.getThreshold())) print(nonmaxSuppression:{}.format(fast.getNonmaxSuppression())) print(neighborhood: {}.format(fast.getType())) print(Total Keypoints with nonmaxSuppression: {}.format(len(kp))) cv.imwrite(fast_true.png, img2) # 关闭非极大值抑制 fast.setNonmaxSuppression(0) kp fast.detect(img, None) print(Total Keypoints without nonmaxSuppression: {}.format(len(kp))) img3 cv.drawKeypoints(img, kp, None, color(255, 0, 0)) cv.imwrite(fast_false.png, img3)几点使用细节detect(img, None)的第二个参数是掩膜None表示全图检测。若传入掩膜实现中会调用KeyPointsFilter::runByPixelsMask()过滤掩膜外的点见 fast.cpp。输入若不是 8 位灰度图实现内部会自动cvtColor转灰度因此直接传彩色图也能工作但显式IMREAD_GRAYSCALE更省一次转换。关闭 NMS 后检测到的点数通常明显多于开启时且同一角点周围会出现一簇重叠的圆——这正是相邻位置检测出多个特征问题的直观体现。左图非极大值抑制开启每个角点只保留一个代表点右图关闭抑制则能看到大量相邻重复的关键点簇直观验证了 NMS 的作用。源码级实现剖析主流程预测试 完整段测试核心检测函数是模板函数FAST_tpatternSizefast.cpp模板参数patternSize取 8、12 或 16对应三种DetectorType。其 CPU 标量路径fast.cpp完整体现了论文的两级测试int v ptr[0]; const uchar* tab threshold_tab[0] - v 255; int d tab[ptr[pixel[0]]] | tab[ptr[pixel[8]]]; // 高速测试像素 1 和 9 if( d 0 ) continue; d tab[ptr[pixel[2]]] | tab[ptr[pixel[10]]]; // 像素 5 和 13 d tab[ptr[pixel[4]]] | tab[ptr[pixel[12]]]; d tab[ptr[pixel[6]]] | tab[ptr[pixel[14]]]; if( d 0 ) continue; d tab[ptr[pixel[1]]] | tab[ptr[pixel[9]]]; // ... 其余环像素threshold_tab是一张 512 项的查找表tab[i v]直接给出邻域像素相对中心像素是更暗1/ 更亮2/ 相近0把比较运算压缩成一次内存读取。d的位 1 表示存在足够多的更暗像素位 2 表示存在足够多的更亮像素两者都不满足d 0就跳过这正是高速测试的实现。通过预测试后代码按d 1/d 2分别做完整段测试沿环形偏移数组pixel[0..15]顺序扫描统计连续满足x v - t或x v t的计数count KK patternSize/2才判定为角点并立即break——连续段测试与超过一半即判定的策略让最坏情况也被提前截断。SIMD 向量化路径当patternSize 16且编译启用了 128 位 SIMDCV_SIMD128时实现会以 16 像素为一组并行执行高速预测试fast.cpp一次性加载 16 个中心像素和 4 个关键环像素用v_lt/v_and/v_or组合计算 4 选 3 的组合条件再用v_check_any快速跳过整组全非角点的行段。若检测到 AVX2 支持还会调用opt_AVX2::FAST_t_patternSize16_AVX2专用实例进一步加速。这就是FAST 比其他角点检测器快数倍的底层来源预测试本身被完全向量化且绝大多数像素在预测试阶段就被丢弃。非极大值抑制的邻域比较论文中比较相邻关键点、丢弃 V 小的那个在实现中具体化为 3×3 邻域内的最大值判定。检测到角点后用cornerScorepatternSize()定义在 fast_score.hpp计算得分 $V$ 存入行缓冲随后fast.cppif( !nonmax_suppression || (score prev[j1] score prev[j-1] score pprev[j-1] score pprev[j] score pprev[j1] score curr[j-1] score curr[j] score curr[j1]) ) { keypoints.push_back(KeyPoint((float)j, (float)(i-1), 7.f, -1, (float)score)); }即只有当该点得分严格大于上、下两行及其左右邻点共 8 个候选的得分时才保留最终关键点size固定为 7、response存得分 $V$可供后续KeyPointsFilter::runByScore之类的二次筛选使用。HAL 替换与 OpenCL 路径FAST()入口fast.cpp还体现了 OpenCV 的分层加速架构参数校验type不合法时直接抛出StsBadArg异常测试 test_fast.cpp 的invalidDetectorType用例即验证此行为。OpenCL当输入是UMat且类型为TYPE_9_16时走ocl_FAST()由FAST_findKeypoints与FAST_nonmaxSupression两个 OpenCL 核完成且关键点数量上限取max(图像总像素数/100, 1000)这一简单启发式fast.cpp。HAL优先尝试cv_hal_FASTv2/cv_hal_FAST硬件抽象层钩子供 ARM 等平台的优化库替换。注意 HAL 密集接口hal_FASTfast.cpp在threshold 20时主动返回未实现并回退到通用 CPU 路径——阈值过大时密集打分收益有限。通用 CPU最后回退到FAST_t8/12/16模板实现。测试与回归验证仓库为 FAST 提供了三类测试可作为行为依据modules/features/test/test_fast.cpp 中的Features2d_FAST.regression对 3 种DetectorType分别在两张标定图上以固定阈值调用FAST()并将关键点序列与 XML 基线做 L2 零差比较保证结果跨平台可复现Features2d_FAST.noNMS验证nonmaxSuppressionfalse时的独立回归结果Features2d_FAST.invalidDetectorType验证非法type抛出异常。此外 modules/features/perf/perf_fast.cpp 提供性能基准测试可量化TYPE_5_8 / 7_12 / 9_16与 NMS 开关的耗时差异供调参参考。调参实践建议阈值threshold默认 10。噪声大的图像可以适当调高如 20–40减少误检但会丢失弱角点图像对比度高、角点密集时可适当调低。由于 FAST对高噪声不鲁棒、结果依赖阈值建议对同一图像组扫一遍阈值观察关键点数稳定性。type的选择TYPE_9_16默认最严格、最稳定且是唯一走 OpenCL 加速的类型TYPE_5_8检测最快、点数最多适合需要稠密点且算力极受限的场景。NMS 开关交互式调参与可视化时建议保持默认开启做匹配、跟踪等需要稳定点集的场景务必开启否则相邻冗余点会干扰描述子计算。参考资料Edward Rosten 和 Tom DrummondMachine learning for high speed corner detection第 9 届欧洲计算机视觉大会ECCVvol. 12006pp. 430–443。Edward Rosten、Reid Porter 和 Tom DrummondFaster and better: a machine learning approach to corner detectionIEEE Transactions on Pattern Analysis and Machine Intelligence2010vol. 32pp. 105-119。【免费下载链接】opencvOpen Source Computer Vision Library项目地址: https://gitcode.com/GitHub_Trending/opencv31/opencv创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门