返回专辑
·Johan·3 分钟阅读

去畸变映射:别每帧重算

initUndistortRectifyMap 预计算 remap 表,remap 比每帧 undistort 快一个数量级;map 与 K、dist、分辨率绑定。

去畸变映射:别每帧重算

1. 每帧去畸变是隐形热点

一千零八十 p 三十帧的视觉流水线里,每帧调用一次完整去畸变可能占三到五毫秒,比换一版检测模型还贵。根因是畸变模型每个像素都要做非线性映射;标定内参和畸变系数与分辨率不变时,没有任何理由每帧重算。我见过团队在嵌入式上狂调检测输入尺寸,热点却在去畸变——剖面先于优化。去畸变不是标定文件的附属步骤,它是流水线的一级公民,和推理、后处理一样要占 stage 表的一行。

2. 预计算映射表,每帧只做重映射

初始化函数把映射表算一次;运行时重映射只是查表插值,复杂度从每像素解析变成内存带宽:

python
h, w = src.shape[:2]
newK, roi = cv2.getOptimalNewCameraMatrix(K, dist, (w, h), alpha=0.9)
map1, map2 = cv2.initUndistortRectifyMap(
    K, dist, None, newK, (w, h), cv2.CV_16SC2)
undist = cv2.remap(
    src, map1, map2, cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT)

最优新内参的 alpha 控制有效视场与黑边:alpha 为零返回最大内接矩形;alpha 为一保留全像素但黑边大。后续检测若在全图画框,黑边上常出假框——流水线里应裁到有效区域并同步更新主点坐标。这是几何契约,漏了会导致检测框偏移或位姿解算在错误内参下仍收敛。

3. 映射类型与插值取舍

十六位定点映射对比浮点映射省内存、更快,一般检测和特征流水线够用。亚像素测量链——标定角点细化、视觉计量——才考虑浮点映射。双线性插值通常够用;三次插值边缘略好但更慢。常数边界产生黑边;复制边界可能把边缘伪影引进角点响应。选型要在精度和帧率之间写进配置,不能口头约定。

4. 双目与稀疏分支

双目校正时初始化函数带上旋转和平移投影矩阵,一次生成校正后映射。后续立体匹配算法隐含极线约束——校正映射和单目去畸变映射是同一接口的不同参数组合。只有少量点要去畸变时,点级去畸变比整图重映射便宜;稠密流水线仍选映射表。图形处理器路径需上传映射表一次;重映射只读映射表,多线程共享安全,输出缓冲可复用减分配。

5. 失效条件与缓存

换分辨率、换镜头、改裁剪、改 alpha 必须重建映射表。启动时对内参、畸变、尺寸、alpha 做哈希与缓存比对;不匹配则阻断并告警,别静默用旧表。多节点共享同一标定文件时,映射表生成应集中做一次再广播,避免各节点重复算。我会把映射表哈希写进启动摘要,现场改 yaml 后一眼能看出是否触发重建。

6. 案例:alpha 与假框

某次 alpha 设为一保留全视场,黑边占一成五面积,检测在黑边上检出三个假框。改 alpha 为零点九并裁到有效区域、更新主点后,假框消失,帧率还涨——因为检测输入有效像素少了。映射参数是流水线契约的一部分,不是标定工程师的私货。后续位姿解算若仍用旧内参,会在局部看起来收敛、全局偏几厘米。

7. 与线程和录包

重映射只读映射表,捕获线程和推理线程各读同一表安全。录包复盘时要记录标定版本和映射哈希,否则无法判断某段 bag 是否用了过期映射。换镜头后若只更新内参文件未重建表,录包里的图像几何与标注会 silently 不一致。

8. 验收

  • 重映射与逐帧去畸变输出最大差应约插值误差级
  • 帧率前后对比加阶段毫秒表
  • 有效区域面积与检测假框率
  • 改标定后映射哈希触发重建日志
  • 裁剪后内参修正的往返测试

映射是空间换时间的标准取舍。标定契约不变时,每帧解析去畸变是纯浪费;剖面确认后再谈换模型。

← 全部文章

johan's blog