1. 课程导论与畸变校正基础
各位同学好,我是你们这门课的主讲。在嵌入式视觉领域摸爬滚打了十几年,我见过太多「算法跑得通,产品装不上」的尴尬局面。今天咱们要聊的畸变校正,就是这类问题的典型代表——看似简单,但一上嵌入式平台就各种翻车。
先问大家一个问题:你拍出来的照片,真的是「真实世界」的还原吗?
答案是否定的。镜头本身就有物理缺陷,拍出来的图像天生就是「变形」的。咱们这门课,就是要教会你怎么把这些变形的图像掰直,并且高效地部署到嵌入式设备上。
什么是镜头畸变?
说白了,镜头畸变就是光线穿过透镜时,因为透镜的物理形状和装配误差,导致成像位置发生了偏移。你想想看,一个凸透镜,边缘和中心对光线的折射能力是不一样的,这就必然带来变形。
我早年做安防摄像头项目时,第一次拿到广角镜头的测试图像,差点以为相机坏了——画面边缘的直线全是弯的。后来才明白,这不是故障,是物理规律。
畸变主要分两类:
- 径向畸变:光线在透镜边缘弯曲得更厉害,导致图像从中心向外「膨胀」或「收缩」。拍出来的直线变成向外凸的曲线(桶形畸变),或者向内凹的曲线(枕形畸变)。
- 切向畸变:透镜和成像平面不平行,有夹角。这通常是因为镜头模组装配时没装正,导致图像像被「拧」了一下。
核心认知: 径向畸变是「形状」问题,切向畸变是「角度」问题。实际项目中,径向畸变占主导,切向畸变通常小一个数量级。但如果你做高精度测量,切向畸变也不能忽略。
相机模型与内参矩阵
要校正畸变,得先搞清楚相机是怎么成像的。这里有个经典模型——针孔相机模型。
想象一个暗箱,前面戳个小孔,光线穿过小孔在后面的感光元件上成像。这就是最原始的相机。实际镜头虽然复杂,但数学上可以用这个模型近似。
从三维世界到二维图像,经历了四次坐标变换:
- 世界坐标系 → 相机坐标系(刚体变换,旋转+平移)
- 相机坐标系 → 图像物理坐标系(透视投影)
- 图像物理坐标系 → 图像像素坐标系(离散化采样)
把这些变换写成矩阵形式,就是大名鼎鼎的内参矩阵 K:
K = [ fx 0 cx
0 fy cy
0 0 1 ]
其中:
fx、fy:焦距在 x、y 方向上的像素尺度cx、cy:光心在像素坐标系中的位置(通常接近图像中心)
我的经验: 内参矩阵是相机的「身份证」。同一款镜头,不同个体之间都有细微差异。量产项目中,我建议每台设备单独标定,至少也要抽检标定。曾经有个客户图省事,所有摄像头用同一组内参,结果校正后的拼接图像错位了 3 个像素——这在安防监控里是致命的。
校正的数学原理
畸变校正的核心思路很简单:建立「理想像素」到「实际像素」的映射关系,然后反向查表。
数学上,我们用多项式模型来描述这种映射。以径向畸变为例,最常用的是 Brown-Conrady 模型:
x_distorted = x_ideal * (1 + k1*r^2 + k2*r^4 + k3*r^6)
y_distorted = y_ideal * (1 + k1*r^2 + k2*r^4 + k3*r^6)
其中:
(x_ideal, y_ideal):理想的无畸变坐标(归一化平面)(x_distorted, y_distorted):实际带畸变的坐标r^2 = x_ideal^2 + y_ideal^2:像素到光心的距离平方k1, k2, k3:径向畸变系数
切向畸变则用另外两个参数 p1, p2 来描述:
x_distorted = x_ideal + [2*p1*x_ideal*y_ideal + p2*(r^2 + 2*x_ideal^2)]
y_distorted = y_ideal + [p1*(r^2 + 2*y_ideal^2) + 2*p2*x_ideal*y_ideal]
注意: 实际校正时,我们做的是「反向映射」——遍历目标图像的每个像素,去原图中找它应该取哪个位置的颜色值。如果正向映射,目标图像会出现空洞和重叠,效果惨不忍睹。我曾经见过新手直接套正向公式,结果校正出来的图像像马赛克拼图。
整个校正流程可以概括为:
- 标定:用棋盘格或圆点标定板,通过多张不同角度的照片解算出内参和畸变系数
- 生成映射表:根据内参和畸变系数,计算每个目标像素对应的原图坐标
- 重采样:用双线性插值或最近邻插值,从原图中取出像素值填入目标图像
下面这张图展示了整个知识体系的结构:
从这张图可以看得很清楚:畸变校正不是孤立的算法,它从物理来源出发,经过数学模型,最终落到工程实现和嵌入式优化。咱们这门课,就是沿着这条路径一步步深入。
最后说个我踩过的坑。早期做车载环视系统时,我直接在 CPU 上用浮点运算做校正,结果 720p 图像只能跑 8fps。后来改成预生成映射表 + 定点化 + NEON 指令优化,直接飙到 30fps。这告诉我们:数学原理是基础,但工程实现才是产品落地的关键。