为什么需要畸变校正?
无人机通常使用广角甚至鱼眼镜头以获得更大的视野范围,这类镜头会导致图像产生严重的非线性几何失真,称为镜头畸变,畸变主要分为两种:

-
径向畸变:这是最主要的畸变类型,它沿着从图像中心到图像边缘的径向方向发生,它又分为:
- 枕形畸变:图像边缘的物体被“拉伸”远离中心,导致直线向内弯曲。
- 桶形畸变:图像边缘的物体被“压缩”推向中心,导致直线向外弯曲,这是无人机镜头最常见的畸变。
-
切向畸变:由于镜头与成像平面不平行(制造或安装误差)引起的,它使得图像的某些部分看起来被“剪切”或倾斜。
畸变的存在会影响后续所有基于图像的分析任务,
- 测绘与三维重建:导致生成的三维模型尺寸不准、变形。
- 目标检测与跟踪:目标的位置和形状发生偏移,影响精度。
- 图像拼接:接缝处难以对齐,出现错位或模糊。
- 距离测量:无法准确估算地面上物体的实际距离。
在大多数无人机应用中,畸变校正是必不可少的前置步骤。

畸变校正的核心思想
校正的基本思想是建立一个数学模型,描述一个无畸变的理想图像点 如何映射到一个有畸变的实际图像点,为了得到校正后的图像,我们需要进行逆运算:对于校正后图像中的每一个像素,我们找到它在原始畸变图像中对应的位置,并将该位置的像素值“搬运”过来,如果位置不是整数像素,就需要进行插值。
正向模型(畸变模型):
畸变图像点 = Distortion(Ideal Image Point)
校正过程(逆向映射):
校正图像点 = f(原始畸变图像)
对于校正图像中的每个点 (x_corrected, y_corrected),我们计算它在原始图像中的对应点 (x_distorted, y_distorted),然后进行采样。
核心数学公式与模型
1 相机内参矩阵
我们需要定义相机的内部参数,它描述了相机自身的光学特性,内参矩阵 K 是一个 3x3 的矩阵:

$$ K = \begin{bmatrix} f_x & s & c_x \ 0 & f_y & c_y \ 0 & 0 & 1 \end{bmatrix} $$
f_x,f_y:分别以像素为单位的x和y方向上的焦距,如果像素是正方形的,f_x和f_y应该相等。c_x,c_y:主点 坐标,即相机光轴与成像平面的交点,理论上应该是图像的中心,但实际中可能略有偏差。s:倾斜因子 或 歪斜系数,描述了成像平面坐标轴之间的非正交性,在现代大多数相机中,这个值接近于0。
为了方便计算,我们通常将图像坐标归一化到以主点为原点的坐标系中:
$$ \begin{bmatrix} x \ y \ \end{bmatrix}
\begin{bmatrix} \frac{u - c_x}{f_x} \ \frac{v - c_y}{f_y} \ \end{bmatrix} $$
(u, v) 是原始图像的像素坐标,(x, y) 是归一化坐标。
2 径向畸变模型
径向畸变只与点到图像中心的距离 r 有关。r 的计算公式为:
$$ r = \sqrt{x^2 + y^2} $$
畸变模型将归一化坐标 (x, y) 映射到一个新的坐标 (x_{radial}, y_{radial}):
$$ \begin{bmatrix} x{radial} \ y{radial} \ \end{bmatrix} = (1 + k_1 r^2 + k_2 r^4 + k_3 r^6) \begin{bmatrix} x \ y \ \end{bmatrix} $$
k1, k2, k3 是径向畸变系数。
- 对于桶形畸变,这些系数通常是负值。
- 对于枕形畸变,这些系数通常是正值。
k3通常用于描述高阶畸变,对于普通镜头,k1和k2已经足够。
3 切向畸变模型
切向畸变由两个系数 p1 和 p2 描述:
$$ \begin{bmatrix} x{tangential} \ y{tangential} \ \end{bmatrix} = \begin{bmatrix} x_{radial} + [2p_1xy + p2(r^2 + 2x^2)] \ y{radial} + [p_1(r^2 + 2y^2) + 2p_2xy] \ \end{bmatrix} $$
(x_radial, y_radial) 是经过径向畸变校正后的坐标。
4 完整的畸变模型
将径向和切向畸变结合起来,我们得到最终的畸变模型,它将理想坐标映射到畸变坐标:
$$ \begin{bmatrix} x{distorted} \ y{distorted} \ \end{bmatrix} = \begin{bmatrix} x{tangential} \ y{tangential} \ \end{bmatrix} $$
或者写成完整的公式:
$$ \begin{cases} x_{distorted} = x(1 + k_1 r^2 + k_2 r^4 + k_3 r^6) + [2p_1xy + p2(r^2 + 2x^2)] \ y{distorted} = y(1 + k_1 r^2 + k_2 r^4 + k_3 r^6) + [p_1(r^2 + 2y^2) + 2p_2xy] \end{cases} $$
这里的 (x_distorted, y_distorted) 仍然是归一化坐标,要转换回像素坐标,只需进行逆变换:
$$ \begin{bmatrix} u{distorted} \ v{distorted} \ \end{bmatrix}
\begin{bmatrix} fx x{distorted} + c_x \ fy y{distorted} + c_y \ \end{bmatrix} $$
校正过程(逆向映射)
现在我们有了从理想到畸变的公式,但我们需要的是反过来的过程,校正步骤如下:
- 遍历目标图像:对于校正后(目标)图像中的每一个像素点
(u_corr, v_corr)。 - 归一化坐标:将其转换为归一化坐标
(x_corr, y_corr)。 - 逆向求解:我们需要找到原始图像中的哪个点
(x_dist, y_dist)经过上述正向畸变模型后会变成(x_corr, y_corr),这个过程没有直接的解析解,通常使用数值方法(如牛顿迭代法)来近似求解,幸运的是,OpenCV等库已经封装好了这个复杂的求解过程。 - 正向畸变:将求解出的理想坐标
(x_dist, y_dist)代入正向畸变公式,计算出它在原始畸变图像中对应的像素坐标(u_dist, v_dist)。 - 边界检查:检查计算出的
(u_dist, v_dist)是否在原始图像的范围内,如果超出,则目标图像中的这个点设为黑色或忽略。 - 插值:由于
(u_dist, v_dist)几乎不可能是一个整数坐标,我们需要在原始图像中进行插值(如双线性插值、双三次插值)来获取该位置的像素值。 - 赋值:将插值得到的像素值赋给目标图像的
(u_corr, v_corr)位置。
如何获取校正参数?
上述所有公式中的参数——内参矩阵 K 和畸变系数 [k1, k2, p1, p2, k3]——都不是已知的,需要通过相机标定来获取。
标定流程:
- 打印一个标准的棋盘格标定板。
- 从不同角度、不同距离拍摄至少 10-20 张标定板的清晰照片。
- 使用 OpenCV 等库的
calibrateCamera()函数。 - 该函数会自动检测每张图片中的棋盘格角点,并根据这些已知的 3D 世界坐标和 2D 图像坐标,计算出相机的内参矩阵和畸变系数。
标定完成后,你将得到一个 .yaml 或 .xml 文件,里面包含了所有必要的参数,用于后续的图像校正。
OpenCV 中的实现代码示例
这是使用 Python 和 OpenCV 进行畸变校正的典型代码:
import cv2
import numpy as np
# 1. 加载原始畸变图像
distorted_image = cv2.imread('distorted_drone_image.jpg')
# 2. 加载相机标定参数 (假设已通过标定获得)
# 这些参数通常来自 cv2.calibrateCamera() 的结果
# mtx = 内参矩阵, dist = 畸变系数
mtx = np.array([[800.0, 0.0, 320.0],
[0.0, 800.0, 240.0],
[0.0, 0.0, 1.0]])
dist = np.array([[-0.2, 0.05, 0.001, 0.002, 0.0]]) # [k1, k2, p1, p2, k3]
# 3. 获取图像尺寸
h, w = distorted_image.shape[:2]
# 4. 计算新的相机矩阵和 ROI (可选,但推荐)
# 这个函数会优化相机矩阵,以去除图像边缘因校正产生的黑边
# alpha=1.0 表示保留所有有效像素,可能会裁剪图像
newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w, h), 1, (w, h))
# 5. 执行畸变校正
# 方法一: 使用 undistort (推荐,速度快)
undistorted_image = cv2.undistort(distorted_image, mtx, dist, None, newcameramtx)
# 方法二: 使用 remap (更灵活,可以自定义映射)
# mapx, mapy = cv2.initUndistortRectifyMap(mtx, dist, None, newcameramtx, (w, h), cv2.CV_32FC1)
# undistorted_image = cv2.remap(distorted_image, mapx, mapy, cv2.INTER_LINEAR)
# 6. 裁剪图像 (如果使用了 getOptimalNewCameraMatrix)
x, y, w_roi, h_roi = roi
undistorted_image_cropped = undistorted_image[y:y+h_roi, x:x+w_roi]
# 7. 显示和保存结果
cv2.imshow('Distorted', distorted_image)
cv2.imshow('Undistorted', undistorted_image_cropped)
cv2.imwrite('undistorted_drone_image.jpg', undistorted_image_cropped)
cv2.waitKey(0)
cv2.destroyAllWindows()
无人机镜头畸变校正的公式核心是径向畸变模型和切向畸变模型的组合,实际应用中,我们不需要手动实现复杂的逆向映射和插值,而是依赖像 OpenCV 这样的成熟库,关键在于通过相机标定获取准确的内参和畸变系数,然后使用 cv2.undistort() 或 cv2.remap() 函数高效地完成校正任务,这是无人机视觉处理中保证数据精度的基石。
标签: 无人机镜头畸变校正推导步骤 镜头畸变校正公式无人机应用实例 无人机镜头畸变校正公式推导原理