图像几何映射表(Map)不是双目专属的数据。它是一种通用的坐标变换描述:输出图像中的每一个像素,应该去输入图像的哪个位置取值。 单目用它去除镜头畸变,双目用左右两张 Map 同时完成去畸变和极线对齐,多目系统则用每个相机的 Map 把图像投影到统一的全景、鸟瞰或三维坐标系。
从 AI 数据通路看,Map 不送进神经网络。标定软件根据内参、畸变和相机间外参生成 Map,LDC/Dewarp/Remap 硬件逐像素查表并插值,输出经过几何校正的图像,再进行颜色转换、缩放、归一化和 Tensor 化。
先建立整体认识
Map 在数据通路中的位置
离线标定或启动阶段:
相机内参 K、畸变 D、相机间外参 R/T
│
▼
标定与校正软件
│
▼
left_map / right_map / mono_map
│
▼
保存到文件或DDR
每帧运行阶段:
Camera → ISP → NV12/RGB图像
│
图像 + 对应Map
│
▼
LDC / Dewarp / Remap
│
▼
几何校正后的图像
│
▼
CSC / Resize / Normalize / Quantize
│
▼
Tensor
│
▼
NPU模型或视觉算法
这里需要区分两类工作:
- Map 生成把相机模型编译成像素坐标关系,通常只在标定、启动或配置切换时由软件完成;
- Map 执行对每一帧、每一个输出像素查坐标并插值,吞吐量大,适合交给硬件。
Map 记录的内容
假设校正后的输出图像大小为 $W\times H$,对于每一个输出像素 $(u_o,v_o)$,Map 保存一个输入图像坐标:
$$ \operatorname{Map}(u_o,v_o)=(u_s,v_s) $$
例如:
left_map[100][200] = (203.25, 98.60)
它表示:生成校正后左图的像素 $(200,100)$ 时,应该从原始左图的 $(203.25,98.60)$ 位置取值。
源坐标通常不是整数,硬件需要读取周围四个像素并做双线性插值:
(203,98) (204,98)
●────────────────────────────────●
│ × │
│ (203.25,98.60) │
●────────────────────────────────●
(203,99) (204,99)
运行关系可以写成:
$$ I_{out}(u_o,v_o)=I_{in}\bigl(\operatorname{Map}_x(u_o,v_o), \operatorname{Map}_y(u_o,v_o)\bigr) $$
右侧不是简单的数组整数访问,而是带插值的采样。
把它理解成给空白画布逐像素取色
“输出图像中的每一个像素,应该去输入图像的哪个位置取值”听起来有些反直觉,是因为这里不是把输入像素向外推,而是先确定校正后的输出画布,再逐个填写输出像素:
准备一张空白的校正图
│
▼
处理输出像素 (0,0)
查Map → 去原图取颜色 → 写入输出
│
▼
处理输出像素 (1,0)
查Map → 去原图取颜色 → 写入输出
│
...
│
▼
所有输出像素填写完成
Map 保存的是坐标,不是颜色:
map[y][x] = (src_x, src_y) 坐标导航
input[y][x] = (R, G, B) 图像颜色
因此,map[100][200]=(203.25,98.60) 的完整含义是:输出画布的 $(200,100)$ 需要一个颜色,Map 指示它去原图 $(203.25,98.60)$ 附近取色,插值完成后再把结果写回输出画布的 $(200,100)$。
如果不做任何几何变换,Map中的输出坐标和输入坐标完全相同:
map[y][x] = (x,y)
output[y][x] = input[y][x]
这称为单位映射。去畸变、旋转、缩放和双目校正,本质上只是让不同输出像素查到不同的输入坐标。可以把 Map 看成一张“取色导航表”:输出图像决定最终像素排列,输入图像提供颜色来源,Map负责连接两者。
为什么相机图像需要几何校正
镜头畸变破坏理想投影
理想针孔相机把空间点 $(X,Y,Z)$ 投影到图像坐标:
$$ x=\frac{X}{Z},\qquad y=\frac{Y}{Z} $$
$$ u=f_xx+c_x,\qquad v=f_yy+c_y $$
其中相机内参矩阵为:
$$ K= \begin{bmatrix} f_x&0&c_x\ 0&f_y&c_y\ 0&0&1 \end{bmatrix} $$
真实镜头会使理想坐标发生径向和切向畸变。以常见模型为例,令 $r^2=x^2+y^2$:
$$ x_d=x(1+k_1r^2+k_2r^4+k_3r^6)+2p_1xy+p_2(r^2+2x^2) $$
$$ y_d=y(1+k_1r^2+k_2r^4+k_3r^6)+p_1(r^2+2y^2)+2p_2xy $$
$k_1,k_2,k_3$ 描述径向畸变,$p_1,p_2$ 描述镜头与成像平面不完全对正造成的切向畸变。实际像素为:
$$ u_d=f_xx_d+c_x,\qquad v_d=f_yy_d+c_y $$
因此,原图里的直线可能变成弧线,图像边缘位置也不再符合简单的针孔模型。
双目还有相机姿态不一致
双目系统的左右相机即使安装在同一支架上,也会存在微小的俯仰、偏航、滚转和高度误差。同一个空间点在两幅原图中可能落在不同的行:
校正前:
左图 右图
──────────── ────────────
● (uL,200) ● (uR,205)
而常见双目匹配希望只沿水平方向搜索:
校正后:
左图 右图
──────────── ────────────
● (320,202) ● (300,202)
视差 d = 320 - 300 = 20 pixel
双目校正的目标是构造一对虚拟的平行相机,使左右对应点落在同一行。Map 随后把真实相机图像重采样到这两个虚拟相机的成像平面。
单目、双目和多目分别怎样使用Map
| 场景 | Map数量 | 生成依据 | 主要目的 |
|---|---|---|---|
| 单目去畸变 | 每个相机一张 | 该相机的 $K,D$ | 拉直桶形、枕形等镜头畸变 |
| 鱼眼展开 | 每个相机一张或多个输出视角 | 鱼眼模型、目标投影模型 | 将鱼眼图像变成透视图、柱面图等 |
| 双目校正 | 左右各一张 | $K_L,D_L,K_R,D_R,R,T$ | 去畸变并让左右对应点行对齐 |
| 多目拼接/环视 | 每个相机至少一张 | 各自标定与公共坐标系 | 投影到全景图或鸟瞰图 |
| 电子防抖/透视变换 | 按帧或按姿态更新 | IMU、单应矩阵或目标视角 | 补偿抖动或改变观察视角 |
单目模型不一定都要先去畸变。普通分类、检测和分割模型如果使用同类畸变图像训练,可能直接适应原图;SLAM、视觉测量、机器人定位、抓取、AR 和鱼眼算法更依赖正确的几何关系,通常需要明确处理畸变。
双目模型对校正更敏感。LiteAnyStereo 等模型的相关性计算建立在“对应点位于同一行”这一假设上,普通 LDC 只把曲线拉直,并不自动保证左右行对齐。
双目Map的生成原理
先建立一对虚拟平行相机
双目标定得到:
左相机:K_L、D_L
右相机:K_R、D_R
左右关系:R、T
校正算法根据基线方向,计算左右校正旋转 $R_1,R_2$,把真实左右相机的光轴旋转到一对共同的虚拟成像平面;同时得到校正后的投影矩阵 $P_1,P_2$ 和深度重投影矩阵 $Q$。
真实相机:
左相机 ↗ ↘ 右相机
姿态存在安装误差
校正后的虚拟相机:
左相机 → → 右相机
成像平面平行、极线水平
$R_1,R_2$ 决定图像怎样旋转到校正坐标系,$P_1,P_2$ 定义校正图的焦距、主点和基线表示,$Q$ 用于把视差重新投影成三维坐标。
再为每个输出像素寻找原图坐标
Map 采用反向映射。对于校正图中的一个输出像素 $p_o=[u_o,v_o,1]^T$,大致经历以下过程:
校正图像素 p_o
│
▼
用校正后内参反投影成虚拟相机射线
│
▼
通过 R1⁻¹ 或 R2⁻¹ 转回真实相机射线
│
▼
应用该真实镜头的畸变模型 D
│
▼
使用原相机内参 K 投影到原图
│
▼
得到源坐标 (u_s,v_s)
│
▼
写入 left_map 或 right_map
概念上可以写成:
$$ \mathbf r_{rect}=K_{rect}^{-1}\mathbf p_o $$
$$ \mathbf r_{real}=R_{rect}^{-1}\mathbf r_{rect} $$
然后将 $\mathbf r_{real}$ 归一化,应用畸变参数 $D$,最后通过原始内参 $K$ 投影,得到源图坐标。
软件对输出画布中的每个像素执行一次上述计算,就形成完整 Map。OpenCV 中常见的软件流程是:
stereoCalibrate
│
▼
stereoRectify
│
▼
initUndistortRectifyMap
│
▼
left_map / right_map
│
▼
remap
这些函数只是一个常见实现,Map 的原理不依赖 OpenCV。
为什么使用反向映射
直觉上可以把原图像素向校正图“推过去”,这称为前向映射。但多个源像素可能落到同一位置,部分输出位置又可能没人覆盖,容易产生重叠和空洞:
源像素前向投影到输出:
● ● ● ● ●
↑
输出空洞
反向映射从每个输出像素出发,询问它应该去原图哪里取值:
每个输出像素
│
▼
查Map得到输入坐标
│
▼
插值采样
这样输出画布上的每个像素都有明确的处理过程,更适合固定吞吐的硬件流水线。超出原图范围的坐标则按配置填零、复制边缘或标为无效区域。
Map的存储形式
稠密Map
稠密 Map 为每个输出像素保存横纵两个源坐标,表达能力最强:
map[y][x] = (src_x, src_y)
如果两个坐标都使用 FP32,一个输出像素需要 8 字节。对于 $1920\times1080$:
一张Map约15.8 MiB
双目两张约31.6 MiB
这还没有计算每帧读取图像和写出结果的带宽。硬件通常会采用定点坐标、压缩格式和片上缓存降低开销。
Mesh网格
Mesh 只保存稀疏控制点,硬件在网格内部插值生成逐像素坐标:
●────●────●
│ │ │
●────●────●
│ │ │
●────●────●
Mesh 能显著减少 Map 存储和读取带宽,但网格太稀时无法准确描述强鱼眼畸变和复杂双目校正。硬件规格需要说明网格间距、坐标精度和插值方式,并用实际标定数据验证残余误差。
复合Map
Map 不必只表示去畸变。软件可以把去畸变、双目校正、裁剪和缩放合并成一次输出到输入的坐标变换:
去畸变 + 极线校正 + Crop + Resize
│
▼
复合Map
运行时只重采样一次,可以减少中间图像、DDR读写和多次插值造成的画质损失。此时校正后的有效内参也要随输出分辨率、裁剪和填充同步更新,深度换算必须使用最终输出画布对应的 $f_x$。
软硬件应该怎样分工
软件负责生成和管理Map
软件侧通常负责:
- 读取工厂标定得到的 $K,D,R,T$;
- 根据目标分辨率、裁剪和投影方式生成 Map;
- 为 Map 分配设备可访问的内存;
- 维护
calibration_profile_id和版本; - 在分辨率、Sensor模式或标定版本改变时切换 Map;
- 同时保存校正后的内参、$P_1,P_2,Q$ 和基线,供深度及点云后处理使用。
Map 通常不需要每帧生成。固定镜头、固定分辨率的产品可以在工厂工具中提前生成并保存;支持动态裁剪、电子防抖或变焦的系统才可能按配置或按帧更新。
硬件负责逐帧Remap
LDC/Dewarp/Remap 硬件负责:
for 每个输出像素 (x,y):
(src_x,src_y) = map(x,y)
dst(x,y) = bilinear_sample(src,src_x,src_y)
对于双目,硬件不必理解“内参、外参、极线”这些概念,只要能为左右通道加载不同的任意二维反向 Map,并以足够精度完成插值即可。
如果输入是 NV12,硬件还需要明确 Y 和 UV 平面的坐标关系、色度采样和插值方式;也可以先转换为 RGB 再 Remap。两种顺序都能实现,但必须定义颜色格式、像素中心和坐标精度,避免左右通路采用不同规则。
Map与AI模型参数的边界
以 LiteAnyStereo 为例,模型输入仍然只是两幅校正后的 RGB Tensor:
left_tensor [B,3,H,W]
right_tensor [B,3,H,W]
相关参数的使用位置如下:
| 数据 | 使用位置 | 是否进入LiteAnyStereo网络 |
|---|---|---|
| $K,D,R,T$ | 软件生成校正Map | 否 |
left_map/right_map | 模型前的LDC/Dewarp硬件 | 否 |
| 校正后左右RGB Tensor | NPU模型 | 是 |
| 校正后 $f_x$、基线 $B$ | 模型后将视差换成深度 | 否 |
| $Q$ 矩阵 | 模型后将视差重投影为点云 | 否 |
frame_id/timestamp/profile_id | 同步、结果绑定和配置管理 | 否 |
模型输出的是视差 $d$,米制深度由:
$$ Z=\frac{f_xB}{d} $$
得到。Map 解决的是“图像几何是否满足匹配假设”,$f_x$ 和 $B$ 解决的是“视差怎样变成物理距离”,两者不能混为一类模型输入。
怎样确认硬件能否完成双目校正
不能只问硬件是否“支持LDC”。有些 LDC 只能接受固定径向畸变系数或预设鱼眼模式,不一定能表达双目极线校正。需要确认硬件是否具备通用的二维重映射能力。
最关键的问题是:
LDC/Dewarp模块是否支持软件配置的任意二维反向Map或Mesh,对每个输出像素读取源图亚像素坐标并进行双线性插值,同时支持左右两路分别配置独立Map?
设计确认至少需要覆盖以下内容:
| 确认项 | 需要明确的内容 |
|---|---|
| Map能力 | 任意二维Map、可编程Mesh,还是仅固定畸变公式 |
| 坐标定义 | 输出到输入还是输入到输出;绝对坐标还是相对偏移 |
| 精度 | 坐标整数位、小数位、累积误差和插值精度 |
| 双路能力 | 左右通道能否加载不同Map,是否能并行或满足时分吞吐 |
| 图像格式 | NV12、NV21、RGB、位宽、Plane地址和Stride |
| 插值与边界 | 双线性/最近邻、填零/复制、有效ROI |
| 数据通路 | 能否在线接ISP和后续CSC/Normalize,还是必须DDR往返 |
| 配置切换 | Map地址、大小、版本能否在帧边界原子切换 |
功能验收可以直接检查硬件是否等价实现:
$$ I_{out}(x,y)=\operatorname{bilinear}\left(I_{in}, \operatorname{Map}_x(x,y),\operatorname{Map}_y(x,y)\right) $$
如果硬件只能处理一个相机、只能使用同一张 Map、只支持最近邻,或者不能满足两路目标分辨率与帧率,就不能直接认定它具备可用的双目校正能力。
如何判断校正是否正确
单目检查
- 棋盘格和建筑边缘等直线在去畸变后应保持笔直;
- 使用标定板检查重投影误差;
- 图像边缘不应出现异常拉伸、折叠或大量无效像素;
- Map对应的分辨率、Crop、旋转方向和Sensor模式必须与输入一致。
双目检查
- 在左右校正图中选取同一个棋盘格角点,纵坐标残差应接近零;
- 用水平线叠加显示左右图,物体特征应落在同一行;
- 检查全视场的纵向视差分布,而不只看图像中心;
- 左右图必须来自同一次曝光或满足同步误差要求;
- 左右 Map、图像角色和标定版本不能交换或错配;
- Resize、Crop、Pad 应使用共同的输出画布,并同步更新后处理使用的内参。
需要特别避免“重复校正”:如果 ISP 已经输出校正图,AI 前处理再套一次 Map 会重新扭曲图像。因此输入描述符应明确标记图像是否已校正,以及使用了哪个标定 Profile。
总结
图像几何映射表的本质,是把复杂的相机几何提前转换成一个简单、规则的逐像素采样问题:
输出像素
│
▼
查询Map得到原图坐标
│
▼
插值读取原图
│
▼
生成校正图
单目使用 Map 去除自身镜头畸变,双目使用左右两张 Map 在去畸变的同时完成极线对齐,多目系统使用多张 Map 投影到公共视角。通常由软件根据 $K,D,R,T$ 生成和管理 Map,由 LDC/Dewarp 硬件逐帧执行 Remap;AI 模型只接收最终校正后的 Tensor,不直接接收 Map 和标定参数。
评论