盘算机视觉——基于利用 OpenCV 与 Python 实现相机标定畸变校正

[复制链接]
发表于 2025-9-23 01:04:21 | 显示全部楼层 |阅读模式
概述

相机标定是一种旨在通过确定相机的内参(焦距、光学中心、畸变系数)和外参(相机的位置和方向),进步图像在现实天下中的多少精度的过程。该过程可以改正相机拍摄的图像中的畸变,使相机可以或许正确感知现实天下中的间隔、角度和物体。一个很好的例子是改正鱼眼相机拍摄的图像。
一、什么是相机标定

相机通过将其投影到二维平面上来捕获现实天下。然而,由于光学元件和镜头的结构特性,这些图像可能会出现偏差。最常见的偏差是畸变和透视偏差。相机标定通过盘算相机的内参和外参来改正这些偏差,从而实现更正确的丈量和多少盘算。
关键参数


  • 内参

    • 焦距:根据镜头的焦距确定图像的巨细。
    • 光学中心(主点):相机镜头的中心点。
    • 畸变系数:用于改正镜头畸变,如桶形畸变和枕形畸变。(你可以在图 1 中清楚地看到这一点。)
    注意:术语“畸变”指的是镜头引起的偏差,如变形或弯曲。


  • 外参

    • 相机位置:相机相对于天下的位置(x、y、z 坐标)。
    • 相机方向:相机相对于天下的视角(旋转角度)。


二、怎样举行相机标定

通常利用已知的多少图案(如棋盘格)举行相机标定。该图案的已知尺寸和位置用作参考,以检测相机图像中的畸变。 标定过程包罗以下步调:

  • 图像采集:要举行相机标定,你必要一组至少 15 张从差别角度拍摄的棋盘格图案的图像。该图案的角点有助于检测图像中的畸变。
  • 角点检测:在每张图像中检测棋盘格图案的角点。精确检测这些角点对于正确标定至关告急。
  • 内参和外参的盘算:根据相机图像中的角点与它们的真实天下坐标之间的差别,优化并盘算相机的内参和外参。通常利用 AI 算法或数学优化技能举行此盘算。
  • 畸变改正:利用盘算出的参数改正图像中的畸变,去除非线性镜头畸变。
  • 验证:为了测试标定的正确性,用相机拍摄一张新图像,并应用标定参数来改正图像。然后观察改正的正确性。


三、利用 OpenCV 在 Python 中举行相机标定

OpenCV 是 Python 中用于相机标定最常用的库之一。OpenCV 提供了相机标定和畸变改正所需的函数。以下是简单的标定示例:
  1. import cv2
  2. import numpy as np
  3. import glob
  4. # 棋盘格的尺寸(内部角点的数量)
  5. grid_size = (9, 6)
  6. # 每个正方形的实际尺寸(2 厘米)
  7. square_size = 2  # 厘米
  8. # 棋盘格的 3D 世界坐标
  9. obj_points = np.zeros((grid_size[0] * grid_size[1], 3), np.float32)
  10. obj_points[:, :2] = np.mgrid[0:grid_size[0], 0:grid_size[1]].T.reshape(-1, 2) * square_size
  11. # 用于存储标定所需点的列表
  12. object_points = []  # 3D 世界坐标
  13. image_points = []  # 2D 图像坐标
  14. # 存放标定图像的文件夹
  15. images = glob.glob('calibration_images/*.jpg')
  16. for fname in images:
  17.     img = cv2.imread(fname)
  18.     gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  19.     # 查找棋盘格的角点
  20.     ret, corners = cv2.findChessboardCorners(gray, grid_size, None)
  21.     if ret:
  22.         object_points.append(obj_points)
  23.         image_points.append(corners)
  24.         # 可视化角点
  25.         cv2.drawChessboardCorners(img, grid_size, corners, ret)
  26.         cv2.imshow('Chessboard Corners', img)
  27.         cv2.waitKey(500)
  28. cv2.destroyAllWindows()
  29. # 执行标定
  30. ret, camera_matrix, dist_coeffs, rvecs, tvecs = cv2.calibrateCamera(
  31.     object_points, image_points, gray.shape[::-1], None, None
  32. )
  33. # 保存相机矩阵和畸变系数
  34. np.savez('calibration_data.npz', camera_matrix=camera_matrix, dist_coeffs=dist_coeffs)
  35. # 打印标定结果
  36. print("Camera Matrix:\n", camera_matrix)
  37. print("Distortion Coefficients:\n", dist_coeffs)
复制代码
四、代码表明
  1. import cv2
  2. import numpy as np
  3. import glob
复制代码

  • cv2(OpenCV):我们导入 OpenCV,这是一个用于图像处置惩罚的库。该库提供了许多用于相机标定和图像处置惩罚的函数。
  • numpy(np):我们导入 NumPy,以便轻松举行数值运算和处置惩罚数组。
  • glob:用于构造文件路径并列出文件夹中的文件。在这里,它用于获取包罗标定图像的文件夹中的全部图像。
  1. grid_size = (9, 6)
复制代码

  • grid_size:指定棋盘格上内部角点的数量。在此示例中,棋盘格图案有 9 列和 6 行角点(9 列 × 6 行 = 54 个角点)。此值应与现实利用的棋盘格匹配。
  1. square_size = 2  # cm
复制代码

  • square_size:棋盘格上的每个正方形的现实边长设置为 2 厘米。
  1. obj_points = np.zeros((grid_size[0] * grid_size[1], 3), np.float32)
  2. obj_points[:, :2] = np.mgrid[0:grid_size[0], 0:grid_size[1]].T.reshape(-1, 2) * square_size
复制代码

  • obj_points:我们创建棋盘格角点在真实天下坐标中的 3D 位置。每个角点的 Z 轴值设置为 0。
  • np.zeros((grid_size[0] * grid_size[1], 3), np.float32):创建一个 3D 空矩阵,为每个角点包罗(x、y、z)坐标。
  • np.mgrid[0:grid_size[0], 0:grid_size[1]]:天生棋盘格上角点的(x、y)坐标。
注意:mgrid 是 NumPy 的一个函数,用于创建多维网格结构,其语法为 mgrid[start:end:step]。
比方:
  1. # 二维网格(网格)
  2. x, y = np.mgrid[0:3, 0:3]
  3. print("X:\n", x)
  4. print("Y:\n", y)
复制代码
输出:
  1. X:
  2. [[0 0 0]
  3.   [1 1 1]
  4.   [2 2 2]]
  5. Y:
  6. [[0 1 2]
  7.   [0 1 2]
  8.   [0 1 2]]
复制代码

  • T.reshape(-1, 2):将二维角点转换为单个矩阵。
  1. object_points = []  # 3D 世界坐标
  2. image_points = []  # 2D 图像坐标
复制代码

  • object_points:一个列表,用于存储每张图像的 3D 真实天下棋盘格角点。
  • image_points:一个列表,用于存储每张图像的 2D 图像角点。
  1. images = glob.glob('calibration_images/*.jpg')
复制代码

  • images:查找 calibration_images 文件夹中的全部 .jpg 文件,并将它们存储在一个列表中。这些是用于标定的棋盘格图案图像。
  1. for fname in images:
  2.     img = cv2.imread(fname)
  3.     gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
复制代码

  • 此循环处置惩罚每张图像:

    • cv2.imread(fname):读取由 fname 指定的图像。
    • cv2.cvtColor(img, cv2.COLOR_BGR2GRAY):将读取的图像从彩色(BGR)转换为灰度。在灰度图像上检测棋盘格图案更轻易。

  1. ret, corners = cv2.findChessboardCorners(gray, grid_size, None)
复制代码

  • cv2.findChessboardCorners:实行在灰度图像中查找棋盘格的角点。
  • ret:一个标志(True/False),指示是否乐成找到棋盘格的角点。
  • corners:检测到的图像中角点的 2D 坐标。
  1. if ret:
  2.     object_points.append(obj_points)
  3.     image_points.append(corners)
复制代码

  • 如果 ret 为 True,即乐成找到棋盘格的角点:

    • object_points.append(obj_points):将 3D 真实天下坐标添加到列表中。
    • image_points.append(corners):将 2D 图像坐标添加到列表中。

  1. cv2.drawChessboardCorners(img, grid_size, corners, ret)
  2. cv2.imshow('Chessboard Corners', img)
  3. cv2.waitKey(500)
复制代码

  • cv2.drawChessboardCorners:通过在图像上绘制线条来可视化检测到的棋盘格角点。
  • cv2.imshow:在一个新窗口中显示带有检测到的角点的图像。
  • cv2.waitKey(500):显示图像 500 毫秒(0.5 秒)。
  1. cv2.destroyAllWindows()
复制代码

  • cv2.destroyAllWindows:关闭全部打开的窗口。
  1. ret, camera_matrix, dist_coeffs, rvecs, tvecs = cv2.calibrateCamera(
  2.     object_points, image_points, gray.shape[::-1], None, None
  3. )
复制代码

  • camera_matrix:一个包罗相机内参(焦距、光学中心等)的矩阵。
  • dist_coeffs:镜头畸变系数。
  • rvecs:旋转向量。
  • tvecs:平移向量。
  • cv2.calibrateCamera:实行相机标定。该函数根据真实天下 3D 点与其在图像中的对应 2D 点之间的关系盘算相机参数。
  • object_points:3D 真实天下坐标。
  • image_points:图像中的 2D 投影坐标。
  • gray.shape[::-1]:图像分辨率(宽度和高度)。
  • camera_matrix(默认值:None)—— calibrateCamera 的参数:这是一个 3×3 矩阵,体现相机的内参(焦距、主点等)。如果提供为 None,这些参数将由函数盘算。如果你有一个已知的相机矩阵,你可以在这里提供它。
  • dist_coeffs(默认值:None)—— calibrateCamera 的参数:这是一个体现畸变系数(畸变)的向量。如果提供为 None,畸变系数将由函数盘算。
注意提供 **camera_matrix=None** **dist_coeffs=None** 的缘故原由是你渴望盘算这些参数并得到标定的结果。 在你的代码中,你试图从特定图像中推导出相机的内参和镜头畸变系数(camera_matrix 和 dist_coeffs)。

  • flags(可选):这些是用于在标定期间指定某些选项的标志。比方:

    • cv2.CALIB_USE_INTRINSIC_GUESS:启用内参(相机矩阵和畸变系数)的初始推测。
    • cv2.CALIB_FIX_PRINCIPAL_POINT:固定主点。
    • cv2.CALIB_FIX_ASPECT_RATIO:固定纵横比。

  • criteria(可选):指定迭代标准。这是优化过程的制止条件,通常与 cv2.TERM_CRITERIA_MAX_ITER 和 cv2.TERM_CRITERIA_EPS 等选项一起利用。
  1. np.savez('calibration_data.npz', camera_matrix=camera_matrix, dist_coeffs=dist_coeffs)
复制代码

  • np.savez:将盘算出的相机矩阵和畸变系数保存到名为 calibration_data.npz 的文件中。此文件允许你稍后重用标定参数。
  1. print("Camera Matrix:\n", camera_matrix)
  2. print("Distortion Coefficients:\n", dist_coeffs)
复制代码

  • print:在屏幕上显示 camera_matrix(内参)和 dist_coeffs
此代码利用 OpenCV 举行相机标定,并保存结果。相机标定对于改正图像中的畸变以及举行正确丈量至关告急。
五、标定结果中你将得到的值

在这一过程结束时,camera_matrix 和 dist_coeffs 将由函数盘算并返回:
camera_matrix

该矩阵包罗相机的内参(焦距、主点等)。它用于相识相机镜头的特性以及透视变动。它是一个 3×3 矩阵,可能如下所示:

在这里,f_xf_y 是相机沿程度和垂直方向的焦距(以像素为单位),c_xc_y 是图像平面上主点的像素坐标(通常是图像的中心)。
什么是主点? 主点体现图像的光学中心,并界说了相机镜头与图像平面之间的关系。如果相机的光轴偏离中心,这种偏移可以通过 c_xc_y 坐标检测到。
示例
假设你的相机分辨率为 1920×1080 像素,标定后你得到以下 camera_matrix:


  • f_x = 1200f_y = 1200:沿程度和垂直方向的焦距。
  • c_x = 960c_y = 540:主点的坐标,位于图像平面的中心(960 和 540 体现中心点,由于你的分辨率为 1920×1080)。
dist_coeffs

该向量包罗镜头的畸变系数。这些系数用于改正镜头的多少畸变(比方桶形畸变或枕形畸变)。
通常,该向量包罗以下系数:

这些系数:

  • k_1、k_2、k_3:径向畸变系数。这些系数用于改正桶形或枕形畸变。如果图像中的畸变随着间隔中心的增长而变得更加显着,这就是径向畸变,k_1k_2k_3 用于改正这种畸变。k_1 改正靠近图像中心的畸变。k_2 改正向图像边沿的较大畸变。k_3 对远离中心的点(尤其是边沿)举行微调,特别是对于边沿处的畸变。
    桶形畸变:一种向边沿膨胀的畸变。
    枕形畸变:一种向边沿紧缩的畸变。
  • p_1、p_2:切向畸变系数。当镜头与传感器未完美对齐时,会发生这种畸变。如果镜头未完美居中或存在轴向偏移,图像倾向于向边沿偏移。p_1p_2 用于改正这种倾斜。p_1 改正沿 x 轴(程度平面)的偏移或畸变。p_2 改正沿 y 轴(垂直平面)的偏移或畸变。
    什么是径向畸变和切向畸变?
    径向畸变:这些畸变导致图像中的直线随着间隔中心的增长而弯曲。k_1k_2k_3 用于改正这些曲线。
    切向畸变:当镜头与传感器不完全垂直时发生,导致图像向边沿偏移。p_1p_2 用于改正这些偏移。
  • k_4、k_5、k_6(可选):高阶径向畸变系数。这些参数用于改正更复杂的畸变,比方来自超广角镜头的畸变。它们通常不消于标准标定,但在必要更正确的校正时可以应用。
示例:
  1. dist_coeffs = [0.1, -0.25, 0.001, 0.002, 0.03]
复制代码

  • k_1 = 0.1k_2 = -0.25:用于改正径向畸变的系数。
  • p_1 = 0.001p_2 = 0.002:用于改正切向畸变的系数。
  • k_3 = 0.03:一个高阶径向畸变系数。
KP 的值越大,校正结果越强。随着它们的减小,校正结果减弱。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
继续阅读请点击广告

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
回复

使用道具 举报

×
登录参与点评抽奖,加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表