概述
相机标定是一种旨在通过确定相机的内参(焦距、光学中心、畸变系数)和外参(相机的位置和方向),进步图像在现实天下中的多少精度的过程。该过程可以改正相机拍摄的图像中的畸变,使相机可以或许正确感知现实天下中的间隔、角度和物体。一个很好的例子是改正鱼眼相机拍摄的图像。
一、什么是相机标定
相机通过将其投影到二维平面上来捕获现实天下。然而,由于光学元件和镜头的结构特性,这些图像可能会出现偏差。最常见的偏差是畸变和透视偏差。相机标定通过盘算相机的内参和外参来改正这些偏差,从而实现更正确的丈量和多少盘算。
关键参数
- 内参
- 焦距:根据镜头的焦距确定图像的巨细。
- 光学中心(主点):相机镜头的中心点。
- 畸变系数:用于改正镜头畸变,如桶形畸变和枕形畸变。(你可以在图 1 中清楚地看到这一点。)
注意:术语“畸变”指的是镜头引起的偏差,如变形或弯曲。
- 外参
- 相机位置:相机相对于天下的位置(x、y、z 坐标)。
- 相机方向:相机相对于天下的视角(旋转角度)。
二、怎样举行相机标定
通常利用已知的多少图案(如棋盘格)举行相机标定。该图案的已知尺寸和位置用作参考,以检测相机图像中的畸变。 标定过程包罗以下步调:
- 图像采集:要举行相机标定,你必要一组至少 15 张从差别角度拍摄的棋盘格图案的图像。该图案的角点有助于检测图像中的畸变。
- 角点检测:在每张图像中检测棋盘格图案的角点。精确检测这些角点对于正确标定至关告急。
- 内参和外参的盘算:根据相机图像中的角点与它们的真实天下坐标之间的差别,优化并盘算相机的内参和外参。通常利用 AI 算法或数学优化技能举行此盘算。
- 畸变改正:利用盘算出的参数改正图像中的畸变,去除非线性镜头畸变。
- 验证:为了测试标定的正确性,用相机拍摄一张新图像,并应用标定参数来改正图像。然后观察改正的正确性。
三、利用 OpenCV 在 Python 中举行相机标定
OpenCV 是 Python 中用于相机标定最常用的库之一。OpenCV 提供了相机标定和畸变改正所需的函数。以下是简单的标定示例:- import cv2
- import numpy as np
- import glob
- # 棋盘格的尺寸(内部角点的数量)
- grid_size = (9, 6)
- # 每个正方形的实际尺寸(2 厘米)
- square_size = 2 # 厘米
- # 棋盘格的 3D 世界坐标
- obj_points = np.zeros((grid_size[0] * grid_size[1], 3), np.float32)
- obj_points[:, :2] = np.mgrid[0:grid_size[0], 0:grid_size[1]].T.reshape(-1, 2) * square_size
- # 用于存储标定所需点的列表
- object_points = [] # 3D 世界坐标
- image_points = [] # 2D 图像坐标
- # 存放标定图像的文件夹
- images = glob.glob('calibration_images/*.jpg')
- for fname in images:
- img = cv2.imread(fname)
- gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
- # 查找棋盘格的角点
- ret, corners = cv2.findChessboardCorners(gray, grid_size, None)
- if ret:
- object_points.append(obj_points)
- image_points.append(corners)
- # 可视化角点
- cv2.drawChessboardCorners(img, grid_size, corners, ret)
- cv2.imshow('Chessboard Corners', img)
- cv2.waitKey(500)
- cv2.destroyAllWindows()
- # 执行标定
- ret, camera_matrix, dist_coeffs, rvecs, tvecs = cv2.calibrateCamera(
- object_points, image_points, gray.shape[::-1], None, None
- )
- # 保存相机矩阵和畸变系数
- np.savez('calibration_data.npz', camera_matrix=camera_matrix, dist_coeffs=dist_coeffs)
- # 打印标定结果
- print("Camera Matrix:\n", camera_matrix)
- print("Distortion Coefficients:\n", dist_coeffs)
复制代码 四、代码表明
- import cv2
- import numpy as np
- import glob
复制代码
- cv2(OpenCV):我们导入 OpenCV,这是一个用于图像处置惩罚的库。该库提供了许多用于相机标定和图像处置惩罚的函数。
- numpy(np):我们导入 NumPy,以便轻松举行数值运算和处置惩罚数组。
- glob:用于构造文件路径并列出文件夹中的文件。在这里,它用于获取包罗标定图像的文件夹中的全部图像。
- grid_size:指定棋盘格上内部角点的数量。在此示例中,棋盘格图案有 9 列和 6 行角点(9 列 × 6 行 = 54 个角点)。此值应与现实利用的棋盘格匹配。
- square_size:棋盘格上的每个正方形的现实边长设置为 2 厘米。
- obj_points = np.zeros((grid_size[0] * grid_size[1], 3), np.float32)
- 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]。
比方:- # 二维网格(网格)
- x, y = np.mgrid[0:3, 0:3]
- print("X:\n", x)
- print("Y:\n", y)
复制代码 输出:- X:
- [[0 0 0]
- [1 1 1]
- [2 2 2]]
- Y:
- [[0 1 2]
- [0 1 2]
- [0 1 2]]
复制代码
- T.reshape(-1, 2):将二维角点转换为单个矩阵。
- object_points = [] # 3D 世界坐标
- image_points = [] # 2D 图像坐标
复制代码
- object_points:一个列表,用于存储每张图像的 3D 真实天下棋盘格角点。
- image_points:一个列表,用于存储每张图像的 2D 图像角点。
- images = glob.glob('calibration_images/*.jpg')
复制代码
- images:查找 calibration_images 文件夹中的全部 .jpg 文件,并将它们存储在一个列表中。这些是用于标定的棋盘格图案图像。
- for fname in images:
- img = cv2.imread(fname)
- gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
复制代码
- 此循环处置惩罚每张图像:
- cv2.imread(fname):读取由 fname 指定的图像。
- cv2.cvtColor(img, cv2.COLOR_BGR2GRAY):将读取的图像从彩色(BGR)转换为灰度。在灰度图像上检测棋盘格图案更轻易。
- ret, corners = cv2.findChessboardCorners(gray, grid_size, None)
复制代码
- cv2.findChessboardCorners:实行在灰度图像中查找棋盘格的角点。
- ret:一个标志(True/False),指示是否乐成找到棋盘格的角点。
- corners:检测到的图像中角点的 2D 坐标。
- if ret:
- object_points.append(obj_points)
- image_points.append(corners)
复制代码
- 如果 ret 为 True,即乐成找到棋盘格的角点:
- object_points.append(obj_points):将 3D 真实天下坐标添加到列表中。
- image_points.append(corners):将 2D 图像坐标添加到列表中。
- cv2.drawChessboardCorners(img, grid_size, corners, ret)
- cv2.imshow('Chessboard Corners', img)
- cv2.waitKey(500)
复制代码
- cv2.drawChessboardCorners:通过在图像上绘制线条来可视化检测到的棋盘格角点。
- cv2.imshow:在一个新窗口中显示带有检测到的角点的图像。
- cv2.waitKey(500):显示图像 500 毫秒(0.5 秒)。
- cv2.destroyAllWindows:关闭全部打开的窗口。
- ret, camera_matrix, dist_coeffs, rvecs, tvecs = cv2.calibrateCamera(
- object_points, image_points, gray.shape[::-1], None, None
- )
复制代码
- 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 等选项一起利用。
- np.savez('calibration_data.npz', camera_matrix=camera_matrix, dist_coeffs=dist_coeffs)
复制代码
- np.savez:将盘算出的相机矩阵和畸变系数保存到名为 calibration_data.npz 的文件中。此文件允许你稍后重用标定参数。
- print("Camera Matrix:\n", camera_matrix)
- print("Distortion Coefficients:\n", dist_coeffs)
复制代码
- print:在屏幕上显示 camera_matrix(内参)和 dist_coeffs。
此代码利用 OpenCV 举行相机标定,并保存结果。相机标定对于改正图像中的畸变以及举行正确丈量至关告急。
五、标定结果中你将得到的值
在这一过程结束时,camera_matrix 和 dist_coeffs 将由函数盘算并返回:
camera_matrix
该矩阵包罗相机的内参(焦距、主点等)。它用于相识相机镜头的特性以及透视变动。它是一个 3×3 矩阵,可能如下所示:
在这里,f_x 和 f_y 是相机沿程度和垂直方向的焦距(以像素为单位),c_x 和 c_y 是图像平面上主点的像素坐标(通常是图像的中心)。
什么是主点? 主点体现图像的光学中心,并界说了相机镜头与图像平面之间的关系。如果相机的光轴偏离中心,这种偏移可以通过 c_x 和 c_y 坐标检测到。
示例:
假设你的相机分辨率为 1920×1080 像素,标定后你得到以下 camera_matrix:
- f_x = 1200 和 f_y = 1200:沿程度和垂直方向的焦距。
- c_x = 960 和 c_y = 540:主点的坐标,位于图像平面的中心(960 和 540 体现中心点,由于你的分辨率为 1920×1080)。
dist_coeffs
该向量包罗镜头的畸变系数。这些系数用于改正镜头的多少畸变(比方桶形畸变或枕形畸变)。
通常,该向量包罗以下系数:
这些系数:
- k_1、k_2、k_3:径向畸变系数。这些系数用于改正桶形或枕形畸变。如果图像中的畸变随着间隔中心的增长而变得更加显着,这就是径向畸变,k_1、k_2 和 k_3 用于改正这种畸变。k_1 改正靠近图像中心的畸变。k_2 改正向图像边沿的较大畸变。k_3 对远离中心的点(尤其是边沿)举行微调,特别是对于边沿处的畸变。
桶形畸变:一种向边沿膨胀的畸变。
枕形畸变:一种向边沿紧缩的畸变。
- p_1、p_2:切向畸变系数。当镜头与传感器未完美对齐时,会发生这种畸变。如果镜头未完美居中或存在轴向偏移,图像倾向于向边沿偏移。p_1 和 p_2 用于改正这种倾斜。p_1 改正沿 x 轴(程度平面)的偏移或畸变。p_2 改正沿 y 轴(垂直平面)的偏移或畸变。
什么是径向畸变和切向畸变?
径向畸变:这些畸变导致图像中的直线随着间隔中心的增长而弯曲。k_1、k_2 和 k_3 用于改正这些曲线。
切向畸变:当镜头与传感器不完全垂直时发生,导致图像向边沿偏移。p_1 和 p_2 用于改正这些偏移。
- k_4、k_5、k_6(可选):高阶径向畸变系数。这些参数用于改正更复杂的畸变,比方来自超广角镜头的畸变。它们通常不消于标准标定,但在必要更正确的校正时可以应用。
示例:- dist_coeffs = [0.1, -0.25, 0.001, 0.002, 0.03]
复制代码
- k_1 = 0.1 和 k_2 = -0.25:用于改正径向畸变的系数。
- p_1 = 0.001 和 p_2 = 0.002:用于改正切向畸变的系数。
- k_3 = 0.03:一个高阶径向畸变系数。
K 和 P 的值越大,校正结果越强。随着它们的减小,校正结果减弱。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
|