图像几何映射表:从单目去畸变到双目极线校正

图像几何映射表(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

软件侧通常负责:

  1. 读取工厂标定得到的 $K,D,R,T$;
  2. 根据目标分辨率、裁剪和投影方式生成 Map;
  3. 为 Map 分配设备可访问的内存;
  4. 维护 calibration_profile_id 和版本;
  5. 在分辨率、Sensor模式或标定版本改变时切换 Map;
  6. 同时保存校正后的内参、$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 TensorNPU模型
校正后 $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 和标定参数。

评论