OpenCV-鱼眼相机图像处理
鱼眼相机图像处理完整指南
1. 概述
鱼眼镜头由于其超广视角(通常可达180度甚至更大),在计算机视觉应用中非常有用,但同时也会引入严重的径向畸变。畸变矫正的目标是将鱼眼图像转换为符合针孔相机模型的图像,消除畸变影响,使图像更适合后续的计算机视觉处理任务。
2. 鱼眼镜头畸变特性
2.1 Kannala-Brandt 模型
鱼眼镜头使用Kannala-Brandt模型来描述畸变,其数学表达式为:
θ_d = θ (1 + k1 θ² + k2 θ⁴ + k3 θ⁶ + k4 θ⁸)
其中 θ
为入射角,θ_d
为畸变后的角度,k1-k4
为径向畸变系数。
鱼眼镜头产生的畸变主要为径向畸变,表现为图像边缘的强烈弯曲。在鱼眼图像中:
- 图像中心区域畸变较小
- 越靠近边缘畸变越严重
- 直线在图像边缘区域会变成曲线
我们可以把鱼眼镜头想象成一个球面,光线从场景中射入后在球面上形成图像,然后再投影到平面图像传感器上。这种投影方式导致了强烈的径向畸变。
3. 关键函数详解
3.1 cv2.fisheye.calibrate
用于鱼眼相机单目标定,计算相机内参和畸变系数。
参数说明:
objectPoints
:世界坐标系中的角点坐标(Nx3数组)imagePoints
:图像坐标系中的角点坐标(Nx2数组)imageSize
:图像尺寸(宽,高)K
:输出的相机内参矩阵(3x3)D
:输出的畸变系数(1x4)rvecs
:输出的旋转向量tvecs
:输出的平移向量flags
:标定标志
3.2 cv2.fisheye.stereoCalibrate
用于鱼眼相机双目标定,计算两个相机之间的外参和立体校正参数。
参数说明:
objectPoints
:世界坐标系中的角点坐标(Nx3数组)imagePoints1
:左图像坐标系中的角点坐标(Nx2数组)imagePoints2
:右图像坐标系中的角点坐标(Nx2数组)K1
:左相机内参矩阵(3x3)D1
:左相机畸变系数(1x4)K2
:右相机内参矩阵(3x3)D2
:右相机畸变系数(1x4)imageSize
:图像尺寸(宽,高)R
:输出的旋转矩阵(3x3)T
:输出的平移向量(3x1)flags
:标定标志
3.3 cv2.fisheye.estimateNewCameraMatrixForUndistortRectify
计算去畸变后的新相机内参矩阵。
参数说明:
K
:原始相机内参矩阵(3x3)D
:畸变系数(1x4)imageSize
:图像尺寸(宽,高)R
:校正变换矩阵(通常为单位矩阵)balance
:平衡参数(0.0~1.0),控制裁剪与保留的平衡- 0.0:最大程度裁剪,视野最小
- 1.0:保留完整视野,但可能有黑边
newSize
:输出图像尺寸(可选)fovScale
:视野缩放因子(可选)
3.4 cv2.fisheye.initUndistortRectifyMap
生成去畸变映射表,用于后续图像去畸变。
参数说明:
K
:原始相机内参矩阵(3x3)D
:畸变系数(1x4)R
:校正变换矩阵(通常为单位矩阵)P
:新的相机内参矩阵size
:输出图像尺寸(宽,高)m1type
:映射表的数据类型(如cv2.CV_32FC1)
输出:
map1
:x方向映射表map2
:y方向映射表
3.5 cv2.remap
根据映射表对图像进行去畸变处理。
参数说明:
src
:输入图像map1
:x方向映射表map2
:y方向映射表interpolation
:插值方法(如cv2.INTER_LINEAR)borderMode
:边界处理方式
3.6 cv2.fisheye.undistortImage
直接对鱼眼图像进行去畸变处理。
参数说明:
src
:输入的鱼眼畸变图像K
:输入相机的内参矩阵(3x3)D
:输入相机的畸变系数(1x4)Knew
:输出相机的内参矩阵,如果为None则使用Knew_size
:输出图像的尺寸(宽,高)
3.7 cv2.fisheye.stereoRectify
计算立体矫正变换。
参数说明:
K1
:左相机内参矩阵(3x3)D1
:左相机畸变系数(1x4)K2
:右相机内参矩阵(3x3)D2
:右相机畸变系数(1x4)imageSize
:图像尺寸(宽,高)R
:左右相机之间的旋转矩阵tvec
:左右相机之间的平移向量flags
:矫正标志R1
:输出的左相机矫正旋转矩阵R2
:输出的右相机矫正旋转矩阵P1
:输出的左相机矫正投影矩阵P2
:输出的右相机矫正投影矩阵Q
:输出的重投影矩阵
3.8 cv2.fisheye.projectPoints
将3D点投影到鱼眼相机图像平面上。
参数说明:
objectPoints
:3D点坐标(Nx3数组)rvec
:旋转向量tvec
:平移向量K
:相机内参矩阵D
:畸变系数imagePoints
:输出的图像点坐标alpha
:可选参数
3.9 cv2.fisheye.undistortPoints
对鱼眼图像的点坐标进行去畸变处理,将畸变图像中的点映射到去畸变图像坐标系。
参数说明:
distorted
:输入的畸变点集,格式应为(N, 1, 2)K
:使用标定得到的原始相机内参矩阵D
:仅使用前4个径向畸变系数(k1, k2, k3, k4)R
:旋转矩阵(可选,默认为单位矩阵)P
:新内参矩阵,定义输出点坐标系(可选,默认为K)
优势:
- 精度更高:直接使用数学模型进行点的去畸变,避免了映射表插值带来的误差
- 更加灵活:不依赖于预计算的映射表,可以直接对任意点坐标进行去畸变处理
- 参数控制更精确:可以直接指定输出点坐标系的内参矩阵(P参数)
3.10 cv2.fisheye.distortPoints
对点坐标进行畸变处理,将无畸变点坐标转换为畸变点坐标。
参数说明:
undistorted
:输入的无畸变点集,格式应为(N, 1, 2)K
:相机内参矩阵D
:畸变系数(1x4)R
:旋转矩阵(可选)
4. 鱼眼图像去畸变处理流程
鱼眼图像去畸变的标准处理流程如下:
4.1 基于映射表的去畸变方法
def fisheye_undistort(image_path, K, D, balance=0.7, output_size=None, visualize=True):
"""
鱼眼图像去畸变完整流程
:param image_path: 输入图像路径
:param K: 内参矩阵
:param D: 畸变系数
:param balance: 裁剪系数 (0-1)
:param output_size: 输出图像尺寸 (宽, 高)
:param visualize: 是否显示结果
"""
# 步骤1: 读取图像
distorted_img = cv2.imread(image_path)
# 步骤2: 计算新内参new_K
new_K = cv2.fisheye.estimateNewCameraMatrixForUndistortRectify(
K, D, distorted_img.shape[:2][::-1], np.eye(3), balance=balance
)
# 步骤3: 生成去畸变映射
map1, map2 = cv2.fisheye.initUndistortRectifyMap(
K, D, np.eye(3), new_K, distorted_img.shape[:2][::-1], cv2.CV_32FC1
)
# 步骤4: 应用映射去畸变
undistorted = cv2.remap(
distorted_img, map1, map2, interpolation=cv2.INTER_LINEAR,
borderMode=cv2.BORDER_CONSTANT, borderValue=(0, 0, 0)
)
# 步骤5: 可视化结果
if visualize:
cv2.imshow("Original", distorted_img)
cv2.imshow("Undistorted", undistorted)
cv2.waitKey(0)
cv2.destroyAllWindows()
return undistorted, new_K
4.2 直接去畸变方法
def fisheye_undistort_direct(image_path, K, D, balance=0.7):
"""
使用cv2.fisheye.undistortImage直接去畸变
:param image_path: 输入图像路径
:param K: 内参矩阵
:param D: 畸变系数
:param balance: 裁剪系数 (0-1)
"""
# 读取图像
distorted_img = cv2.imread(image_path)
# 计算新内参矩阵
new_K = cv2.fisheye.estimateNewCameraMatrixForUndistortRectify(
K, D, distorted_img.shape[:2][::-1], np.eye(3), balance=balance
)
# 直接去畸变
undistorted = cv2.fisheye.undistortImage(
distorted_img, K, D, new_K, distorted_img.shape[:2][::-1]
)
return undistorted, new_K
4.3. 点坐标去畸变处理
对于需要高精度处理的点坐标,推荐使用cv2.fisheye.undistortPoints
:
def undistort_points_example(distorted_points, K, D, new_K):
"""
使用fisheye.undistortPoints对点进行去畸变处理
参数:
distorted_points: 畸变点坐标列表 [[x1, y1], [x2, y2], ...]
K: 相机内参矩阵
D: 畸变系数
new_K: 新的相机内参矩阵
返回:
undistorted_points: 去畸变后的点坐标
"""
# 将点转换为正确的格式 (N, 1, 2)
points = np.array(distorted_points, dtype=np.float32).reshape(-1, 1, 2)
# 使用fisheye.undistortPoints进行去畸变
undistorted_points = cv2.fisheye.undistortPoints(points, K, D, P=new_K)
# 返回去畸变后的点坐标
return undistorted_points.reshape(-1, 2)
5. 畸变系数说明
对于鱼眼相机,OpenCV使用4个径向畸变系数:
k1
:第一个径向畸变系数k2
:第二个径向畸变系数k3
:第三个径向畸变系数k4
:第四个径向畸变系数
即使标定工具输出了更多系数,也只应使用前4个。
6. 最佳实践
6.1 参数配置
- 确保相机内参矩阵为3x3格式
- 畸变系数使用前4个径向畸变系数
- 合理设置balance参数以平衡视野和图像质量
6.2 处理流程
- 首先进行相机标定获取准确的内参和畸变系数
- 使用
cv2.fisheye.estimateNewCameraMatrixForUndistortRectify
计算新相机矩阵 - 生成映射表
cv2.fisheye.initUndistortRectifyMap
- 应用映射进行去畸变
cv2.remap
6.3 点坐标去畸变
- 对于需要高精度处理的点坐标,推荐使用
cv2.fisheye.undistortPoints
- 确保输入点格式为(N, 1, 2)
- 正确传递相机内参矩阵和畸变系数
- 可选地指定输出坐标系的内参矩阵
6.4 注意事项
- 去畸变后的图像可能有黑边,需要根据应用需求处理
- balance参数影响视野保留程度,需要根据具体场景调整
- 确保畸变系数只使用前4个,即使标定结果提供了更多系数
- 使用
cv2.fisheye.undistortPoints
比基于映射表的方法精度更高