如何使用OpenCV和Python进行相机校准

《------往期经典推荐------》

一、AI应用软件开发实战专栏【链接】

项目名称 项目名称
1.【人脸识别与管理系统开发 2.【车牌识别与自动收费管理系统开发
3.【手势识别系统开发 4.【人脸面部活体检测系统开发
5.【图片风格快速迁移软件开发 6.【人脸表表情识别系统
7.【YOLOv8多目标识别与自动标注软件开发 8.【基于YOLOv8深度学习的行人跌倒检测系统
9.【基于YOLOv8深度学习的PCB板缺陷检测系统 10.【基于YOLOv8深度学习的生活垃圾分类目标检测系统
11.【基于YOLOv8深度学习的安全帽目标检测系统 12.【基于YOLOv8深度学习的120种犬类检测与识别系统
13.【基于YOLOv8深度学习的路面坑洞检测系统 14.【基于YOLOv8深度学习的火焰烟雾检测系统
15.【基于YOLOv8深度学习的钢材表面缺陷检测系统 16.【基于YOLOv8深度学习的舰船目标分类检测系统
17.【基于YOLOv8深度学习的西红柿成熟度检测系统 18.【基于YOLOv8深度学习的血细胞检测与计数系统
19.【基于YOLOv8深度学习的吸烟/抽烟行为检测系统 20.【基于YOLOv8深度学习的水稻害虫检测与识别系统
21.【基于YOLOv8深度学习的高精度车辆行人检测与计数系统 22.【基于YOLOv8深度学习的路面标志线检测与识别系统
23.【基于YOLOv8深度学习的智能小麦害虫检测识别系统 24.【基于YOLOv8深度学习的智能玉米害虫检测识别系统
25.【基于YOLOv8深度学习的200种鸟类智能检测与识别系统 26.【基于YOLOv8深度学习的45种交通标志智能检测与识别系统
27.【基于YOLOv8深度学习的人脸面部表情识别系统 28.【基于YOLOv8深度学习的苹果叶片病害智能诊断系统
29.【基于YOLOv8深度学习的智能肺炎诊断系统 30.【基于YOLOv8深度学习的葡萄簇目标检测系统
31.【基于YOLOv8深度学习的100种中草药智能识别系统 32.【基于YOLOv8深度学习的102种花卉智能识别系统
33.【基于YOLOv8深度学习的100种蝴蝶智能识别系统 34.【基于YOLOv8深度学习的水稻叶片病害智能诊断系统
35.【基于YOLOv8与ByteTrack的车辆行人多目标检测与追踪系统 36.【基于YOLOv8深度学习的智能草莓病害检测与分割系统
37.【基于YOLOv8深度学习的复杂场景下船舶目标检测系统 38.【基于YOLOv8深度学习的农作物幼苗与杂草检测系统
39.【基于YOLOv8深度学习的智能道路裂缝检测与分析系统 40.【基于YOLOv8深度学习的葡萄病害智能诊断与防治系统
41.【基于YOLOv8深度学习的遥感地理空间物体检测系统 42.【基于YOLOv8深度学习的无人机视角地面物体检测系统
43.【基于YOLOv8深度学习的木薯病害智能诊断与防治系统 44.【基于YOLOv8深度学习的野外火焰烟雾检测系统
45.【基于YOLOv8深度学习的脑肿瘤智能检测系统 46.【基于YOLOv8深度学习的玉米叶片病害智能诊断与防治系统
47.【基于YOLOv8深度学习的橙子病害智能诊断与防治系统 48.【基于深度学习的车辆检测追踪与流量计数系统
49.【基于深度学习的行人检测追踪与双向流量计数系统 50.【基于深度学习的反光衣检测与预警系统
51.【基于深度学习的危险区域人员闯入检测与报警系统 52.【基于深度学习的高密度人脸智能检测与统计系统
53.【基于深度学习的CT扫描图像肾结石智能检测系统 54.【基于深度学习的水果智能检测系统
55.【基于深度学习的水果质量好坏智能检测系统 56.【基于深度学习的蔬菜目标检测与识别系统
57.【基于深度学习的非机动车驾驶员头盔检测系统 58.【太基于深度学习的阳能电池板检测与分析系统
59.【基于深度学习的工业螺栓螺母检测 60.【基于深度学习的金属焊缝缺陷检测系统
61.【基于深度学习的链条缺陷检测与识别系统 62.【基于深度学习的交通信号灯检测识别
63.【基于深度学习的草莓成熟度检测与识别系统 64.【基于深度学习的水下海生物检测识别系统
65.【基于深度学习的道路交通事故检测识别系统 66.【基于深度学习的安检X光危险品检测与识别系统
67.【基于深度学习的农作物类别检测与识别系统 68.【基于深度学习的危险驾驶行为检测识别系统
69.【基于深度学习的维修工具检测识别系统 70.【基于深度学习的维修工具检测识别系统
71.【基于深度学习的建筑墙面损伤检测系统 72.【基于深度学习的煤矿传送带异物检测系统
73.【基于深度学习的老鼠智能检测系统

二、机器学习实战专栏【链接】 ,已更新31期,欢迎关注,持续更新中~~
三、深度学习【Pytorch】专栏【链接】
四、【Stable Diffusion绘画系列】专栏【链接】
五、YOLOv8改进专栏【链接】持续更新中~~
六、YOLO性能对比专栏【链接】,持续更新中~

《------正文------》

目录

引言

摄像机标定是通过确定摄像机的内参数(焦距、光学中心、畸变系数)和外参数(摄像机位置和方向)来提高图像在真实的世界中的几何精度的过程。该过程校正相机捕获的图像中的失真,从而允许相机准确地感知真实的世界中的距离、角度和对象。一个很好的例子是校正鱼眼相机拍摄的图像。

什么是相机校准?

照相机通过将真实的世界投影到二维平面上来捕捉它。然而,由于光学元件和透镜的结构特性,这些图像中可能会出现误差。最常见的错误是扭曲和透视错误。相机校准通过计算相机的内在和外在参数来校正这些误差,从而允许更准确的测量和几何计算。

关键参数:

  1. 内在参数:
  • 焦距:根据透镜的焦距确定图像的大小。
  • 光学中心(主点):相机透镜的中心点。
  • 畸变系数:用于校正透镜畸变,如桶形畸变和枕形畸变。(You将在图1中清楚地看到这一点。)

:术语"失真"是指镜头引起的误差,如翘曲或弯曲。

图1.枕形失真和桶形失真。

2.外部参数:

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

图2.收集用于校准的视觉数据。

如何进行相机校准?

通常,已知的几何图案(诸如棋盘)用于相机校准。**该图案的已知尺寸和位置用作检测相机图像中的失真的参考。**校准过程包括以下步骤:

  1. 图像采集:要执行相机校准,您需要从不同角度拍摄一组至少15张棋盘图案的图像。该图案的角点有助于检测图像中的失真。
  2. 角点检测:在每个图像中检测棋盘图案的角点。这些角点的正确检测对于精确校准至关重要。
  3. 内外参数计算:根据摄像机图像中角点与其真实坐标的差异,优化计算摄像机的内外参数。该计算通常使用AI算法或数学优化技术来完成。
  4. 失真校正:计算出的参数用于校正图像中的失真,消除非线性透镜失真。
  5. 验证:为了测试校准的准确性,使用相机拍摄新图像,并应用校准参数来校正图像。然后观察校正的准确性。

图3.添加桶形失真。

在Python中使用OpenCV进行相机校准

OpenCV是Python中最常用的相机校准库之一。OpenCV为相机校准和畸变校正提供了必要的功能。下面是一个简单的校准示例:

python 复制代码
import cv2
import numpy as np
import glob

# Dimensions of the chessboard (number of internal corners)
grid_size = (9, 6)

# The real-world size of each square (2 cm)
square_size = 2  # cm

# 3D world coordinates of the chessboard
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

# Lists for storing the necessary points for calibration
object_points = []  # 3D world coordinates
image_points = []  # 2D image coordinates

# Folder where calibration images are stored
images = glob.glob('calibration_images/*.jpg')

for fname in images:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # Find the corners of the chessboard
    ret, corners = cv2.findChessboardCorners(gray, grid_size, None)

    if ret:
        object_points.append(obj_points)
        image_points.append(corners)

        # Visualize the corners
        cv2.drawChessboardCorners(img, grid_size, corners, ret)
        cv2.imshow('Chessboard Corners', img)
        cv2.waitKey(500)

cv2.destroyAllWindows()

# Perform calibration
ret, camera_matrix, dist_coeffs, rvecs, tvecs = cv2.calibrateCamera(object_points, image_points, gray.shape[::-1], None, None)

# Save the camera matrix and distortion coefficients
np.savez('calibration_data.npz', camera_matrix=camera_matrix, dist_coeffs=dist_coeffs)

# Print the calibration results
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)

  • grid_size:指定棋盘上内角点的数量。在这个例子中,棋盘图案具有9列和6行角点(9列 * 6行= 54个角点)。此值应与实际使用的棋盘相匹配。

    square_size = 2 # cm

  • square_size:棋盘上的每个正方形都被设置为具有2 cm的真实世界边长。

    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):为每个角点创建具有(x,y,z)坐标的3D空矩阵。

  • **np.mgrid[0:grid_size[0],0:grid_size[1]]:**生成棋盘上角点的(x,y)坐标。

mgrid是一个NumPy函数,用于创建多维网格结构,语法为mgrid[start:end:step]

举例来说:

Two-Dimensional Grid (Mesh)

x, y = np.mgrid[0:3, 0:3]
print("X:\n", x)
print("Y:\n", y)

Output:
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 world coordinates
    image_points = [] # 2D image coordinates

  • 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)

  • 如果retTrue,表示棋盘角已成功找到:

  • 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()

  • cv2.destroyAllWindows:关闭所有打开的窗口。

    ret, camera_matrix, dist_coeffs, rvecs, tvecs = cv2.calibrateCamera(object_points, image_points, gray.shape[::-1], camera_matrix=None, dist_coeffs=None, flags=None, criteria=None)

  • camera_matrix:包含相机内部参数(焦距、光学中心等)的矩阵。

  • dist_coeffs:透镜畸变系数。

  • rvecs:旋转向量。

  • tvecs:平移向量。

  • **cv2.calibrate Camera:执行相机校准。**此函数根据真实世界3D点与图像中对应的2D点之间的关系计算相机参数。

  • object_points:3D真实世界坐标。

  • image_points:图像中的2D投影坐标。

  • gray. shape [::-1]:图像分辨率(宽度和高度)。

  • **camera_matrix(默认值:None)-calibrate相机侧:这是一个3x3矩阵,表示相机的内部参数(焦距、主点等)。**如果提供为"无",则这些参数将由函数计算。如果你有一个已知的相机矩阵,你可以在这里提供它。

  • **dist_coeffs(默认值:None)-calibrate相机侧:这是表示失真系数(失真)的向量。**如果设置为"无",则将通过函数计算失真系数。

注意提供 **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_ITERcv2.TERM_CRITERIA_EPS等选项一起使用。

    np.savez('calibration_data.npz', camera_matrix=camera_matrix, dist_coeffs=dist_coeffs)

  • savez :将计算的相机矩阵和失真系数保存到一个名为calibration_data.npz的文件中。此文件允许您以后重复使用校准参数。

    print("Camera Matrix:\n", camera_matrix)
    print("Distortion Coefficients:\n", dist_coeffs)

  • print :在屏幕上显示camera_matrix (内部参数)和失真系数

此代码使用OpenCV执行相机校准并保存结果。摄像机校准对于校正图像中的失真和进行精确测量至关重要。

校准后将获得的值

在此过程结束时,函数将计算并返回camera_matrixdist_coeffs

摄象机矩阵

该矩阵包含相机的内部参数(焦距、主点等)。它用于了解摄影机的透镜特性和透视变换。它是一个3x3矩阵,可以看起来像这样:

这里,f_xf_y 是相机的焦距(以像素为单位),c_xc_y是图像平面上的主点(通常是图像的中心)的像素坐标。

什么是最重要的一点?主点表示图像的光学中心,并定义相机的透镜和图像平面之间的关系。如果相机的光轴偏离中心,则可以使用c_xc_y坐标来检测该偏移。

范例:

假设您的相机分辨率为1920x1080像素,校准后,您将获得以下camera_matrix:

  • f_x = 1200f_y = 1200:沿水平轴和垂直轴的焦距沿着。
  • c_x = 960c_y = 540:主点的坐标,位于图像平面的中心(960和540表示中心点,因为您的分辨率为1920x1080)。

分布系数

它包含透镜的畸变系数。这些系数用于校正透镜的几何失真(例如,桶形失真或枕形失真)。

通常,该向量包含以下系数:

这些系数:

  1. k_1、k_2、k_3 :径向畸变系数。这些用于校正桶形或枕形失真。如果图像中的失真随着它们远离中心而变得更加明显,则这是径向失真,并且k_1k_2k_3 校正该失真。k_1 校正图像中心附近的失真。k_2 校正朝向图像边缘的较大失真。k_3在离中心最远的点处,特别是在边缘处,对失真进行微调。

桶形失真:向边缘扩展的失真。

枕形失真:向内收缩到边缘的失真。

2. p_1、p_2 :切向失真系数。当透镜与传感器未完全对准时,会发生这种失真。如果透镜没有完全居中或具有轴偏移,则图像倾向于向边缘偏移。p_1p_2 校正该倾斜。p_1 校正沿x轴 (水平面)的沿着偏移或失真。P_2 校正沿y轴(垂直平面)的沿着偏移或失真。

什么是径向和切向失真?

径向失真 :这些失真导致图像中的直线在远离中心时弯曲。k_1k_2k_3用于校正这些曲线。

切向畸变 :当透镜与传感器不完全垂直时产生的畸变,导致图像向边缘偏移。p_1p_2校正这些移位。

3. k_4、k_5、k_6***(可选)***:高阶径向畸变系数。这些参数用于校正更复杂的畸变,例如来自非常广角镜头的畸变。它们通常不用于标准校准,但可以在需要更精确的校正时应用。

范例:

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值越大,校正越强。随着它们的减少,校正的效果也会减弱。


好了,这篇文章就介绍到这里,喜欢的小伙伴感谢给点个赞和关注,更多精彩内容持续更新~~
关于本篇文章大家有任何建议或意见,欢迎在评论区留言交流!

相关推荐
网易独家音乐人Mike Zhou3 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
安静读书3 小时前
Python解析视频FPS(帧率)、分辨率信息
python·opencv·音视频
小陈phd3 小时前
OpenCV从入门到精通实战(九)——基于dlib的疲劳监测 ear计算
人工智能·opencv·计算机视觉
小二·5 小时前
java基础面试题笔记(基础篇)
java·笔记·python
小喵要摸鱼6 小时前
Python 神经网络项目常用语法
python
一念之坤8 小时前
零基础学Python之数据结构 -- 01篇
数据结构·python
wxl7812278 小时前
如何使用本地大模型做数据分析
python·数据挖掘·数据分析·代码解释器
NoneCoder8 小时前
Python入门(12)--数据处理
开发语言·python
如若1238 小时前
主要用于图像的颜色提取、替换以及区域修改
人工智能·opencv·计算机视觉
LKID体9 小时前
Python操作neo4j库py2neo使用(一)
python·oracle·neo4j