📑 本页目录(点开跳转)
18 · 经典计算机视觉
⏱ 36 分钟 | ⭐⭐ 深度学习之前,机器「看见」靠一层层手写的小卷积核 —— 其中一半今天还在跑
🎯 一句话
经典视觉把「看」拆成两步:先用固定的小核把图洗成边缘和区域,再拿几何和已知的三维模型去解释这些边缘。 ⭐⭐ CNN 没有推翻第一步,它只是把「核由人写死」换成了「核由数据学」; 第二步的几何则原封不动地长在今天的深度相机、相机标定和 SLAM 里。
这一章和下一章是全板块唯一被深度学习大面积取代的两块,所以写法不同: 当年怎么做 → 为什么输 → 哪些今天仍是对的选择,第三段才是你要带走的。
🖼 一、图像在机器眼里就是一个矩阵
一张图是二维时变强度矩阵 $I(x,y,t)$:彩色三个矩阵(RGB),灰度一个。每格叫像素,那个数是亮度。 最省事的处理是二值化(比阈值亮给 1,其余给 0)—— 糙,但产线上抓零件真的够用。 ⭐ 本章第一个「还活着」的例子:光照可控时,最笨的方法最稳。
💀 所有视觉方法共同的原罪:透视投影是多对一的。 三维 → 二维不可逆,完全不同的场景能投出一模一样的图(远处的大楼 vs 贴在镜头前的小纸片)。 ⚠️ 这不是经典方法的缺陷 —— 神经网络也没解决它,只是用「大楼比纸片常见」的统计先验把歧义压住了。
因为不可逆,机器人视觉被拆成两个阶段:
| 阶段 | 干什么 | 输出 |
|---|---|---|
| 图像处理 | 滤波:降噪、突出边缘、找区域 | 还是一张图 |
| 场景分析 | 解释:这些线条是什么物体、什么姿态 | 符号描述 |
第二阶段的输出长这样:地上叠着三块积木,写成 ((C B A FLOOR))。
⭐ 这已经不是图像了,是一句能拿去做逻辑推理的话。
🧹 二、平滑:一个能手算完的例子
真实图像永远带噪声。平滑=拿小窗口在图上滑,用窗口内所有值的平均替换中心值。 滑动 + 加权求和,这个操作就叫卷积。3×3 窗口在 4×4 上只有四个合法位置(中心必须落在内圈):
$$ I=\begin{bmatrix}9&9&9&3\\9&9&3&3\\9&3&3&3\\3&3&3&3\end{bmatrix} \quad\xrightarrow{\ \text{3×3 均值}\ }\quad \text{内圈四格变成}\ \begin{bmatrix}7&5\\5&4\end{bmatrix} $$
四个窗口的和是 63、45、45、33,除以 9 得 7 / 5 / 5 / 4(最后一个 3.67 四舍五入),外圈不动。
⭐ 原来 9 和 3 之间是一刀切的对角线,平滑后成了 9→7→5→4→3 的斜坡 —— 这就是平滑和边缘检测天然打架的证据:噪声被抹平,真边缘也被抹钝,细线被抹掉,粗线被加宽。
📐 三、边缘:本章的核心手算
边缘 = 亮度突然变化的地方,连起来就是线画,线画能和物体模型比对。找突变就是求梯度, 离散图像上用一对固定的 3×3 核近似 —— 最有名的是 Prewitt 和 Sobel。
拿刚才那个 4×4 的左上窗口手算:
$$ \begin{bmatrix}9&9&9\\9&9&3\\9&3&3\end{bmatrix} \Rightarrow G_x = (-9{+}9)+(-18{+}6)+(-9{+}3) = -18,\quad G_y = (-9{-}18{-}9)+(9{+}6{+}3) = -18 $$
边缘强度取 $|G_x|+|G_y| = 36$。四个位置全算完是 36 / 36 / 36 / 12,方向全是 −135°。
⭐ 三个 36 排成一条对角线,正压在 9 区和 3 区的分界上;右下那个 12 弱,是因为它窗口里八格都是 3。 换 Prewitt(把 2 都改成 1)得 24 / 24 / 24 / 12,结论一样只差尺度 —— 所以这类算子从不争「谁更准」,差别只在噪声鲁棒性。
复现只要四行(纯标准库,本机跑过):
def conv(img, k): # 3×3 卷积
return [[sum(img[y+dy][x+dx] * k[dy+1][dx+1] # ⭐ 核与窗口逐格相乘再求和
for dy in (-1,0,1) for dx in (-1,0,1))
for x in range(1, len(img[0])-1)] for y in range(1, len(img)-1)]
I = [[9,9,9,3], [9,9,3,3], [9,3,3,3], [3,3,3,3]]
gx = conv(I, [[-1,0,1], [-2,0,2], [-1,0,1]])
gy = conv(I, [[-1,-2,-1], [0,0,0], [1,2,1]])
print([[abs(a)+abs(b) for a,b in zip(p,q)] for p,q in zip(gx,gy)]) # [[36, 36], [36, 12]]
找区域是边缘的反面:盯内部基本不变的一块,判据是强度差不超过阈值 $\varepsilon$。经典做法叫分裂-合并 —— 不同质就切成四块(四叉树),递归到不用再切,再把相邻同质块合回来。⭐ 没有参数要训,$\varepsilon$ 是你自己定的数。
🔍 四、场景分析:从线条到「这是个什么」
图像处理输出的还是图,场景分析要把它变成描述。因为场景到图像是多对一, 这一步必须往里加信息:相机在哪、光源在哪、可能有哪些物体。
对直棱物体拿直线段拟合边缘,对曲面物体拟合圆锥曲线,然后解释每条线代表什么。 在「只有平面、任一点最多三个面相交」的三面体世界里,答案只有三种标注: → 遮挡、+ 凸边(blade)、− 凹边(fold)。线条汇合处的结点按形状分 V、W、Y、T 四类, 而经典的 Huffman–Clowes 标注表算出来:208 种组合里只有 18 种物理上可实现。
⭐⭐ 于是「看懂一张线画」变成一个纯粹的约束满足问题:给每条线选标注,使两端结点都落在合法表里。 这里没有一个数是从数据里学的,全是几何本身给的硬约束。
模型驱动视觉再进一步:工业场景里你事先就知道有什么 —— 传送带上来的就是那个零件,图纸你有。 那就拿几何模型去拟合:把立方体投影到图上,调尺寸位置朝向(欧拉角)直到和边缘图对上; 复杂形状用广义圆柱搭,每个 9 个参数。⚠️ 它做的不是识别,是配准 —— 只回答「已知是它,现在多大、在哪、朝哪」。这个分工今天几乎没变。
👁 五、立体视觉:两只眼睛才有深度
单图测距很难(例外:已知物体在地面上、又已知相机高度)。通用办法是两个镜头,间距 $b$ 叫基线。 同一个点在左右两幅图里位置不同,这个差叫视差 $d$。
$$Z = \frac{f \cdot b}{d}$$
手算一组:$f = 800$ 像素、$b = 12\ \text{cm}$ 时,视差 40 → $Z = 2.4$ m,20 → 4.8 m,10 → 9.6 m,4 → 24 m。
⚠️ 视差从 10 掉到 4,深度就从 9.6 m 跳到 24 m。 误差按 $Z^2$ 放大 —— 匹配精度取 0.5 像素时, 2.4 m 处误差约 3 cm、24 m 处约 3 m。消费级深度相机量程只有几米,不是传感器不行,是 $Z^2$ 不讲道理。
还有个真难点叫对应问题:得先知道左图哪个像素和右图哪个像素是同一个点, 而无纹理的白墙上这件事无解(每个像素长得都一样)。 ⭐ 所以结构光相机要打散斑:它不是在测光,是在人为造纹理,好让对应问题有解。
🤝 六、和 CNN 的对照:本章最该记住的一条
| 经典边缘算子 | CNN 第一层 | |
|---|---|---|
| 运算 | 3×3 滑窗,逐格乘加 | 3×3 滑窗,逐格乘加 |
| 核里那九个数 | 人写死(Sobel / Prewitt) | 反向传播学出来 |
| 核的数量 | 有几个用几个 | 几十上百个并行 |
| 后面接什么 | 人写的规则(拟合线段、结点标注) | 同样的东西再来几十层 |
⭐⭐ 关键事实:把训练好的 CNN 第一层卷积核画出来,它们和手工边缘算子长得惊人地像(各个朝向的明暗条纹)。 梯度下降自己重新发现了边缘检测。
⭐⭐ CNN 不是推翻了经典视觉,是把「设计特征」换成了「学特征」。 卷积这个机制、局部感受野这个想法、层层抽象这个结构,全是经典视觉留下来的。 换掉的只有一件事:那九个数是谁定的。
那为什么一换就赢?赢在第一层之后。经典方法的第二第三层是人写的规则,而规则写到第三层就写不动了 —— 「猫」没有一条可以写下来的边缘组合规则。CNN 的第二第三层还是同一件事,有数据就能一直堆下去。
⚠️ 但学出来也有代价。1989 年的 ALVINN 用神经网络直接开车:输入 30×32 低分辨率图, 隐层只有 5 个 sigmoid 单元,输出 30 个单元投票定方向盘角度,训练数据是人类开车的 5 分钟录像:
💀 人类司机开得太好了。 训练数据里几乎没有「车已经偏出车道、需要打回来」的样本,走过一段长直路后网络就学成永远直行 —— 真偏了它不知道怎么救。⭐ 这是采样偏差最早的实例之一,而规则方法根本不会犯这个错: 「偏离中线就打方向」是一行规则,不需要在数据里出现过。
🧭 七、被取代了什么,还活着什么
诚实说:通用视觉上经典方法输了,而且输得彻底 —— 分类、检测、分割、姿态估计今天没有一个 SOTA 靠手写算子, 原因就是上一节那句:规则写不到第三层。 但「输了通用」不等于「没用了」——
| 还活着的部分 | 为什么没被换掉 |
|---|---|
| 边缘 / 角点检测 | 相机标定、图像拼接、SLAM 前端的第一步。⭐ 它要的是亚像素级可复算位置,不是语义 |
| 立体几何 | 深度相机、双目模组的基础就是 $Z = fb/d$。神经网络改的是对应问题,几何没得改 |
| 模型驱动配准 | 工业检测主力:图纸已有、光照可控、零训练数据,还能给出「差 0.2 mm」的可解释输出 |
| 二值化、连通域、形态学 | 产线上又快又稳;也常做神经模型的前后处理(去毛刺、补洞、合并碎片) |
⭐⭐ 判据一句话:要「这是什么」用学出来的,要「它在哪、差多少」用几何算出来的。 前者是语义问题,规则写不完;后者是测量问题,数据反而会引入不该有的偏差。
另有四种场景经典方法仍更合适:没有标注数据、必须解释每一步、 算力受限到跑不动网络、需要确定性保证(同输入同输出,且能证明误差上界)。
🔗 这一章连到哪里
| 去哪 | 为什么 |
|---|---|
| ML基础 12 · CNN | ⭐⭐ 本章最该走的一条。那边的卷积、感受野、层层堆叠,机制和本章第三节一模一样,唯一改动是九个数从人写死变成学出来;带着这一章再读,「为什么是卷积不是全连接」会变得显然 |
| 数据这一关 15 · 采样偏差与幸存者偏差 | ALVINN「司机开得太好所以学不会纠偏」是这个坑最早的实例,去看今天怎么系统性地防 |
| 19 · 经典 NLP | 同一个故事的另一半:语言那边的手写规则也被接管了,也留下一批今天还在用的东西 |
✅ 检查点
- 为什么图像不能被直接反演成场景?这是经典方法特有的毛病吗?
- 那个 4×4 用 3×3 均值平滑,为什么只有四个位置?四个数是多少?暴露了平滑的什么代价?
- Sobel 的 $G_x$、$G_y$ 各找什么方向的边缘?左上窗口手算多少?四个位置的强度?换 Prewitt 呢?
- 三面体世界里线条只有哪三种标注?为什么说「解释一张线画」是个约束满足问题?
- 模型驱动视觉做的是识别还是配准?
- 立体视觉的深度公式?$f=800$、$b=12$ cm 时视差 10 和 4 各对应多远?为什么远处误差大得多?
- 对应问题是什么?结构光打散斑是在干什么?
- 经典边缘算子和 CNN 第一层,相同与不同各是什么?CNN 赢在哪一层?
- 举三类今天仍该用经典方法的场景,说出统一判据。
👀 答案
- 透视投影是多对一的变换:不同的三维场景能投出完全相同的图像(远处大楼 vs 镜头前小纸片)。⚠️ 不是经典方法特有的 —— 神经网络也没解决,只是用统计先验压住。
- 3×3 窗口中心必须落在内圈,4×4 的内圈只有 2×2 = 4 格。四窗和 63/45/45/33,除 9 得 7 / 5 / 5 / 4。代价:一刀切被抹成 9→7→5→4→3 的斜坡 —— 抹平噪声的同时也抹钝了真边缘。
- $G_x$ 找竖直边缘,$G_y$ 找水平边缘。左上窗口 $G_x = G_y = \mathbf{-18}$,强度 36,方向 −135°;四个位置 36 / 36 / 36 / 12。Prewitt 给 24 / 24 / 24 / 12 —— ⭐ 同一个东西只差尺度。
- → 遮挡、+ 凸边、− 凹边。之所以是 CSP:每条线要选一个标注,而 V / W / Y / T 四类结点只允许极少数组合 —— 208 种组合中只有 18 种物理可实现。⭐ 约束全来自几何,没有一个数是学的。
- 配准。它答不了「这是什么」,只答「已知是这个零件,现在多大、在哪、朝哪」—— 把已知模型(广义圆柱每个 9 参数)投影到图上调位姿,直到和边缘图对上。
- $Z = f\cdot b/d$。$d=10 \to \mathbf{9.6\ m}$,$d=4 \to \mathbf{24\ m}$。⚠️ 误差按 $Z^2$ 放大:0.5 像素精度下 2.4 m 处约 3 cm、24 m 处约 3 m。几何决定的,换算法没用。
- 判断左图哪个像素与右图哪个像素是同一场景点;⚠️ 白墙上无解。⭐ 打散斑不是在测光,是人为造纹理。
- 相同:3×3 滑窗逐格乘加、局部感受野、层层抽象。不同:那九个数人写死还是学出来、核的数量、后面接人写的规则还是更多同样的层。⭐ CNN 赢在第二层往后:规则写到第三层就写不动了(「猫」没有可写下来的边缘组合规则)。
- ⭐⭐ 要「这是什么」用学出来的,要「它在哪、差多少」用几何算出来的。 三类任选:标定/拼接/SLAM 前端的边缘角点、工业模型配准(零数据、可解释到 0.2 mm)、二值化连通域的产线定位。另加无数据、要可解释、算力受限、要确定性保证。
🛑 可以停在这里
⚡ 走神救援
💀 原罪:透视投影多对一、图像不可逆,⚠️ 神经网络也没解决,只是用统计先验压住。视觉分两阶段:图像处理 → 场景分析(出符号描述如
((C B A FLOOR)))。⭐平滑=滑窗取均值,4×4 上只有 4 个合法位置,四窗和 63/45/45/33 → 7 / 5 / 5 / 4,一刀切被抹成 9→7→5→4→3 的斜坡,这就是平滑与边缘天然打架。⭐边缘=求梯度:Sobel 在左上窗口给 $G_x = G_y = -18$,四个位置强度 36 / 36 / 36 / 12、方向全 −135°;Prewitt 是 24 / 24 / 24 / 12,同一个东西只差尺度。分裂-合并找区域,没有参数要训。三面体世界线条只有 → 遮挡 / + 凸 / − 凹,⭐⭐ 208 种结点组合只有 18 种物理可实现 —— 「看懂线画」是个纯约束满足问题。模型驱动视觉⚠️ 不是识别是配准(广义圆柱每个 9 参数)。立体视觉 $Z = fb/d$:$f=800$、$b=12$ cm 时视差 20 → 4.8 m、4 → 24 m,⚠️ 误差按 $Z^2$ 放大(0.5 像素精度在 2.4 m 错 3 cm、24 m 错 3 m);⭐ 打散斑是人为造纹理,好让对应问题有解。⭐⭐ 全章核心:经典边缘算子和 CNN 第一层运算完全一样,差别只在那九个数是人写死还是学出来 —— CNN 是把「设计特征」换成「学特征」,赢在第二层往后(规则写到第三层就写不动了)。💀 ALVINN(1989,5 个隐层单元、5 分钟驾驶数据)司机开得太好,网络学成永远直行。⭐⭐ 选型:要「这是什么」用学的,要「它在哪、差多少」用几何算的;另有无数据、要可解释、算力受限、要确定性保证四种场景仍首选经典。
下一节 👉 19-经典NLP.md
去那里的理由:视觉这边的结论是「手写的核输给了学出来的核」。语言那边有一套更精致的手写系统 —— 形式文法、句法分析树、指代消解规则,同样被接管了。但那一章有件本章没有的事: 有一块老技术不但没被取代,还在今天的 LLM 里换了个名字继续跑 —— 你每次让模型「只输出 JSON」,用的就是它。