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则使用K
  • new_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 处理流程

  1. 首先进行相机标定获取准确的内参和畸变系数
  2. 使用cv2.fisheye.estimateNewCameraMatrixForUndistortRectify计算新相机矩阵
  3. 生成映射表cv2.fisheye.initUndistortRectifyMap
  4. 应用映射进行去畸变cv2.remap

6.3 点坐标去畸变

  1. 对于需要高精度处理的点坐标,推荐使用cv2.fisheye.undistortPoints
  2. 确保输入点格式为(N, 1, 2)
  3. 正确传递相机内参矩阵和畸变系数
  4. 可选地指定输出坐标系的内参矩阵

6.4 注意事项

  • 去畸变后的图像可能有黑边,需要根据应用需求处理
  • balance参数影响视野保留程度,需要根据具体场景调整
  • 确保畸变系数只使用前4个,即使标定结果提供了更多系数
  • 使用cv2.fisheye.undistortPoints比基于映射表的方法精度更高
posted @ 2025-08-11 19:03  aaooli  阅读(113)  评论(0)    收藏  举报