4. 切向畸变原理
聊完径向畸变,咱们来看看另一种常见的镜头问题——切向畸变。
说白了,径向畸变是镜头“本身”的光学缺陷。而切向畸变,问题出在装配上。
你想想看,镜头模组在生产时,透镜的光轴和传感器平面,理论上应该完美垂直。但实际制造和组装总有公差。一旦透镜和传感器不平行,哪怕只有一点点角度偏差,光线穿过透镜后,在传感器上的成像位置就会发生偏移。这种偏移,就是切向畸变。
4.1 切向畸变的数学模型
切向畸变的数学模型,比径向畸变稍微复杂一点。它有两个参数:p1 和 p2。
校正公式如下:
x_corrected = x + [2 * p1 * x * y + p2 * (r² + 2 * x²)]
y_corrected = y + [p1 * (r² + 2 * y²) + 2 * p2 * x * y]
其中:
(x, y)是归一化平面上的畸变点坐标(x_corrected, y_corrected)是校正后的坐标r² = x² + y²p1, p2是切向畸变系数
这个公式看起来有点绕,但核心思想很简单:畸变偏移量不仅和像素位置有关,还和 x、y 的乘积有关。这意味着,图像角落的畸变,会比中心区域更明显。
关键点:切向畸变在图像边缘的四个角上,表现最突出。中心区域几乎不受影响。
4.2 切向畸变 vs 径向畸变
我经常被问到:这两种畸变怎么区分?
嗯,看图像特征就行。
| 畸变类型 | 根本原因 | 图像表现 | 校正参数 |
|---|---|---|---|
| 径向畸变 | 镜头透镜曲率缺陷 | 直线变曲线(桶形/枕形) | k1, k2, k3 |
| 切向畸变 | 透镜与传感器不平行 | 直线倾斜、梯形失真 | p1, p2 |
举个例子。你拍一张棋盘格照片。如果棋盘格边缘的直线变成了弧线,那是径向畸变。如果棋盘格整体看起来像被“拉扯”了一下,一边宽一边窄,或者格子变成了平行四边形,那多半是切向畸变。
我的经验:实际项目中,切向畸变通常比径向畸变小一个数量级。但千万别忽略它。在需要高精度测量的场景(比如工业视觉、三维重建),切向畸变校正不到位,误差会累积到最终结果里。
4.3 切向畸变校正流程
校正切向畸变,通常和径向畸变一起做。OpenCV 的 cv2.calibrateCamera() 函数会同时输出径向和切向系数。
具体步骤:
- 拍摄标定板:多角度拍摄棋盘格或圆点网格。
- 提取角点:找到标定板上的特征点坐标。
- 计算参数:用
calibrateCamera()得到内参矩阵和畸变系数(包括k1, k2, p1, p2)。 - 生成映射表:用
initUndistortRectifyMap()生成校正映射。 - 应用校正:用
remap()对每一帧图像进行重映射。
代码示例:
import cv2
import numpy as np
# 假设你已经通过标定得到了以下参数
camera_matrix = np.array([[fx, 0, cx],
[0, fy, cy],
[0, 0, 1]], dtype=np.float32)
dist_coeffs = np.array([k1, k2, p1, p2, k3], dtype=np.float32)
# 生成校正映射
h, w = image.shape[:2]
mapx, mapy = cv2.initUndistortRectifyMap(camera_matrix, dist_coeffs,
None, camera_matrix,
(w, h), cv2.CV_32FC1)
# 应用校正
undistorted_img = cv2.remap(image, mapx, mapy, cv2.INTER_LINEAR)
避坑指南:我曾经在一个项目中,只标定了径向畸变,忽略了切向畸变。结果在图像边缘的测量误差达到了 3 个像素。后来加上 p1, p2 重新标定,误差降到了 0.5 像素以内。所以,永远不要只标定径向畸变,除非你的应用对精度完全没要求。
4.4 切向畸变的影响与应对
切向畸变对视觉任务的影响,主要体现在:
- 测量误差:在图像边缘,物体的实际位置和测量位置有偏差。
- 拼接错位:多张图像拼接时,边缘的畸变会导致接缝处不连续。
- 三维重建失真:从二维图像恢复三维结构时,畸变会引入系统性误差。
怎么应对?
- 标定要全面:标定板覆盖整个视野,尤其是边缘区域。
- 参数要完整:畸变系数至少包含
k1, k2, p1, p2。 - 验证要严格:校正后,用标定板重新测量,检查残差。
一句话总结:切向畸变是装配误差的体现。虽然量级小,但影响不可忽视。标定时带上 p1, p2,校正时一步到位,省得后面返工。