4、目标检测基础(上):滑动窗口与图像金字塔、Haar特征与Adaboost分类器(人脸检测)、HOG特征与SVM(行人检测)

各位同学,今天我们来聊聊目标检测的“老底子”。

说实话,现在大家一提到目标检测,脑子里蹦出来的都是YOLO、Faster R-CNN这些深度学习模型。但我想说,如果你没搞懂滑动窗口、图像金字塔、Haar特征和HOG特征这些经典方法,你很难真正理解现代检测器为什么那么设计。

我当年刚入行时,第一个项目就是做人脸检测。那时候哪有什么GPU,全靠CPU硬扛。嗯,今天我就把当年踩过的坑和积累的经验,一次性讲清楚。

核心观点:传统目标检测 = 特征工程 + 分类器。特征决定了你能检测什么,分类器决定了你检测得准不准。

4.1 滑动窗口与图像金字塔:暴力但有效的搜索策略

先问大家一个问题:一张图片里,目标可能出现在任何位置,也可能有大有小。你怎么找到它?

最简单的思路就是——穷举。这就是滑动窗口的核心思想。

4.1.1 滑动窗口是什么?

说白了,就是一个固定大小的矩形框,在图像上从左到右、从上到下地滑动。每滑动一步,就把框内的图像区域提取出来,交给分类器判断:这是目标还是背景?

  • 窗口大小:通常固定,比如64×128(行人检测常用)或24×24(人脸检测常用)
  • 步长:每次移动的像素数。步长越小,检测越精细,但计算量越大
  • 缩放比例:为了检测不同大小的目标,需要缩放图像本身——这就是图像金字塔

我的经验:步长一般设为窗口宽高的10%~20%。比如64宽的窗口,步长8~12像素比较合理。步长太小,你会等到天荒地老;步长太大,目标容易漏检。

4.1.2 图像金字塔:解决尺度问题

目标有大有小,怎么办?

图像金字塔就是答案。你把原图不断缩小(通常每次缩小1.1~1.5倍),形成一系列不同尺度的图像。然后在每一层上跑滑动窗口。

举个例子:

  • 原图1000×800,窗口64×128
  • 缩小到800×640,窗口还是64×128——相当于检测了更大的目标
  • 再缩小到640×512——检测的目标更大
  • 以此类推,直到图像比窗口还小

注意:金字塔层数越多,检测越全面,但计算量呈指数增长。我建议一般建3~5层就够了。曾经有个项目,我建了10层金字塔,结果一帧图像处理了3秒……直接被客户骂惨了。

4.1.3 滑动窗口的致命缺陷

你想想看,一张1000×800的图像,步长8像素,金字塔5层,总共要检测多少个窗口?

答案是:几十万甚至上百万个。每个窗口都要提取特征、跑分类器——这速度,你能忍?

所以,滑动窗口虽然思路简单,但实际应用中必须配合高效的特征和分类器。这就是接下来要讲的Haar和HOG的用武之地。

滑动窗口 + 图像金字塔 检测流程 输入图像 图像金字塔(缩放1.1~1.5倍,共N层) 滑动窗口(固定大小,步长8~12像素) 特征提取(Haar/HOG) + 分类器(Adaboost/SVM)

4.2 Haar特征与Adaboost分类器:人脸检测的经典组合

2001年,Viola和Jones提出了一个里程碑式的工作——实时人脸检测。核心就是Haar特征 + Adaboost + 级联结构。

我至今记得第一次在笔记本上跑通这个算法时,那种“哇,真的能实时检测人脸”的兴奋感。虽然现在看它已经过时了,但它的设计思想至今影响着很多现代算法。

4.2.1 Haar特征:像积木一样的矩形特征

Haar特征其实就是一些黑白相间的矩形模板。计算时,用白色区域像素和减去黑色区域像素和,得到一个数值。

常见的Haar特征有:

  • 边缘特征:2个矩形,检测明暗变化(比如眼睛比脸颊暗)
  • 线特征:3个矩形,检测线条(比如鼻梁)
  • 中心特征:4个矩形,检测斑点(比如眼睛区域)

关键点:Haar特征为什么快?因为它用了积分图(Integral Image)。积分图可以在常数时间内计算出任意矩形区域的像素和。没有积分图,Haar特征根本跑不起来。

4.2.2 Adaboost:从弱分类器到强分类器

单个Haar特征分类能力很弱,可能只有51%的准确率——比瞎猜好一点点。

Adaboost的思路是:把很多个这样的弱分类器组合起来,形成一个强分类器。怎么组合?

  1. 先训练一个弱分类器,找出它分错的样本
  2. 加大这些错分样本的权重
  3. 再训练下一个弱分类器,让它更关注之前分错的样本
  4. 重复,直到达到目标精度

最终,每个弱分类器有一个权重,投票决定结果。

我的经验:Adaboost训练时,弱分类器的数量不是越多越好。我曾经试过用2000个弱分类器,结果过拟合严重,检测率反而下降了。一般100~200个就够用了。

4.2.3 级联结构:让检测飞起来

Viola-Jones最巧妙的设计是级联(Cascade)。

你想想看,一张图像中,99%的区域都是背景。如果每个窗口都跑200个弱分类器,那太浪费了。

级联的思路是:

  • 前几层用少量、简单的Haar特征,快速排除明显不是人脸的区域
  • 只有通过前几层的候选区域,才进入更复杂的后续层
  • 最终只有极少数区域能通过所有层,被判定为人脸

这样,大部分窗口在前几层就被淘汰了,计算量大幅下降。

注意:级联的每一层都要设置一个“通过率”。如果通过率太高,很多非人脸会进入下一层,增加计算量;如果通过率太低,真正的人脸可能被误杀。我一般设置每层通过率99.5%以上,保证不漏检。

4.3 HOG特征与SVM:行人检测的黄金搭档

2005年,Dalal和Triggs提出了HOG(方向梯度直方图)特征,专门用于行人检测。这个算法在深度学习兴起之前,一直是行人检测的标杆。

我记得2012年做安防项目时,用的就是HOG+SVM。虽然现在有更好的方法,但HOG的思想——用梯度方向描述局部形状——至今仍是很多特征提取方法的基础。

4.3.1 HOG特征:用梯度说话

HOG的核心思想是:物体的局部外观和形状,可以通过局部梯度方向的分布来描述。

具体步骤:

  1. 计算梯度:对每个像素,计算水平方向和垂直方向的梯度
  2. 划分细胞单元:将图像分成8×8的小块(cell)
  3. 统计梯度方向直方图:每个cell内,统计9个方向的梯度幅值
  4. 块归一化:将2×2个cell组成一个block,进行对比度归一化
  5. 串联特征:所有block的特征串联起来,形成最终的HOG特征向量

举个例子,一个64×128的行人图像:

  • cell大小:8×8,所以有8×16=128个cell
  • block大小:2×2 cell,步长8像素,所以有7×15=105个block
  • 每个block有4个cell × 9个方向 = 36维特征
  • 最终特征维度:105 × 36 = 3780维

为什么HOG适合行人?行人的轮廓(头、肩膀、腿)有明显的边缘和梯度变化。HOG正好能捕捉这些信息。相比之下,Haar特征更适合人脸这种有固定纹理模式的物体。

4.3.2 SVM:找到最佳分界线

特征提取完了,接下来就是分类。HOG的搭档是SVM(支持向量机)。

SVM的目标是找到一个超平面,把正样本(行人)和负样本(背景)分开,并且让两类样本到超平面的距离(间隔)最大化。

为什么用SVM?

  • HOG特征维度高(3780维),SVM在高维空间表现好
  • SVM的泛化能力强,不容易过拟合
  • SVM有成熟的实现(比如OpenCV的cv2.HOGDescriptor)

我的经验:训练SVM时,负样本的选择非常关键。我曾经只用了一些简单的背景图片做负样本,结果模型把树影、路灯都检测成了行人。后来我用了“难例挖掘”——把误检的样本加入训练集重新训练,效果好了很多。

4.3.3 HOG vs Haar:怎么选?

对比项 Haar特征 HOG特征
适用场景 人脸检测(纹理固定) 行人检测(轮廓明显)
特征维度 低(几百维) 高(几千维)
计算速度 快(积分图加速) 较慢(梯度计算耗时)
分类器 Adaboost + 级联 SVM
光照鲁棒性 一般 较好(归一化后)

4.4 实战经验总结

说了这么多,最后给大家几个实用建议:

  1. 滑动窗口的步长和金字塔层数要权衡。我一般先设大步长(比如16像素)快速测试,再根据结果调小步长
  2. Haar特征适合人脸,HOG适合行人。不要混用。我曾经试过用HOG检测人脸,效果很差——人脸太光滑,梯度信息不够丰富
  3. 训练数据要多样化。正样本要包含不同角度、光照、遮挡的情况。负样本要覆盖各种背景
  4. 难例挖掘是提升精度的关键。先训练一个初版模型,在验证集上跑,把误检的样本加入训练集,再训练一次

避坑指南:我曾经在一个项目中,直接用OpenCV自带的HOG行人检测器,结果在雨天场景下漏检率高达40%。后来发现,默认的检测器是在晴天数据集上训练的。解决办法是:收集雨天数据,重新训练SVM。所以,别迷信预训练模型,数据才是王道。

好了,今天的内容就到这里。滑动窗口、图像金字塔、Haar特征、HOG特征——这些传统方法虽然老了,但它们是理解现代目标检测的基石。下一节我们会讲更深入的内容,到时候你会发现,很多现代方法都是在这些老方法的基础上改进的。

可可精品资料库