
做视觉项目的人几乎都绕不开“角点”和“特征点”这两个词。我第一次做图像拼接时天真地以为“检测到角点”就等于“提取到了特征点”结果匹配出来的特征点对乱七八糟。后来才明白这背后其实是两套完全不同的东西检测子detector负责回答“特征在哪里”描述子descriptor负责回答“这个特征长什么样”。这篇文章就把角点和特征点、检测子和描述子的分工彻底讲清楚再配上一整套从检测、描述到匹配的实操流程和避坑经验。适合刚接触视觉特征提取的初学者也适合那些已经调过几个API、但没系统梳理过原理的同学。1. 角点和特征点先把这两个概念拆明白1.1 角点图像里“拐弯”的地方角点这个词学计算机视觉的人第一天就会遇到。你可以想象一张棋盘格黑白格子相交的那个顶点就是最典型的角点。再比如房间的墙角、窗户框的拐角、文字的笔画端点都是角点。用数学语言描述角点是图像局部区域内灰度在多个方向上都发生剧烈变化的位置。注意“多个方向”这四个字这是角点和边缘的本质区别。一条竖直边缘你沿水平方向跨过它时灰度变化剧烈但沿竖直方向移动时灰度基本不变而角点不一样你不管往哪个方向轻轻移动一个小窗口里面的灰度都会明显变。这种“四周都在变”的奇异位置就是角点。角点检测关心的不是这块区域具体是什么内容它不关心是墙脚还是纸箱角只关心“灰度变化是否足够奇异”。这也是为什么角点检测算法可以用在很多完全不相关的场景里。1.2 特征点一个更大的口袋特征点有的地方叫关键点keypoint 或 interest point是一个更宽泛的概念。它的定义也很直白在图像中位置明确、局部外观足够独特、并且在视角变化后还能被重复检测出来的点。注意关键词是“独特”和“可重复”。一个特征点不一定非得是角点。我给你举几个例子斑点blob一团亮斑的中心或者一团暗斑的中心。它周围没有明显“拐弯”但在尺度空间里却有稳定的极值响应。SIFT 检测出的很多特征点就是这种斑点不是角点。局部灰度极值点某个局部区域内最亮或最暗的那个像素也可以作为特征点。边缘上的特殊点某些边缘曲线上曲率特别大的位置虽然不是严格意义上的角点但足够独特也可以被当作特征点。所以你可以这么理解角点是一个“几何形态”层面的描述特征点是一个“应用层面”的通用概念。角点一定是特征点但特征点不一定是角点。1.3 一张表说清两者关系对比项角点特征点定义角度局部灰度在多个方向剧烈变化位置独特、外观可区分、可重复检测典型类型棋盘格顶点、墙角、文字端点角点、斑点、局部极值点、边缘高曲率点是不是一回事是特征点的一种特例更宽泛的类别常见算法Harris、FAST、Shi-TomasiSIFT、ORB、SURF、AKAZE搞清这个关系之后再看“检测子”和“描述子”思路就顺了。检测子对应的是“找特征点”而角点检测是其中一种找法描述子解决的是“找到之后怎么区分它们”。2. 检测子让算法知道“在哪里找”2.1 Harris 角点检测用数学严格定义“角”Harris 算法是我建议每个初学者第一个完整看懂的检测子因为它把一个很直观的想法变成了一套漂亮的数学表达。核心思想是这样的拿一个小窗口在图像上滑动。如果窗口内灰度变化很小说明处于平坦区域如果沿某个方向变化大、沿另一个方向变化小说明处于边缘如果沿任何方向移动灰度都变化剧烈这里就是角点。为了实现这个判断Harris 对窗口内的像素梯度做了统计构造了一个自相关矩阵 M。这个矩阵的特征值 λ1 和 λ2 起决定性作用λ1 和 λ2 都很大角点因为两个正交方向的梯度都强一个很大、一个很小边缘因为只有一个方向变化剧烈两个都很小平坦区域梯度整体都很弱。工程上不会直接算两个特征值而是用角点响应函数 R det(M) - k·trace(M)²k 一般取 0.04 到 0.06。R 大于某个阈值并且在局部区域取极大值的位置就是检测到的角点坐标。Harris 有一个我很欣赏的性质旋转不变性。因为它是基于梯度方向的统计图像转个角度自相关矩阵的特征值关系不会大变所以角点还能被找到。但它有个致命短板没有尺度不变性。图像放大或缩小之后同一个物理角点在原图中是角点缩小后可能变成一个平滑的过渡区域响应值就崩了。这也是后来 SIFT 引入尺度空间要解决的核心问题。2.2 FAST为速度而生的工程选择FASTFeatures from Accelerated Segment Test的思路比 Harris 简单粗暴得多。它取一个候选像素 P以 P 为圆心画一个半径为 3 的圆圆周上一共 16 个像素点。然后检查这 16 个点里是不是有连续 N 个点一般取 9 或 12都比 P 亮或都比 P 暗并且亮度差要超过阈值 t。如果满足就认为 P 是角点。这个检测过程没有复杂的矩阵运算只有灰度比较非常快。ORB 检测子选它当底座就是因为实时性要求高的场景比如视觉里程计、移动端 AR里速度优先级最高其他缺陷可以通过额外手段补。但 FAST 的缺点也必须清楚没有尺度不变性图像一缩放检测结果就乱没有方向信息后续描述子无法做旋转对齐对噪声敏感边缘附近容易出现响应检测出的点容易“扎堆”一个角点周围会冒出七八个候选点必须配合非极大值抑制。所以如果你的场景是“图像尺度基本固定、要求实时、计算资源紧张”FAST 系也就是 ORB很合适如果是离线处理、图像尺度变化大别硬上。2.3 SIFT 和 ORB 的检测尺度和方向怎么补回来SIFT 的检测部分解决了 Harris 和 FAST 都没解决的尺度问题。它的做法是构建一个高斯金字塔然后对相邻尺度做差分得到 DoGDifference of Gaussian空间。在这个三维空间里找局部极值点每个点不仅带坐标还带一个“尺度值”。同一物理点在图像放大缩小后会在不同尺度层上出现响应SIFT 通过尺度空间统一了它们所以具备尺度不变性。同时SIFT 会统计关键点邻域的梯度方向得到一个主方向这样在提取描述子之前先把图像块旋转到主轴方向旋转不变性也补上了。ORB 的思路是另一条路它用多分辨率金字塔给 FAST 补尺度信息用灰度质心法给 FAST 补方向信息。具体叫 intensity centroid就是在 FAST 检测出的局部区域里把像素灰度当作质量计算质心然后从中心指向质心的角度就是主方向。这个方法计算量很小但方向估计够用尤其适合实时系统。这里我能补充一个经验如果你用 ORB 做尺度变化很大的匹配要把金字塔层数调大一些但不能无脑调因为层数越多内存占用越高匹配速度也越慢。通常 4 到 8 层够用再大就得掂量掂量硬件了。2.4 检测子的输出不只是坐标很多人把检测子当成一个“返回点列表的函数”拿到的只有坐标。实际上完整的关键点信息应该包含四部分位置 (x, y)特征点在哪尺度scale用于确定后续描述子的采样窗口大小方向angle用于旋转对齐响应强度response这个点有多“像”特征点用于排序和筛选。我之前犯过一个错误把 SIFT 检测出的关键点坐标拿出来但丢弃了尺度和方向然后直接喂给另一个描述子算法。结果匹配效果极差。因为描述子需要知道“以多大范围取 patch”和“要不要旋转对齐”没有这些信息描述子提取就是盲人摸象。所以记住检测子推荐的输出格式是完整的关键点结构别只留坐标。这也是为什么检测子和描述子虽然概念上独立但工程上一般成对使用。3. 描述子让特征点“有身份”3.1 为什么找到位置还不够假设你从两幅图里各检测出了 300 个特征点坐标摆在你面前。你现在能回答“第一个关键点对应另一幅图里的哪个点”吗不能。因为坐标本身没有提供任何可用于匹配的信息。这时就需要描述子了。描述子的本质是以关键点为中心取一小块局部图像区域把它的外观编码成一个高维向量或者一段二进制串。要求是——同一个物理点在不同图像中的描述子尽量相似不同物理点的描述子尽量不同。这句话说起来容易做起来难。因为不同图像之间会有光照变化、旋转、尺度变化、视角变化、噪声描述子得在这些干扰下保持稳定。3.2 二进制描述子BRIEF 和 rBRIEFBRIEFBinary Robust Independent Elementary Features的思路很巧妙。它在关键点周围按一定规则通常是一个高斯分布选取 N 对像素位置对每一对像素比较亮度大小左边比右边亮记 1否则记 0。N 对位置比较完得到一个 N 位的二进制串。二进制描述子的优势很实在匹配的时候用汉明距离也就是比较两个二进制串有多少位不同这个操作在 CPU 上可以用一条位运算指令完成极快。但 BRIEF 有个致命伤没有方向。图像一旋转BRIEF 的采样位置还是按原来的坐标来取里面对应关系全乱匹配效果直接崩坏。ORB 给出的解决方案是 rBRIEF先利用关键点检测阶段算出的方向角把所有采样位置旋转后再进行亮度比较。这样描述子就有了旋转不变性。同时ORB 没有完全随机选点对而是通过统计学习选出一批判别性更强的 256 位降低了随机选点带来的方差。3.3 浮点描述子SIFT 的梯度直方图SIFT 描述子和 BRIEF 不是一套路数。它以关键点为中心取一个 16×16 的窗口旋转对齐后分成 4×4 共 16 个小格子。每个格子里统计 8 个方向的梯度直方图最后拼接成一个 128 维的浮点向量。这 128 维向量里每一维都代表“某个格子中某个梯度方向上的强度”信息量比 256 位的二进制串大得多所以 SIFT 描述子的区分度和鲁棒性在传统方法里是标杆级的。它还做了归一化能消除光照的线性变化影响。代价也很明显128 维浮点向量占内存大匹配时要算欧氏距离比汉明距离慢不少。所以工程选择很清晰实时场景、计算资源有限用 ORB 这类二进制描述子离线处理、精度优先、图像变化大用 SIFT 这类浮点描述子。如果是无人机航拍拼接这种对精度要求极高、又允许离线跑的任务我通常会选 SIFT。3.4 怎么判断两个描述子像不像匹配的核心就是算“距离”。二进制描述子常用汉明距离浮点描述子常用欧氏距离。距离越小说明两个特征越像。但有一个工程经验非常重要不要只看最近邻距离的绝对值。因为不同图像、不同区域的描述子距离分布差异很大设一个绝对阈值往往会误杀或漏放。更稳的方式是用比率测试对当前特征点在另一幅图中找距离最近的和距离次近的两个匹配点计算最近距离与次近距离的比值。比值越小说明最近邻明显优于次近邻匹配越可信。常用的经验阈值是 0.7 到 0.8低于这个值接受高于就丢掉。比率测试是我见过的最实用的匹配筛选手段之一强烈建议纳入标准流程。4. 从角点到特征匹配完整流程和实操笔记4.1 标准“检测-描述-匹配-筛选”流程无论是图像拼接、三维重建还是视觉定位局部特征匹配的流程都是同一套骨架图像预处理转灰度必要时做直方图均衡化或高斯模糊关键点检测选用合适的检测子得到关键点位置、尺度、方向描述子提取以关键点为中心提取局部特征向量或二进制串最近邻匹配为每个描述子在另一幅图中找到距离最近的候选点初步筛选用比率测试或距离阈值去掉模糊匹配几何校验用 RANSAC 估计两幅图之间的变换模型剔除不符合几何约束的误匹配。第 6 步很多人会偷懒跳过但我建议一定保留。纯描述子匹配一定存在误匹配只有通过几何校验才能得到真正可用于后续计算的高质量对应点。4.2 光照、旋转、尺度、视角变化分别会带来什么问题先看光照。灰度值的绝对大小很容易受光照影响。FAST 和 BRIEF 这类基于亮度比较的方法遇到较强光照变化时检测位置和描述子都会漂。SIFT 因为用了梯度方向直方图和归一化对光照变化稍好一些。工程上我一般会在预处理阶段做自适应直方图均衡化能在不引入过多计算量的前提下明显提高匹配稳定性。再看旋转。没有方向信息的 BRIEF 在旋转超过十几度后基本报废带方向的 ORB 和 SIFT 能抗更大旋转但也不是无限度的。实际上当两幅图像旋转超过 90 度时很多局部外观会遮挡或变化再好的描述子也难保证稳定。所以如果你的任务涉及大角度旋转最好在采集端就控制角度变化范围而不是完全指望算法。尺度方面Harris 和 FAST 没有尺度不变性尺度变化超过约两倍时继续硬匹配就是浪费算力。SIFT 天然支持大尺度变化ORB 靠金字塔也能覆盖一定范围但也要注意金字塔层数限制。视角变化是最难的。超过 45 度的大视角变化会让同一个局部区域的外观发生很大的非刚性变形传统描述子普遍吃力。这种场景下要么多视角采集要么考虑换用基于深度学习的特征比如某些学习型关键点和描述子但这属于进阶玩法了。4.3 参数怎么调我踩过的坑和总结参数调优没有万能配方但有一套通用的思考方式。先把几个常见的旋钮讲清楚。特征点数量上限这个直接影响速度和匹配质量。比如实时 SLAM 场景常见设定是每帧保留 1000 到 3000 个特征点太少容易跟踪丢失太多则会拖慢匹配和优化。检测阈值FAST 的阈值 t 一般取 10 到 30。阈值越大检测出的点越少但单个点的稳定性更高。Harris 的 k 值对角点响应结果影响不大真正影响大的是质量水平参数和最小距离参数。非极大值抑制半径用于避免特征点扎堆。半径太小点全堆在一起半径太大点过于稀疏匹配数不够。这个值跟图像分辨率关系很大建议按图像宽度的千分之几到百分之一去试。预处理图像偏模糊时可以先做轻度锐化后再检测图像对比度很弱时先做直方图均衡化。我见过很多匹配结果差的问题根源不是算法参数而是输入图像质量太差预处理比调参管用得多。调参的时候千万记住不要拿单张图反复试选 5 到 10 组有代表性的图像统计成功匹配的内点数用平均值和方差判断一组参数是否合适。不然很容易调出“在测试图上完美、换一组图就崩”的假象。4.4 一个实际项目的选择思路拿我做过的一个全景拼接项目举例。输入是无人机拍的十几张航拍图重叠率大概 30%图像分辨率很高但存在视角变化和曝光差异。我当时对比过两种方案ORB 全流程和 SIFT 全流程。ORB 在 1080p 图像上跑得飞快但曝光差异大的相邻图像之间匹配内点数明显下降SIFT 虽然慢一些但匹配质量和稳定性都高出一截。因为这个任务对时间是离线容忍的最终我选了 SIFT同时用 RANSAC 剔除误匹配效果很理想。反过来如果是一个运行在嵌入式设备上的视觉里程计系统我肯定会选 ORB。因为每帧只有几十毫秒的处理预算SIFT 的浮点描述子匹配开销在这里是不可接受的。检测子和描述子的选型本质上是精度、速度、鲁棒性三者的权衡没有绝对的好坏。5. 常见问题速查和避坑心得5.1 问题速查表现象可能原因处理方向特征点全部扎堆非极大值抑制半径太小或检测阈值太低增大抑制半径适当提高阈值匹配点数量太少检测阈值太高特征点数量上限太小图像对比度低降低阈值提高上限先做预处理误匹配特别多比率测试阈值太松或根本没有做几何校验收紧比率为 0.7 左右增加 RANSAC 校验图像旋转后匹配崩坏使用了无方向信息的描述子换 ORB 或 SIFT确认方向参与描述子计算尺度变化后匹配消失检测子无尺度不变性或金字塔层数不足换 SIFT或增加 ORB 金字塔层数光照变化导致匹配不稳定灰度比较类描述子对亮度敏感预处理做直方图均衡化或换梯度类描述子重复纹理区域匹配混乱局部外观区分度不够增大描述子采样区域必要时引入空间约束5.2 几个值得长期记住的经验第一检测和描述是两个环节但你在工程里不应该把它们割裂看。选检测子时要考虑它能不能给描述子提供方向和尺度信息选描述子时要考虑它跟检测子的组合是否匹配。比如你拿 FAST 检测出来的点硬套一个需要尺度信息的描述子结果一定糟糕。第二可视化调试比打印数据有用得多。我会把检测出的关键点和匹配结果直接画到图像上一眼就能看出问题是点的分布不均还是匹配连线交叉混乱。很多参数问题看可视化结果比看数值更容易定位。第三不要把匹配内点数当成唯一指标。有时候内点数很多但几何校验后的重投影误差很大这说明匹配精度不够。我曾经遇到拼接结果有重影排查后发现是很多匹配点误差在 2 个像素以上把重投影误差大于 1.5 像素的点丢干净之后重影立刻消失。最后再分享一个小技巧当你的任务图像之间存在一个大致已知的变换关系比如连续帧之间的近似平移量可以先用这个先验剔除明显不符合变换的匹配对再进 RANSAC。这样能大幅降低误匹配比例提高几何校验的成功率尤其适合视频序列特征跟踪的场景。特征点这块内容核心就是先理解“在哪里”和“长什么样”是两个环节再把自己场景里的检测子、描述子和后续筛选当成一条流水线来调。你看待它们的方式一旦转变很多问题自己就能定位到具体环节了。