特征提取与描述:SIFT、SURF、ORB、HOG、LBP等经典特征

聊到特征提取,这几乎是每个做视觉的工程师都绕不开的坎。我记得刚入行那会儿,面试官问我“你用过哪些特征?”我张口就是SIFT、SURF,结果被追问了一句“那你说说它们本质区别是什么?”——嗯,当时确实有点懵。今天咱们就把这几个经典特征掰开揉碎了讲清楚。

一、SIFT:尺度不变特征变换

SIFT可以说是特征提取界的“老大哥”了。它最牛的地方在于,不管你把图片放大缩小、旋转、还是改变光照,它都能找到对应的特征点。说白了,就是鲁棒性极强。

核心思想:在尺度空间中寻找极值点,然后给每个点分配一个128维的描述子。

关键步骤:

  1. 构建高斯差分金字塔(DoG)
  2. 在DoG空间检测局部极值点
  3. 精确定位关键点(去除低对比度和边缘响应点)
  4. 为关键点分配主方向
  5. 生成128维描述子

我在项目中遇到过一个问题:用SIFT做图像拼接,结果两张图明明有重叠区域,但特征点匹配数量就是不够。后来发现是图像分辨率太大,默认的尺度参数不够细。我建议你实际用的时候,把nOctaveLayers调大一点,效果会好很多。

避坑指南:我曾经在嵌入式设备上跑SIFT,结果帧率只有0.5fps。SIFT的计算量确实大,不适合实时场景。如果你追求速度,建议往下看ORB。

二、SURF:加速版SIFT

SURF全称是Speeded-Up Robust Features,说白了就是SIFT的“加速版”。它用Hessian矩阵代替了DoG,用积分图加速了计算过程。

对比项 SIFT SURF
尺度空间构建 高斯金字塔 Hessian矩阵+积分图
特征点检测 DoG极值 Hessian行列式极值
描述子维度 128维 64维(默认)
速度 快3-5倍

我个人习惯在需要实时性但又不想牺牲太多精度时,优先考虑SURF。比如做AR场景的标记物识别,SURF就挺合适。不过要注意,SURF是有专利的,商用的话得小心。

三、ORB:又快又免费

ORB是OpenCV Labs推出的,结合了FAST角点检测和BRIEF描述子。它最大的优势就是——快,而且没有专利限制。

为什么快?因为FAST检测只需要比较像素亮度,BRIEF描述子用的是二进制字符串,匹配时用汉明距离,位运算一下就搞定了。

// OpenCV中ORB的使用示例
cv::Ptr<cv::ORB> orb = cv::ORB::create(500); // 500个特征点
std::vector<cv::KeyPoint> keypoints;
cv::Mat descriptors;
orb->detectAndCompute(image, cv::Mat(), keypoints, descriptors);

// 匹配时用汉明距离
cv::BFMatcher matcher(cv::NORM_HAMMING);
std::vector<cv::DMatch> matches;
matcher.match(descriptors1, descriptors2, matches);

你想想看,SIFT匹配一次可能要几十毫秒,ORB可能1毫秒就搞定了。我在做手机端的实时SLAM时,用的就是ORB。不过它也有缺点——对旋转和尺度变化比较敏感,尤其是大角度旋转时,匹配质量会下降。

小技巧:如果你用ORB做特征匹配,建议先做一下图像金字塔,或者用cv::ORB::create()时设置nlevels参数,这样能稍微缓解尺度问题。

四、HOG:行人检测的利器

HOG(方向梯度直方图)跟前面几个不太一样。它不是找特征点,而是提取整个图像块的特征。说白了,就是统计图像局部区域的梯度方向分布。

核心思路:

  • 将图像分成小的cell(比如8x8像素)
  • 计算每个cell的梯度方向和幅值
  • 统计梯度方向直方图
  • 将多个cell组成block,做归一化
  • 串联所有block的特征,得到最终描述子

我记得当年做行人检测,HOG+SVM是标配。OpenCV里有个cv::HOGDescriptor,直接就能用。不过要注意,HOG对光照变化比较敏感,我建议你在预处理时做一下直方图均衡化。

实际经验:HOG的cell大小和block大小对效果影响很大。我一般用8x8的cell,2x2的block,步长8像素。如果你检测的目标比较小,可以试试4x4的cell。

五、LBP:纹理特征的经典

LBP(局部二值模式)是纹理分析的好手。它的思想很简单:比较中心像素和周围像素的大小关系,生成一个二进制编码。

基本LBP计算:

// 假设3x3邻域
// 中心像素值为c,周围8个像素值为p0-p7
// 如果pi >= c,则对应位为1,否则为0
// 最终得到一个8位二进制数

// 例如:
// 中心值: 85
// 周围: [90, 80, 70, 95, 100, 75, 65, 88]
// 比较后: [1, 0, 0, 1, 1, 0, 0, 1]
// 二进制: 10011001 = 153

LBP的优点是计算极快,而且对单调灰度变化不敏感。我在做人脸识别时,经常用LBP提取纹理特征,配合直方图做分类。不过它也有局限——对噪声比较敏感,而且旋转不变性不好。

避坑指南:我曾经直接用原始LBP做纹理分类,结果准确率只有60%多。后来换成圆形邻域和旋转不变模式(LBPROT),准确率提到了85%。所以,别偷懒,该升级的版本还是要升级。

六、如何选择?

说了这么多,到底该用哪个?我个人的经验是这样的:

  • 追求精度、不差算力:选SIFT,尤其是做三维重建、图像拼接
  • 需要实时、精度尚可:选SURF,适合AR、视觉里程计
  • 极致速度、移动端:选ORB,SLAM、特征匹配首选
  • 目标检测、行人识别:选HOG,配合SVM效果稳定
  • 纹理分析、人脸识别:选LBP,简单高效

当然,现在深度学习火了之后,很多场景直接用CNN提取特征了。但经典方法的价值在于——它们让你理解“特征”到底是什么。你想想看,如果连SIFT的尺度空间都不懂,你怎么理解CNN里的感受野和池化?

嗯,今天就聊到这儿。下一章咱们会讲特征匹配和几何验证,到时候再细聊。