3. 相机成像模型
聊到人像模式,绕不开一个核心问题:手机怎么知道物体离我有多远?
答案就藏在相机成像模型里。说白了,我们得先搞懂相机是怎么「看」世界的,才能教它算出深度。这一章我会从最经典的针孔模型讲起,再带你理解视差和深度的关系,最后落到双目立体视觉——这也是很多手机双摄方案的理论基础。
3.1 针孔相机模型:最朴素的成像方式
针孔相机模型,是所有相机模型的起点。它简单到令人发指:一个不透光的盒子,前面戳个小孔,后面放一张感光底片。
光线从物体表面反射,穿过小孔,在底片上形成一个倒立的像。这就是最原始的成像过程。
核心公式(投影关系):
X_screen = f * (X_world / Z_world)
Y_screen = f * (Y_world / Z_world)
其中 f 是焦距(小孔到成像平面的距离),(X_world, Y_world, Z_world) 是物体在三维空间中的坐标,(X_screen, Y_screen) 是像点在成像平面上的位置。
这个公式告诉我们一件事:物体越远(Z_world 越大),它在成像平面上的投影就越小。反过来,近处的物体看起来更大。这就是透视效应的数学本质。
我在项目中遇到过一个问题:用针孔模型标定手机摄像头时,发现边缘区域畸变特别严重。后来才意识到,针孔模型是理想情况,真实镜头有透镜,必须引入畸变参数才能校正。嗯,这个坑我踩过,后面讲相机标定时会细说。
3.2 从针孔到数字图像:内参矩阵
实际相机不是用物理底片,而是用 CMOS 传感器把光信号转成像素。所以我们需要把成像平面上的物理坐标,映射到像素坐标上。
这个映射关系,就是相机内参矩阵 K:
K = [[fx, 0, cx],
[ 0, fy, cy],
[ 0, 0, 1]]
- fx, fy:焦距在 x 和 y 方向上的像素单位(通常很接近)
- cx, cy:光心在像素坐标系中的位置(一般是图像中心附近)
有了内参矩阵,我们就可以把三维空间中的点,投影到二维像素坐标上:
pixel_u = fx * (X_world / Z_world) + cx
pixel_v = fy * (Y_world / Z_world) + cy
我的习惯:拿到一台新手机或相机,第一件事就是标定内参。很多深度估计算法精度上不去,其实就是内参没标准。别问我怎么知道的……
3.3 视差与深度:一对天生的冤家
单目相机只能得到二维投影,丢失了深度信息。那怎么找回深度?答案是:用两个相机看同一个点。
你想想看,人的两只眼睛为什么长在两边?就是为了产生视差。左右眼看到的同一物体,在视网膜上的位置是有偏移的,这个偏移量就是视差。
视差和深度的关系,可以用一个极其简洁的公式表达:
深度-视差公式:
Z = (f * B) / d
其中:
- Z:物体到相机的深度(距离)
- f:相机焦距(像素单位)
- B:两个相机之间的基线距离
- d:视差值(左右图像中对应点的像素偏移)
这个公式告诉我们:视差越大,物体越近;视差越小,物体越远。而且深度和视差成反比——近处的物体视差变化剧烈,远处的物体视差变化平缓。
我曾经在做一个双目测距项目时,发现远处物体的深度抖动特别厉害。后来一分析,就是因为视差太小,量化误差被放大了。所以双目系统对远距离物体的深度估计,天生就不准。这也是为什么人像模式主要关注近景——散景效果本来就在近处才明显。
3.4 双目立体视觉:从两幅图算出深度图
双目立体视觉的流程,说白了就是三步:
- 图像校正:把左右两张图拉平,让对应的像素点在同一行上
- 立体匹配:在左图中选一个点,去右图的同一行上找它的匹配点
- 三角测量:根据匹配点的偏移量(视差),用上面的公式算出深度
这里面最核心、也最难的,是第二步——立体匹配。你想想看,左图的一个像素点,怎么在右图上找到它的「另一半」?
常用的方法有:
| 方法 | 原理 | 优缺点 |
|---|---|---|
| 块匹配(Block Matching) | 以像素为中心取一个小窗口,计算左右窗口的相似度 | 速度快,但纹理弱区域容易出错 |
| SGM(半全局匹配) | 在块匹配基础上加入平滑约束,沿多个方向优化 | 精度高,速度适中,工业界常用 |
| 深度学习匹配 | 用 CNN 提取特征,计算匹配代价 | 精度最高,但需要 GPU,功耗大 |
注意:立体匹配有一个前提——左右图像必须已经极线校正过。如果没有校正,匹配点可能出现在不同行上,搜索空间从一维变成二维,计算量爆炸。我见过有人直接拿原始双目图像做匹配,结果跑了一天都没出结果……
3.5 知识结构总览
下面这张图,把本章的核心逻辑串起来了。你可以把它当作一个思维导图来看:
3.6 从理论到实战:双目系统的局限
理论讲完了,说点实际的。双目立体视觉在手机上做人像模式,有几个绕不开的坎:
- 基线限制:手机两个摄像头之间的距离就那么几厘米,导致视差范围很小,深度分辨率有限
- 弱纹理区域:拍一面白墙,左右图看起来一模一样,立体匹配直接失效
- 遮挡问题:左图能看到的点,右图可能被前景挡住,匹配不到
- 计算量:实时做全图立体匹配,手机芯片的功耗和发热是个大问题
我的建议:如果你在手机上做深度估计,别只依赖双目。现在的主流方案都是双目 + ToF + 深度学习多模态融合。单靠双目,在复杂场景下很容易翻车。