识别
前面的章节一步步建立了视觉处理的工具链:从像素级的滤波(Ch3-4),到边缘和区域(Ch6-7),再到关键点的检测、描述和匹配(Ch8-9),最后到几何对齐(Ch10)。这些都是在回答「图像里面有什么结构」。本章进入计算机视觉的核心问题——识别(Recognition):这张图里有一只猫还是一条狗?这个场景是厨房还是海滩?那个物体在哪里?
识别是「高层视觉」的起点。它不再关注像素和梯度,而是跨越从像素到语义的鸿沟——这正是第一章中提到的「语义鸿沟」。
为什么需要类别
人类看到一只兔子,会立刻知道它是活的、毛茸茸的、可以触摸的、跑得很快的——尽管这些信息没有一个能从当前的视觉输入中直接获得。这就是类别(Category)的力量:
- 预测行为:识别出「熊」就知道要远离,不需要亲身验证
- 知识索引:类别是通向大量先验知识的入口,帮助理解从未见过的个体
- 沟通交流:「那边有只猫」比描述像素值高效得多
分类的层次
认知心理学家 Rosch 在 1970 年代提出了分类的层次结构:
flowchart TD
A[上位类<br/>animal] --> B[基本类<br/>dog / cat / cow]
B --> C[下位类<br/>German shepherd / Doberman]
C --> D[个体<br/>"Fido"]
classDef super fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
classDef basic fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
classDef sub fill:#e8f5e8,stroke:#2e7d32,stroke-width:2px
classDef inst fill:#fff3e0,stroke:#ef6c00,stroke-width:2px
class A super
class B basic
class C sub
class D inst
基本层(Basic Level)是人类最自然使用的分类粒度——它是满足以下条件的最高层级:成员具有相似的形状、相似的交互方式、大量的共享属性。人们说「那是一只狗」而不是「那是一只动物」或「那是一只德国牧羊犬」——除非有特殊需要。
分类的理论
如何判断一个东西属于哪个类别?认知科学提出了三种模型:
| 模型 | 核心思想 | 对应的 CV 方法 |
|---|---|---|
| 定义式 | 类别由一组充要属性定义,满足即属于 | 规则系统、决策树 |
| 原型式 | 与类别的「典型代表」比较相似度 | 最近均值分类器 |
| 样例式 | 与所有已知成员逐一比较 | K 近邻、SVM |
定义式方法(Plato/Aristotle 的经典观点)假设类别有清晰的边界和必要充分条件,但现实中很难为「椅子」或「游戏」给出完美定义。原型模型只存储一个「平均代表」,简洁但丢失了类内变化信息。样例模型存储所有见过的实例,灵活但计算代价高。
现代计算机视觉中的深度学习方法可以看作是这些理论的混合——网络在隐含层中既学到了类似原型的「中心表示」,又通过大量训练样例保留了类内变化的信息。
图像分类的任务谱系
「识别」不是一个单一任务,而是一个从粗到细的谱系:
| 任务 | 输入 | 输出 | 示例 |
|---|---|---|---|
| 图像分类 | 整张图 | 类别标签 | 「这是厨房」 |
| 目标检测 | 整张图 | 类别 + 边界框 | 「位置 (x,y,w,h) 有一只狗」 |
| 语义分割 | 整张图 | 逐像素类别 | 每个像素标记为「人/羊/狗/背景」 |
| 实例分割 | 整张图 | 逐像素类别 + 实例 ID | 区分「第 1 只羊」和「第 2 只羊」 |
分类的对象也远不止常见物体——包括细粒度识别(区分不同鸟类品种)、场景识别(卧室 vs 厨房 vs 海滩)、材质识别(木材 vs 金属 vs 玻璃)、风格识别(巴洛克 vs 印象派)甚至字体识别。每种任务需要的特征可能截然不同:物体识别依赖形状,场景识别依赖空间布局,材质识别依赖颜色和纹理,动作识别依赖运动。
监督学习框架
不管具体任务如何,基于监督学习的图像分类都遵循同一个框架:
flowchart LR
subgraph 训练
A[训练图像] --> B[特征提取]
B --> C[分类器训练]
L[训练标签] --> C
C --> D[训练好的分类器]
end
subgraph 测试
E[测试图像] --> F[特征提取]
F --> D
D --> G[预测标签]
end
classDef data fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
classDef process fill:#e8f5e8,stroke:#2e7d32,stroke-width:2px
classDef result fill:#fff3e0,stroke:#ef6c00,stroke-width:2px
class A,E,L data
class B,C,F process
class D,G result
核心由两部分组成:特征提取(将图像转换为固定维度的向量)和分类器(从向量到类别的映射)。传统方法中这两部分是分开设计的——先手工设计特征(颜色直方图、HOG、SIFT 等),再训练 SVM 等分类器。深度学习的核心变革是将两者合并为一个端到端训练的系统。
视觉词袋与空间金字塔
在深度学习之前,最成功的图像分类方法是空间金字塔词袋(Spatial Pyramid Bag-of-Words)模型。理解它不仅有历史价值——它的核心思想(直方图表示、聚类量化、空间金字塔)至今仍在各种方法中被使用。
用什么特征来描述图像
特征的选择取决于要识别什么。不同的任务需要不同类型的信息:
| 任务 | 关键信息 | 适用特征 |
|---|---|---|
| 物体识别 | 形状 | 局部形状、阴影、纹理 |
| 场景识别 | 空间布局 | 透视线、梯度、线段 |
| 材质识别 | 反照率、触感 | 颜色、纹理 |
| 动作识别 | 运动 | 光流、轨迹点 |
好的特征应遵循三个原则:覆盖性(Coverage,捕获所有相关信息)、简洁性(Concision,在不损失覆盖的前提下最小化特征数量)、直接性(Directness,理想的特征应当独立地对预测有用)。
常用的直方图特征包括:颜色直方图(在 L*a*b* 或 HSV 空间中统计)、纹理直方图(滤波器组响应或 HOG 区域统计)和描述子直方图(SIFT 等局部描述子的聚类统计,即视觉词袋)。
直方图的构建
将高维特征编码为直方图时,面临联合直方图(Joint Histogram)和边际直方图(Marginal Histogram)的选择。联合直方图在多个特征维度上同时分 bin,精确但 bin 数量随维度指数增长——高维时大量 bin 是空的,需要海量数据。边际直方图对每个维度单独统计,bin 数量线性增长,每个 bin 有更多数据——但假设了特征维度之间相互独立。
一个折中方案是基于聚类的直方图:用 K-means 将数据在高维空间中聚成 个簇,然后统计落入每个簇的样本数量。所有图像共用同一组聚类中心。这既避免了联合直方图的维度灾难,又不要求特征独立——正是视觉词袋的核心思路。
bin 的数量有一个权衡:少 bin 需要更少的数据但表示粗糙,多 bin 表示精细但需要更多数据。
从描述子到视觉词汇
第 9 章介绍了 SIFT 等局部描述子。一张图像中可以提取成百上千个 128 维的 SIFT 描述子——但分类器需要一个固定长度的表示。怎么办?
借鉴自然语言处理中的词袋模型(Bag of Words):一篇文章可以用各个词出现的频率来表示,不管词的顺序。类似地,一张图像可以用各个「视觉词汇」出现的频率来表示。
视觉词汇(Visual Word)是通过聚类获得的描述子原型。完整的 BoW 流程如下:
训练:
- 从所有训练图像中提取关键点和描述子
- 用 K-means 聚类所有描述子,得到 个视觉词汇(簇中心)
- 将每个描述子量化到最近的视觉词汇
- 用归一化的视觉词汇计数表示每张图像( 维直方图)
- 用直方图作为特征训练分类器
测试:
- 提取描述子并量化到视觉词汇
- 计算视觉词汇直方图
- 用训练好的分类器预测类别
直方图距离
有了直方图表示,就需要衡量两个直方图之间的相似度。常用的距离度量包括:
- 余弦相似度:归一化后的内积,计算快
- 直方图交叉:
- 距离:对每个 bin 的差异按该 bin 的大小归一化,通常效果最好
- 推土机距离(Earth Mover's Distance, EMD):将一个分布「搬运」成另一个分布的最小代价,能考虑相邻 bin 之间的语义相似性,适合 bin 之间有自然顺序的场景(如颜色)
空间金字塔
普通 BoW 有一个致命缺陷:完全丢弃了空间信息。一张在草地上的女孩照片、一块纯绿色噪声图和一个绿色渐变图可能有相同的颜色直方图——但它们显然是完全不同的图像。
空间金字塔(Spatial Pyramid)的解决方案是在多个空间分辨率上计算直方图:
- Level 0:整张图计算一个直方图( 个 bin)
- Level 1:将图像分成 个区域,每个区域各计算一个直方图
- Level 2:分成 个区域
- …以此类推
将所有层级的直方图拼接起来,就得到了既包含全局统计又保留了粗略空间布局的表示。Level 0 告诉你「图中有什么」,Level 2 告诉你「什么在哪里」。
线性 SVM 分类器
有了空间金字塔特征,下一步是训练分类器。支持向量机(SVM)在深度学习之前是最常用的选择。
线性 SVM 的目标是找到一个超平面 将不同类别的样本分开。在所有能正确分类的超平面中,SVM 选择间隔最大(Maximum Margin)的那个——离超平面最近的样本叫做支持向量(Support Vector),间隔 就是两类支持向量之间的距离。
是正则化项(控制间隔大小), 是松弛变量之和(允许部分样本违反间隔), 控制两者的权衡—— 越大越不容忍错误分类, 越小越倾向大间隔。
空间金字塔 BoW 的效果
在 Caltech-101 数据集上,使用 200 个强特征(SIFT)、3 层空间金字塔加 SVM,分类准确率达到 。相比不使用金字塔的单层直方图(),空间信息带来了超过 23 个百分点的提升。这一结果在 2006 年是最先进的。
深度卷积神经网络
范式转变
空间金字塔 BoW 的流程是:手工设计特征(SIFT)→ 手工设计编码(BoW + 空间金字塔)→ 训练分类器(SVM)。每一步都需要领域专家精心设计,而且各步骤之间不能联合优化——SIFT 不知道什么样的特征对 SVM 更好,SVM 也无法改进 SIFT。
深度学习的革命性在于端到端训练(End-to-End Training):将特征提取和分类合并为一个可微分的网络,从原始像素直接学到类别标签,所有参数联合优化。
对比 SIFT+BoW 管线和 CNN,两者结构其实是对应的:
| SIFT + 空间金字塔 | CNN |
|---|---|
| 手工设计的方向滤波器 | 可学习的卷积核 |
| 空间池化(求和) | 空间池化(最大值) |
| 归一化为单位长度 | 批归一化 / 层归一化 |
| 视觉词汇匹配 → 多尺度空间池化 → 分类器 | 多层特征 → 全连接层 → softmax |
关键区别在于:CNN 中每一步的参数都不是固定的,而是从数据中学来的。
深度学习简史
神经网络的历史充满了起伏:
- 1950 年代:Rosenblatt 发明感知机
- 1980-90 年代:神经网络流行一时后被认为难以优化而遭冷落
- 1990 年代:LeCun 用卷积网络在字符识别上取得最好效果(已包含现代 CNN 的核心思想)
- 2000 年代:少数研究者坚持深度网络研究,但在视觉界缺乏认可
- 2012 年:AlexNet 在 ImageNet 挑战赛上以惊人的优势获胜——从此改变了整个领域
从感知机到多层网络
感知机(Perceptron)是最简单的神经元模型:输入向量 与权重 做内积,加偏置 ,通过符号函数输出分类结果:。单层感知机只能学习线性可分的函数。
加入一个隐含层并使用可微的非线性激活函数(如 Sigmoid ),网络就能学习非线性函数。多层堆叠则能表示越来越复杂的函数。
训练多层网络的目标是最小化预测误差:
通过梯度下降更新权重:。反向传播(Backpropagation)利用链式法则从输出层到输入层逐层计算梯度。随机梯度下降(SGD)每次只用一小批样本计算梯度更新,在多个 epoch 中随机遍历训练集。
CNN 的核心操作
普通的全连接网络将整张图像展平为一个向量,每个像素与每个隐含单元都有连接——这导致参数爆炸(一张 的图像就有 15 万个输入维度)。卷积神经网络(CNN)通过两个关键约束解决这个问题:
局部连接:每个隐含单元只连接输入图像的一个小区域(感受野),而不是整张图。这编码了一个先验:相邻像素的相关性远高于远距离像素。
权重共享:同一个卷积核在图像的所有位置上使用相同的权重——换句话说,在图像的每个位置都计算同一个局部函数。这不仅大幅减少参数,还天然地提供了平移等变性:物体移动时,特征图也跟着移动。
一个 CNN 层的基本操作是:
- 卷积(Convolution):用一组可学习的滤波器与输入做卷积,每个滤波器产生一个特征图(Feature Map)——这和第 3 章的图像滤波完全一样,只是滤波器的权重不再是手工设计的,而是从数据中学习的
- 非线性激活:对特征图逐元素应用 ReLU(Rectified Linear Unit):。ReLU 比 sigmoid 更好,因为它在正半轴上梯度恒为 1,不会出现梯度消失
- 空间池化(Spatial Pooling):在小区域内取最大值(最大池化),降低空间分辨率并增大感受野,同时提供一定的平移不变性
多个这样的层堆叠起来,底层的滤波器学到边缘和纹理(类似 Gabor 滤波器),中间层学到部件和模式,顶层学到整体物体和场景——这和第 5 章中视觉系统的层次结构(V1 → V2 → V4 → IT)不谋而合。
架构演进
LeNet-5(1998)
最早成功的 CNN 之一,用于手写数字识别。使用平均池化和 sigmoid/tanh 激活,在 MNIST 的 60K 训练样本上取得了当时最好的效果。它确立了 CNN 的基本结构:卷积层 → 子采样层 → 全连接层。
ImageNet 与 AlexNet(2012)
ImageNet 数据集的出现改变了一切:约 1400 万张标注图像,2 万个类别。其中 ILSVRC 挑战赛使用 120 万训练图像和 1000 个类别。
2012 年,AlexNet 在 ILSVRC 上以约 15% 的 top-5 错误率震惊了整个视觉社区——第二名使用传统方法的错误率约 25%,差距之大令人难以置信。AlexNet 的关键改进:
- 用最大池化和 ReLU 替代平均池化和 sigmoid
- 更大的模型:7 个隐含层,650K 单元,6000 万参数
- GPU 训练(比 CPU 快约 50 倍),两块 GPU 训练一周
- Dropout 正则化:训练时随机关闭一部分神经元,防止过拟合
VGGNet(2015)
VGGNet 的核心洞察:用多个 卷积层替代一个大卷积核。三个 层的感受野等效于一个 层,但参数量从 降低到 ,同时在每层之间加入 ReLU 增加了非线性。这一原则成为后续架构设计的标准。
GoogLeNet / Inception(2015)
GoogLeNet 引入了 Inception 模块:在同一层内并行使用不同大小的卷积核(、、)和池化,将结果拼接。
其中 卷积(最早由 Network in Network 提出)是一个看似奇怪但极为重要的操作。它的空间感受野只有一个像素,不做任何空间滤波——它做的是跨通道的线性组合。如果输入有 256 个通道,一个 的卷积层将每个像素位置的 256 维向量投影到 64 维,实现了通道降维。在大卷积之前用 卷积降维,大幅减少后续计算量。
网络还使用了辅助分类器(Auxiliary Classifier)在中间层提供额外的梯度信号,缓解深层网络的训练困难。
ResNet(2016)
当网络变得非常深时,训练误差反而上升——这不是过拟合,而是优化困难。ResNet 用残差连接(Skip / Shortcut Connection)优雅地解决了这个问题:
网络不需要学习整个映射 ,只需要学习「残差」。如果某一层应该做恒等映射(什么都不改),只需让 ——这比学习 容易得多。
ResNet 的瓶颈模块(Bottleneck)进一步用 卷积减少计算:先将 256 个通道降到 64(),做 卷积,再升回 256(),参数量从约 600K 降到约 70K。这使得网络可以达到 152 层甚至更深。
一个值得注意的趋势是:更深的网络反而用更少的参数。从 AlexNet 的 6000 万参数,到 VGGNet 的 1.38 亿(参数量的峰值),再到 GoogLeNet 的 500 万和 ResNet 的 2500 万——架构创新在增加深度的同时持续降低参数量,通过更高效的结构设计而非更大的模型来提升性能。
CNN 架构的关键思想总结
| 设计原则 | 作用 |
|---|---|
| 卷积层(局部连接 + 权重共享) | 大幅减少参数,编码空间局部性 |
| 池化 | 增大感受野,提供平移不变性 |
| ReLU | 在大部分定义域上保持梯度信号 |
| 小卷积核堆叠() | 用更少参数获得大感受野,增加非线性 |
| 卷积 | 通道间降维/升维 |
| 残差连接 | 使极深网络可训练,类似集成效应 |
从 CNN 到 Transformer
近年来,Vision Transformer(ViT)将 NLP 中的 Transformer 架构引入视觉:将图像切分为 的 patch,将每个 patch 线性嵌入后作为「token」输入标准 Transformer。ViT 在大规模预训练下表现优异,但原始 Transformer 的自注意力机制对所有 token 对计算相似度,复杂度为 。
Swin Transformer 通过滑动窗口(Shifted Window)机制解决了这个问题:在局部窗口内计算自注意力,并通过窗口移位实现跨窗口信息交换,形成类似 CNN 的层级结构(逐层合并 patch 以增大感受野)。这使得计算复杂度降为线性,同时保持了 Transformer 的建模能力。
ViT-22B(2023)将模型规模推至 220 亿参数,展示了视觉 Transformer 的规模扩展能力。
迁移学习
一个重要的实践发现是:在大数据集上预训练的 CNN 特征可以直接迁移到其他任务。具体做法是:在 ImageNet 上训练好一个 CNN,去掉最后的分类层,将中间层的输出作为通用的图像特征——即使不做任何微调,这些「现成的 CNN 特征」在物体分类、场景分类、属性检测、图像检索等十几个任务上都能达到或超过专门设计的方法。如果目标任务有足够的标注数据,还可以进一步微调(Fine-tune)整个网络以获得更好的性能。
目标检测
图像分类回答「是什么」,目标检测还要回答「在哪里」——输出不是一个类别标签,而是一组边界框(Bounding Box)加上对应的类别和置信度。
检测的一般流程
flowchart TD
A[定义目标模型] --> B[生成候选假设]
B --> C[评分假设]
C --> D[解决重叠检测]
classDef step fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
class A,B,C,D step
-
定义目标模型:用什么来描述目标?
- 统计模板:目标是一个 的边界框,框内的 HOG/CNN 特征满足某个统计模型
- 部件模型:目标是一组可检测部件的空间配置(如脸 = 眼睛 + 鼻子 + 嘴巴的特定排列)
- 混合模型:如 DPM(Deformable Parts Model),将全局模板和可变形部件结合
-
生成候选假设:在哪里寻找目标?
- 滑动窗口:在所有位置和尺度上滑动固定大小的窗口,逐一检测。全面但慢(约 10 万个候选)
- 关键点投票:利用 Ch8-9 的局部特征为目标中心投票(类似 Hough 变换)
- 区域提议(Region Proposal):基于图像的边缘和纹理生成约 2000-10000 个与物体形状贴合的候选区域(如 Selective Search)。比滑动窗口更少但更精准
-
评分假设:用 CNN 特征 + 分类器对每个候选评分
-
解决重叠:同一个物体可能有多个高分候选框
- 非极大值抑制(NMS):保留最高分的框,删除与它 IoU 超过阈值的其他框
- 上下文推理:利用场景信息排除不合理的检测(如天空中的汽车)
检测方法的演进
目标检测经历了从手工特征到深度学习的巨大飞跃。在 VOC 2007 数据集上,mAP 从 2005 年的约 0.1(HOG 模板)经过 DPM 系列(2008-2012,mAP 约 0.2-0.35)逐步提升,到 2014 年 R-CNN 的约 0.6,提升了 6 倍。
Viola-Jones 人脸检测器(2001)
在深度学习时代之前,最具影响力的检测方法是 Viola-Jones 人脸检测器。它引入了三个关键创新:
- Haar-like 特征:用简单的矩形差分(如水平边缘、垂直边缘、对角线)作为特征,通过积分图像实现常数时间计算
- AdaBoost 特征选择:从约 16 万个 Haar-like 特征中自动选择最有区分力的少量特征,构建强分类器
- 级联结构(Cascade):将多个分类器串联——前几级用极少的特征快速排除大部分非人脸区域(如背景),只有通过所有级别的候选才被判定为人脸
这种「快速排除 + 逐步精化」的设计使得 Viola-Jones 在 2001 年实现了实时人脸检测——处理速度比当时的其他方法快数百倍,是工程上的里程碑。
R-CNN(2014)
R-CNN 是第一个将 CNN 引入目标检测的方法:
- 用 Selective Search 生成约 2000 个区域提议
- 将每个区域裁剪并缩放到
- 用在 ImageNet 上预训练并微调的 CNN 提取特征
- 用 SVM 对最后一层特征做分类
准确率大幅提升,但速度很慢——每个区域都要单独做一次 CNN 前向传播。
Fast R-CNN(2015)
关键改进:只对整张图像做一次 CNN 前向传播,然后在特征图上为每个区域提议做 ROI 池化(将不同大小的区域池化为固定的 ),再接分类和回归层。相比 R-CNN 提速约 100 倍(从 0.02-0.1 FPS 提升到 0.5-20 FPS)。
Faster R-CNN(2016)
区域提议本身也可以用 CNN 生成。RPN(Region Proposal Network)在卷积特征图上为每个位置预测 个锚框(Anchor)的物体性分数和修正后的边界框,取代了 Selective Search。整个系统(RPN + 检测网络)共享卷积特征,相比 Fast R-CNN 再提速约 10 倍。
YOLO(2016)
YOLO(You Only Look Once)将检测重新定义为一个回归问题:将图像划分为 的网格,每个网格单元预测 2 个边界框(位置 + 置信度)和各类别的概率,最后用 NMS 合并。整个过程只需一次前向传播——速度达到 45-155 FPS(相比 Faster R-CNN 的 7-18 FPS 快约 7 倍),但在定位精度和小物体召回率上有所损失。
YOLOv2 引入批归一化、更高分辨率的预训练、锚框机制和多尺度训练,在保持速度的同时大幅提升了精度。
DETR(2020)
DETR(Detection Transformer)更进一步,使用 Transformer 实现端到端的目标检测——不需要锚框、不需要 NMS、不需要任何手工设计的组件。DETR 将检测建模为一个集合预测问题:一组可学习的「目标查询」(Object Query)通过 Transformer 解码器直接预测所有目标的类别和位置。
后续工作如 AdaMixer 改进了查询解码器的结构,用自适应混合策略替代标准的交叉注意力;Pix2Seq 则将检测重新定义为序列生成问题——给定图像,直接生成描述目标位置和类别的 token 序列,完全统一了检测与语言生成的范式。
检测方法的演进脉络
flowchart LR
A["HOG 模板<br/>(2005)"] --> B["DPM<br/>(2008-2012)"]
B --> C["R-CNN<br/>(2014)"]
C --> D["Fast/Faster R-CNN<br/>(2015-2016)"]
D --> E["YOLO 系列<br/>(2016-)"]
D --> F["DETR<br/>(2020)"]
classDef handcraft fill:#fff3e0,stroke:#ef6c00,stroke-width:2px
classDef hybrid fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
classDef deep fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
classDef e2e fill:#e8f5e8,stroke:#2e7d32,stroke-width:2px
class A,B handcraft
class C hybrid
class D,E deep
class F e2e
从 HOG 模板到 DETR,检测方法的演进反映了一个清晰的趋势:手工设计的组件逐步被可学习的模块替代。HOG 需要手工设计特征,DPM 需要手工设计部件模型,R-CNN 系列需要手工设计区域提议和 NMS,而 DETR 将整个流程端到端化——唯一需要的输入是图像和标注。
课程在视觉系统中的位置
本章标志着课程基础部分的收尾。从底层(像素、滤波、频率)到中层(边缘、分割、关键点、匹配)再到高层(识别、检测),我们走完了经典计算机视觉的完整链条。后续的前沿部分(深度学习架构、视频理解、视觉生成等)将在这些基础之上展开。