本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:计算机视觉领域的相机标定是实现精确三维重建和物体跟踪的关键步骤。本项目通过OpenCV库提供了一个C++实现的相机标定程序。通过该程序,用户可以校正图像畸变、获取相机内参和外参,并进行三维重建。OpenCV中的 cv::calibrateCamera() 函数用于估计相机参数和转换矩阵。相机标定流程包括创建棋盘格图案、图像检测、角点精修、构建图像金字塔、收集样本、调用 calibrateCamera() 、校正畸变和保存应用标定结果等步骤。此外,还包括了如何读取图像、检测角点、进行标定及校正结果展示的示例代码,为计算机视觉应用提供了基础工具。 C++_OpenCV_相机标定程序Calibration

1. 相机标定概念和重要性

1.1 相机标定的定义

相机标定是计算机视觉领域中的一项基础技术,用于确定相机的内在参数(内参)以及可能的外部参数(外参)。内参包括焦距、主点坐标和畸变系数等,是相机内部光学系统特性的数学表示。外参则描述了相机相对于世界坐标系的位置和姿态。标定过程涉及到拍摄一系列已知几何特性的标定物,通过分析这些图像来计算这些参数。

1.2 相机标定的重要性

在计算机视觉和机器视觉应用中,相机标定至关重要。准确的标定能够补偿图像畸变,提高测量精度,是许多视觉算法能够正常工作的前提。例如,在三维重建、机器人导航、增强现实等应用中,精确的相机模型可以提升整个系统的性能,确保图像分析和理解的准确性。

1.3 相机标定的目的和应用场景

相机标定的根本目的是为了建立现实世界坐标系与图像像素坐标系之间的精确映射关系。这项技术广泛应用于各个领域,包括但不限于工业自动化、医疗成像、监控安全、自动驾驶汽车等。不同的应用场景对相机标定的精度和稳定性有不同的要求,但其核心目标都是为了提高视觉处理系统的准确性和可靠性。

2. OpenCV库介绍与相机标定函数

2.1 OpenCV库概述

OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习软件库。它包含了一系列针对图像处理和计算机视觉应用的函数和方法。OpenCV库广泛应用于学术研究、工业应用以及商业产品中,特别是在进行视觉算法研究和开发时,它是不可或缺的工具之一。

2.1.1 OpenCV库的安装与配置

安装OpenCV库之前,需要准备好一些环境依赖,包括Python和某些必要的编译工具。以下是针对Python环境的安装步骤。

首先,确保系统已经安装了Python。然后通过pip安装OpenCV:

pip install opencv-python

如果需要OpenCV的扩展模块,可以安装OpenCV的完整版本:

pip install opencv-python-headless

安装完成后,在Python脚本中导入OpenCV进行验证:

import cv2
print(cv2.__version__)

如果能够正常打印版本信息,则表示安装成功。

2.1.2 OpenCV库的模块和功能介绍

OpenCV库分为多个模块,每个模块包含了一系列特定功能的函数和类。其中核心模块包括:

  • core :基础数据结构和功能,如矩阵操作、图像处理等。
  • imgproc :图像处理,如滤波、形态学操作、特征检测等。
  • imgcodecs :图像文件的读写。
  • videoio :视频流处理。
  • calib3d :三维重建、相机标定等功能。

每个模块的函数可以单独导入使用,例如:

import cv2
from cv2 import aruco

# 使用ArUco标记进行相机标定
marker_dict = aruco.Dictionary_get(aruco.DICT_6X6_250)

2.2 OpenCV中的相机标定函数

2.2.1 相机标定函数的原理

相机标定是计算机视觉中的基础任务之一,它旨在估计相机的内部参数和外部参数,以及可能的镜头畸变参数。这些参数对于图像校正和三维重建是必不可少的。

相机标定通常使用已知几何结构的标定物体,例如棋盘格或圆形格。通过拍摄这些标定物体在不同视角下的图片,使用标定算法计算相机的内参矩阵(焦距、主点等)、畸变系数、以及外参(相机相对于标定物体的位置和姿态)。

OpenCV提供了 cv::calibrateCamera() 函数进行相机标定。该函数基于多视角几何和非线性优化算法实现。

2.2.2 标定函数的参数详解

cv::calibrateCamera() 函数的主要参数包括:

  • objectPoints :3D点的世界坐标。
  • imagePoints :3D点在图像上的投影坐标。
  • imageSize :标定图像的尺寸。
  • cameraMatrix :输出的相机内参矩阵。
  • distCoeffs :输出的畸变系数。
  • rvecs :相机旋转矩阵(外参)。
  • tvecs :相机平移向量(外参)。
  • flags :标定过程中的标志位。
  • criteria :标定优化过程中的终止条件。

下面是一个简化的使用示例:

import numpy as np
import cv2
import glob

# 准备对象点,如 (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
objp = np.zeros((6*7, 3), np.float32)
objp[:,:2] = np.mgrid[0:7, 0:6].T.reshape(-1, 2)

# 用于存储所有图像的对象点和图像点的数组
objpoints = [] # 真实世界中的点
imgpoints = [] # 图像平面中的点

# 读取所有标定图像
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, (7,6), None)

    # 如果找到足够点对,将其添加到列表中
    if ret == True:
        objpoints.append(objp)
        imgpoints.append(corners)

        # 绘制并显示角点
        img = cv2.drawChessboardCorners(img, (7,6), corners, ret)
        cv2.imshow('img', img)
        cv2.waitKey(500)

cv2.destroyAllWindows()

# 标定
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)

print("相机内参矩阵:\n", mtx)
print("畸变系数:\n", dist)
print("旋转向量:\n", rvecs)
print("平移向量:\n", tvecs)

以上代码展示了如何使用OpenCV进行相机标定的基本步骤。实际使用时,需要根据具体的标定物体和相机设置进行相应的调整。标定过程得到的内参和畸变系数对于后续的图像校正和三维重建具有非常重要的作用。

3. 相机标定基本流程概述

在进行相机标定之前,我们需要明确标定的基本流程以及每个步骤的具体操作。这为我们的标定工作提供了一个清晰的路线图,从而确保我们能够有效地提取相机参数,并对图像畸变进行校正。下面将详细介绍相机标定的前置准备工作与标定过程中的关键步骤。

3.1 相机标定的前置准备工作

3.1.1 准备标定图案和拍摄环境

在标定相机之前,首先需要准备合适的标定图案。这些图案通常是一组已知几何结构的平面图案,例如棋盘格,因为它们为图像中点的检测提供了明确的特征。棋盘格的优势在于角点容易检测且数量丰富,这对于提高标定精度至关重要。

拍摄环境也应该尽量保持一致且易于控制。最好在一个光线均匀且稳定的环境下进行标定,以减少环境因素对结果的影响。此外,应确保标定图案在拍摄过程中完全展现其全部特征,避免因遮挡导致的特征点丢失。

3.1.2 图像采集和预处理

采集到的图像需要进行预处理,以提高后续标定过程的稳定性和准确性。预处理步骤可能包括:

  • 灰度化 :将彩色图像转换为灰度图像,减少计算量。
  • 滤波去噪 :使用高斯滤波等方法对图像进行平滑处理,去除噪声。
  • 二值化处理 :通过阈值分割将图像转换为二值图像,便于后续处理。

3.2 标定过程中的关键步骤

3.2.1 提取标定点

标定点的提取是相机标定过程中的关键步骤。在棋盘格图案中,角点是主要的标定点。OpenCV提供了一个非常有用的函数 cv::findChessboardCorners() 用于自动检测图像中的角点。

cv::Mat image; // 加载的标定图像
std::vector<std::vector<cv::Point2f>> imagePoints; // 存储检测到的角点
bool found = cv::findChessboardCorners(image, // 输入图像
                                        cv::Size(9,6), // 格子大小,这里是9x6
                                        imagePoints, // 输出的角点向量
                                        cv::CALIB_CB_ADAPTIVE_THRESH | cv::CALIB_CB_FILTER_QUADS); // 检测标志

if (found) {
    cv::cornerSubPix(image, // 输入图像
                     imagePoints[0], // 输入/输出的角点坐标向量
                     cv::Size(11, 11), // 搜索窗口大小
                     cv::Size(-1, -1), // 零区域
                     cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::MAX_ITER, 30, 0.1)); // 迭代停止条件
}

该函数利用亚像素精度的角点检测算法来提高角点的定位精度。只有当所有图像中的角点都被成功检测后,才能进行下一步的相机内参计算。

3.2.2 计算相机内参和畸变系数

计算相机内参和畸变系数是标定过程的核心环节。通过前面提取的标定点,我们可以使用 cv::calibrateCamera() 函数来计算相机的内参矩阵和畸变系数。

std::vector<cv::Mat> rvecs, tvecs; // 存储旋转向量和平移向量
cv::Mat cameraMatrix; // 相机内参矩阵
cv::Mat distCoeffs; // 畸变系数矩阵

double error = cv::calibrateCamera(objectPoints, // 标定对象的3D点
                                   imagePoints, // 标定图像的2D点
                                   image.size(), // 图像大小
                                   cameraMatrix, // 相机内参矩阵
                                   distCoeffs, // 畸变系数矩阵
                                   rvecs, tvecs); // 旋转向量和平移向量

// 等待用户按键后继续
cv::waitKey();

该函数通过求解最小化重投影误差的优化问题来计算出相机的内参矩阵和畸变系数。内参矩阵 cameraMatrix 包含焦距、主点坐标等信息,而 distCoeffs 则包含径向畸变和切向畸变的系数。

在完成了上述步骤后,标定工作基本完成,我们可以通过检查误差值来评估标定的精度,并进行进一步的校正或重新标定操作。通过这些步骤,我们可以获得精确的相机内参和畸变系数,为后续的图像处理和计算机视觉应用打下坚实的基础。

4. 标定程序的组成部分和操作步骤

4.1 标定程序的结构框架

4.1.1 程序的主要组成部分

标定程序通常由几个关键部分组成,这些部分协同工作以完成整个标定过程。主要组成部分包括:

  • 参数设置模块 :负责接收用户输入的标定参数,例如图像数量、棋盘格尺寸等。
  • 图像采集模块 :用于获取用于标定的棋盘格图片,确保图片质量符合要求。
  • 特征提取模块 :从图片中提取标定点,常见的方法是检测棋盘格角点。
  • 标定计算模块 :使用提取的标定点数据计算相机的内参和畸变系数。
  • 结果输出模块 :输出标定结果,包括相机内参矩阵、畸变系数等,并可将结果保存至文件。
  • 评估模块 :评估标定结果的准确性,通常通过重投影误差等指标。

这些模块以流水线的方式相互关联,形成一个完整的标定系统。

4.1.2 各部分功能和相互关系

各个模块的功能和相互关系是紧密相连的。一个典型的标定程序的运行逻辑可以概括如下:

  1. 参数设置模块 初始化标定过程,为后续模块提供配置信息。
  2. 图像采集模块 根据参数设置获取必需的标定图像。
  3. 特征提取模块 处理图像,提取出用于标定的特征点。
  4. 标定计算模块 利用提取的特征点,使用标定算法计算相机参数。
  5. 结果输出模块 将计算得到的相机参数进行保存和显示。
  6. 评估模块 对计算结果进行评估,并可能根据结果重新调整参数设置模块的参数,以优化标定过程。

这种设计使得标定程序能够灵活地适应不同的标定需求和改进算法。

4.2 实际操作步骤详解

接下来,我们将详细解读标定程序的实际操作步骤。

4.2.1 步骤一:设置标定参数

在开始标定之前,必须对程序进行初始设置。这通常涉及到定义标定图案的大小、棋盘格的角点数、标定图像的数量等参数。这些参数将决定标定的精度和程序的行为。在一些标定软件中,这一过程可以通过图形用户界面来完成,而在命令行工具中,则需要通过配置文件或直接在代码中指定。

代码示例:

import cv2

# 设置标定参数
num_squares_x = 9  # 棋盘格的行数
num_squares_y = 6  # 棋盘格的列数
square_size = 25   # 棋盘格角点间的距离,单位为毫米

# 创建棋盘格角点的世界坐标
objp = np.zeros((num_squares_x * num_squares_y, 3), np.float32)
objp[:, :2] = np.mgrid[0:num_squares_x, 0:num_squares_y].T.reshape(-1, 2)
objp = objp * square_size

# 创建用于存储所有对象点和图像点的数组
objpoints = []  # 真实世界中的3D点
imgpoints = []  # 相机捕获的图像中的2D点
4.2.2 步骤二:运行标定程序

标定程序运行时,会从一系列已知结构的图像中提取标定点,并根据这些点计算相机的内参和畸变系数。用户需要提供标定图像,并确保图像质量良好,以便正确提取角点。

代码示例:

# 加载标定图像
images = [cv2.imread(f'image{i}.jpg') for i in range(1, 20)]

# 确保图像被成功加载
for img in images:
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 查找棋盘格角点
    ret, corners = cv2.findChessboardCorners(gray, (num_squares_x, num_squares_y), None)
    if ret:
        objpoints.append(objp)
        imgpoints.append(corners)
    else:
        print(f'Image {img} is not suitable for calibration.')

# 计算内参和畸变系数
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
4.2.3 步骤三:评估标定结果

评估标定结果是确保标定准确性的关键步骤。评估通常基于重投影误差,它测量标定点在重投影回图像后的误差。重投影误差越小,说明标定越准确。

代码示例:

# 重投影误差的计算
mean_error = 0
for i in range(len(objpoints)):
    imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
    error = cv2.norm(imgpoints[i], imgpoints2, cv2.NORM_L2) / len(imgpoints2)
    mean_error += error

mean_error /= len(objpoints)
print(f'Mean error: {mean_error}')

# 输出标定参数
print("Camera matrix : \n")
print(mtx)
print("dist : \n")
print(dist)

在本例中,我们使用OpenCV库来计算相机的内参矩阵和畸变系数。代码的逻辑首先是准备标定图案的世界坐标,然后是加载标定图像,并从中提取棋盘格角点。之后,使用 cv::calibrateCamera() 函数计算相机的内参和畸变系数,并通过计算重投影误差评估标定结果。上述代码块展示了标定过程中各个步骤的代码实现,并说明了如何评估标定结果的准确性。在实际应用中,标定结果的准确性直接影响计算机视觉系统的性能,因此这一步骤不可或缺。

5. OpenCV中的 cv::calibrateCamera() 函数

5.1 cv::calibrateCamera() 函数使用入门

5.1.1 函数调用格式和参数设置

cv::calibrateCamera() 函数是OpenCV中实现相机标定的核心函数,它根据一系列已知结构的物体图像计算相机内参和畸变系数。该函数的一般调用格式如下:

bool cv::calibrateCamera(
    InputArrayOfArrays objectPoints, 
    InputArrayOfArrays imagePoints,
    Size image_size,
    InputOutputArray cameraMatrix, 
    InputOutputArray distCoeffs,
    OutputArrayOfArrays rvecs, 
    OutputArrayOfArrays tvecs,
    int flags = 0,
    TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 30, DBL_EPSILON)
);
  • objectPoints : 一个向量,其中包含了每个标定图像中物体点的3D坐标,这些点应该按照实际的物理尺寸进行测量。
  • imagePoints : 一个向量,包含了对应于 objectPoints 中的3D点在图像平面上的2D点的坐标。
  • image_size : 标定图像的大小。
  • cameraMatrix : 相机内参矩阵,通常初始化为一个3x3单位矩阵。
  • distCoeffs : 畸变系数,初始值为零向量。
  • rvecs : 一个向量,用于存储每一个图像的旋转向量。
  • tvecs : 一个向量,用于存储每一个图像的平移向量。
  • flags : 标志位,用于选择不同的校准方法,比如固定内参矩阵、设置畸变系数的初始值等。
  • criteria : 标定终止条件,可以是迭代次数或精确度。

5.1.2 函数的返回值解析

函数返回一个布尔值,如果标定成功则返回 true ,否则返回 false 。标定成功后,相关的参数矩阵和向量会包含相机的标定信息。

需要注意的是, cv::calibrateCamera() 函数的性能和精度会受到输入数据质量的影响。因此,在实际使用时,高质量的标定板图案和精确的图像点检测算法是必不可少的。

5.2 高级用法和参数优化

5.2.1 参数优化策略

在使用 cv::calibrateCamera() 时,参数优化是一个重要的步骤。通常,这意味着需要进行多次标定实验,每次尝试不同的初始值和优化策略,以确保获得最佳的标定结果。以下是一些优化策略:

  1. 初始化内参矩阵 :使用 cv::initCameraMatrix2D() 函数进行初始估计,它基于 objectPoints imagePoints 计算一个近似的内参矩阵。
  2. 设置畸变系数的初始值 :有时候为畸变系数设置一个合理的初始值可以帮助提高优化的速度和稳定性。
  3. 调整优化标志 :改变 flags 参数,可以对内参矩阵或畸变系数进行不同程度的优化。
cv::Mat cameraMatrix = cv::Mat::eye(3, 3, CV_64F);
cv::Mat distCoeffs = cv::Mat::zeros(8, 1, CV_64F);

// 使用默认标志进行标定
bool success = cv::calibrateCamera(objPoints, imgPoints, imgSize, cameraMatrix, distCoeffs, ...);

5.2.2 错误处理和异常情况分析

在使用 cv::calibrateCamera() 函数时,可能会遇到各种错误和异常情况,合理处理这些问题对于提高程序的鲁棒性至关重要。以下是一些常见的错误处理方法:

  1. 检查输入数据的有效性 :确保 objectPoints imagePoints 的数量匹配,且每个图像对应的点数量相同。
  2. 异常值的检测 :标定图像中的噪声或错误检测的特征点会导致严重的标定误差。需要实现检测和剔除这些异常值的机制。
  3. 算法收敛性检查 :如果标定算法没有收敛(即函数返回 false ),检查终止条件 criteria 是否设置得合理。
// 检查输出参数是否为零向量,表示未初始化或错误
if (distCoeffs.total() == 0 || cameraMatrix.total() == 0) {
    // 输出错误信息并进行相应处理
}

在后续章节中,我们将继续探讨OpenCV在计算机视觉中的应用,并通过实际案例来演示相机标定技术在不同场景下的应用效果。

6. 图像畸变校正方法

6.1 图像畸变的类型和成因

6.1.1 径向畸变和切向畸变分析

在相机标定的过程中,图像畸变是不可避免的问题,尤其在广角镜头中更为明显。图像畸变主要分为两类:径向畸变和切向畸变。

  • 径向畸变 :由于相机镜头的形状和折射率分布不均匀导致光线在穿过镜头时弯曲的程度不一致,形成了图像边缘的枕形或桶形失真。径向畸变通常用数学多项式函数来描述,其表达式为 (r_{\text{distorted}} = r + k_1 \cdot r^3 + k_2 \cdot r^5 + k_3 \cdot r^7 + \dots),其中 (r) 是理想情况下没有畸变的半径,(r_{\text{distorted}}) 是畸变后的半径,(k_1, k_2, k_3, \dots) 是畸变系数。

  • 切向畸变 :由于相机镜头与成像平面没有精确对准或镜头组装不完美而引起的图像中心的偏移。它与径向畸变不同,不依赖于光线的半径距离,而是依赖于像素的位置。切向畸变可以表示为 (x_{\text{distorted}} = x + [2p_1 \cdot x \cdot y + p_2 \cdot (r^2 + 2x^2)]) 和 (y_{\text{distorted}} = y + [p_1 \cdot (r^2 + 2y^2) + 2p_2 \cdot x \cdot y]),其中 (p_1) 和 (p_2) 是切向畸变的系数。

6.1.2 畸变对图像质量的影响

畸变会严重扭曲图像内容,影响图像质量,特别是在需要精确测量的计算机视觉应用中,如测量、地图绘制、三维重建等。未校正的畸变会导致边缘的失真,这使得从图像中提取准确的几何信息变得困难。因此,进行图像校正以消除畸变至关重要。

6.2 畸变校正的方法和技术

6.2.1 校正模型的建立

为了校正图像畸变,需要建立一个校正模型,这个模型能够将畸变图像映射回没有畸变的图像。这一过程通常通过以下几个步骤完成:

  1. 标定相机 :首先需要使用已知的标定图案,通过标定函数计算出相机的内参矩阵和畸变系数。

  2. 畸变模型 :使用内参矩阵和畸变系数建立畸变模型,该模型可以根据像素位置计算出校正后的像素位置。

  3. 像素重映射 :根据畸变模型,可以计算出畸变图像中每个像素在未畸变图像中的正确位置,并据此进行像素重映射。

6.2.2 校正过程和效果评估

校正过程包含以下关键步骤:

  1. 初始化映射 :为畸变图像和未畸变图像分别初始化映射数组。

  2. 计算映射关系 :利用畸变模型计算出畸变图像中每个像素点在未畸变图像中的对应位置。

  3. 重映射像素 :根据计算出的映射关系,将畸变图像的每个像素点映射到未畸变图像的对应位置,并使用插值算法填充新的像素值。

  4. 效果评估 :通过比较校正前后的图像以及执行一些定量的图像质量评估指标(如均方误差、峰值信噪比)来评估校正效果。

代码示例:

import cv2
import numpy as np

# 读取畸变图像
distorted_image = cv2.imread('distorted_image.jpg')

# 相机内参和畸变系数(假设已经通过标定获取)
camera_matrix = np.array([[fx, 0, cx],
                          [0, fy, cy],
                          [0, 0, 1]])
dist_coeffs = np.array([k1, k2, p1, p2, k3])

# 假设得到的理想图像尺寸
h理想, w理想 = 480, 640

# 对畸变图像进行校正
undistorted_image = cv2.undistort(distorted_image, camera_matrix, dist_coeffs, None, camera_matrix)

# 评估校正效果的指标计算可以使用scikit-image库中的函数
from skimage.metrics import structural_similarity as ssim
ssim_value = ssim(undistorted_image, ideal_image)

# 保存校正后的图像
cv2.imwrite('undistorted_image.jpg', undistorted_image)

在上述代码中, cv2.undistort 函数用于执行畸变校正。它需要原始图像、内参矩阵、畸变系数,可选地还有用于输出的内参矩阵。校正效果可以通过比较原始畸变图像和校正后的图像并计算结构相似性指数(SSIM)值来评估。

校正后的图像应该显示出明显的改善,边缘失真被减少或消除,为后续的图像处理步骤提供了高质量的数据源。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:计算机视觉领域的相机标定是实现精确三维重建和物体跟踪的关键步骤。本项目通过OpenCV库提供了一个C++实现的相机标定程序。通过该程序,用户可以校正图像畸变、获取相机内参和外参,并进行三维重建。OpenCV中的 cv::calibrateCamera() 函数用于估计相机参数和转换矩阵。相机标定流程包括创建棋盘格图案、图像检测、角点精修、构建图像金字塔、收集样本、调用 calibrateCamera() 、校正畸变和保存应用标定结果等步骤。此外,还包括了如何读取图像、检测角点、进行标定及校正结果展示的示例代码,为计算机视觉应用提供了基础工具。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐