OpenCV相机标定与3D重建(59)用于立体相机标定的函数stereoCalibrate()的使用

  • 操作系统:ubuntu22.04
  • OpenCV版本:OpenCV4.9
  • IDE:Visual Studio Code
  • 编程语言:C++11

算法描述

标定立体相机设置。此函数找到两个相机各自的内参以及两个相机之间的外参。

cv::stereoCalibrate 是 OpenCV 中用于立体相机标定的函数。它通过一组已知的3D点及其在两个相机中的对应2D投影,来估计两个相机之间的相对位置和方向(旋转矩阵R和平移向量T),同时还可以优化每个相机的内参矩阵和畸变系数。

函数原型

cpp 复制代码
double cv::stereoCalibrate	
(
	InputArrayOfArrays 	objectPoints,
	InputArrayOfArrays 	imagePoints1,
	InputArrayOfArrays 	imagePoints2,
	InputOutputArray 	cameraMatrix1,
	InputOutputArray 	distCoeffs1,
	InputOutputArray 	cameraMatrix2,
	InputOutputArray 	distCoeffs2,
	Size 	imageSize,
	InputOutputArray 	R,
	InputOutputArray 	T,
	OutputArray 	E,
	OutputArray 	F,
	OutputArrayOfArrays 	rvecs,
	OutputArrayOfArrays 	tvecs,
	OutputArray 	perViewErrors,
	int 	flags = CALIB_FIX_INTRINSIC,
	TermCriteria 	criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 1e-6) 
)		

参数

  • 参数objectPoints 校准图案点的向量的向量。结构与 calibrateCamera 中相同。对于每个图案视图,两个相机需要看到相同的物体点。因此,objectPoints.size()、imagePoints1.size() 和 imagePoints2.size() 需要相等,并且对于每个 i,objectPoints[i].size()、imagePoints1[i].size() 和 imagePoints2[i].size() 也需要相等。
  • 参数imagePoints1 第一个相机观测到的校准图案点投影的向量的向量。结构与 calibrateCamera 中相同。
  • 参数imagePoints2 第二个相机观测到的校准图案点投影的向量的向量。结构与 calibrateCamera 中相同。
  • 参数cameraMatrix1 第一个相机的输入/输出内参矩阵,与 calibrateCamera 中相同。对于立体情况,可以使用额外的标志,见下文。
  • 参数distCoeffs1 输入/输出畸变系数向量,与 calibrateCamera 中相同。
  • 参数cameraMatrix2 第二个相机的输入/输出内参矩阵。详见 cameraMatrix1 的描述。
  • 参数distCoeffs2 第二个相机的镜头畸变系数的输入/输出向量。详见 distCoeffs1 的描述。
  • 参数imageSize 仅用于初始化相机内参矩阵的图像尺寸。
  • 参数R 输出旋转矩阵。连同平移向量 T 一起,该矩阵将第一个相机坐标系中的点变换到第二个相机坐标系中的点。更技术性地说,R 和 T 的组合执行了从第一个相机坐标系到第二个相机坐标系的基底变换。由于其对偶性,这个组合等价于第一个相机相对于第二个相机坐标系的位置。
  • 参数T 输出平移向量,参见上述描述。
  • 参数E 输出本质矩阵。
  • 参数F 输出基础矩阵。
  • 参数rvecs 输出旋转向量(Rodrigues 表示)的向量,估计每个立体对中第一相机坐标系下的图案视图。具体来说,每个第 i 个旋转向量连同对应的第 i 个平移向量(见下一个输出参数描述),将校准图案从物体坐标空间变换到立体对中第一相机的相机坐标空间。更技术性地说,第 i 个旋转和平移向量的组合执行了从物体坐标空间到立体对中第一相机的相机坐标空间的基底变换。
  • 参数tvecs 输出平移向量的向量,估计每个图案视图,参见上一个输出参数(rvecs)的参数描述。
  • 参数perViewErrors 每个图案视图的 RMS 重投影误差的输出向量。
  • 参数flags 不同的标志,可能是零或以下值的组合:
    • CALIB_FIX_INTRINSIC 固定 cameraMatrix? 和 distCoeffs?,以便只估计 R、T、E 和 F 矩阵。
    • CALIB_USE_INTRINSIC_GUESS 根据指定的标志优化一些或全部的内参。初始值由用户提供。
    • CALIB_USE_EXTRINSIC_GUESS R 和 T 包含有效的初始值,这些值被进一步优化。否则,R 和 T 初始化为图案视图的中位数(每个维度分别处理)。
    • CALIB_FIX_PRINCIPAL_POINT 在优化过程中固定主点。
    • CALIB_FIX_FOCAL_LENGTH 固定 f y ( j ) f^{(j)}_y fy(j)和 f y ( j ) f^{(j)}_y fy(j) 。
    • CALIB_FIX_ASPECT_RATIO 优化 f y ( j ) f^{(j)}_y fy(j) ,固定比率 f x ( j ) / f y ( j ) f^{(j)}_x/f^{(j)}_y fx(j)/fy(j) 。
    • CALIB_SAME_FOCAL_LENGTH 强制 f x ( 0 ) = f x ( 1 ) f^{(0)}_x=f^{(1)}_x fx(0)=fx(1)和 f y ( 0 ) = f y ( 1 ) f^{(0)}_y=f^{(1)}_y fy(0)=fy(1)。
    • CALIB_ZERO_TANGENT_DIST 将每个相机的切向畸变系数设为零并固定不变。
    • CALIB_FIX_K1,..., CALIB_FIX_K6 在优化过程中不改变相应的径向畸变系数。如果设置了 CALIB_USE_INTRINSIC_GUESS,则使用提供的 distCoeffs 矩阵中的系数;否则,将其设置为 0。
    • CALIB_RATIONAL_MODEL 启用系数 k4、k5 和 k6。为了提供向后兼容性,此额外标志应显式指定以使标定函数使用有理模型并返回8个系数。如果不设置此标志,函数计算并返回仅5个畸变系数。
    • CALIB_THIN_PRISM_MODEL 启用系数 s1、s2、s3 和 s4。为了提供向后兼容性,此额外标志应显式指定以使标定函数使用薄棱镜模型并返回12个系数。如果不设置此标志,函数计算并返回仅5个畸变系数。
    • CALIB_FIX_S1_S2_S3_S4 在优化过程中不改变薄棱镜畸变系数。如果设置了 CALIB_USE_INTRINSIC_GUESS,则使用提供的
      distCoeffs 矩阵中的系数;否则,将其设置为 0。
    • CALIB_TILTED_MODEL 启用系数 τX 和 τY。为了提供向后兼容性,此额外标志应显式指定以使标定函数使用倾斜传感器模型并返回14个系数。如果不设置此标志,函数计算并返回仅5个畸变系数。
  • CALIB_FIX_TAUX_TAUY 在优化过程中不改变倾斜传感器模型的系数。如果设置了 CALIB_USE_INTRINSIC_GUESS,则使用提供的 distCoeffs 矩阵中的系数;否则,将其设置为 0。
  • criteria 迭代优化算法的终止条件。
    该函数估计了构成立体对的两个相机之间的变换。如果分别计算了一个物体相对于第一个相机和第二个相机的姿态 (R1, T1) 和 (R2, T2),并且对于一个立体相机,两个相机之间的相对位置和方向是固定的,那么这两个姿态肯定相互关联。这意味着,如果已知两个相机之间的相对位置和方向 (R, T),就可以在给定 (R1, T1) 的情况下计算 (R2, T2)。这就是该函数所做的。它计算 (R, T) 使得:

R 2 = R R 1 . R_2=R R_1. R2=RR1.
T 2 = R T 1 + T . T_2=R T_1 + T. T2=RT1+T.

因此,当给定了第一个相机坐标系中的3D点的坐标表示时,可以计算出该点在第二个相机坐标系中的坐标表示:
[ X 2 Y 2 Z 2 1 ] = [ R T 0 1 ] [ X 1 Y 1 Z 1 1 ] . \begin{bmatrix} X_2 \\ Y_2 \\ Z_2 \\ 1 \end{bmatrix} = \begin{bmatrix} R & T \\ 0 & 1 \end{bmatrix} \begin{bmatrix} X_1 \\ Y_1 \\ Z_1 \\ 1 \end{bmatrix}. X2Y2Z21 =[R0T1] X1Y1Z11 .

可选地,该函数还可以计算本质矩阵 E:

E = [ 0 − T 2 T 1 T 2 0 − T 0 − T 1 T 0 0 ] R E = \begin{bmatrix} 0 & -T_2 & T_1 \\ T_2 & 0 & -T_0 \\ -T_1 & T_0 & 0 \end{bmatrix} R E= 0T2−T1−T20T0T1−T00 R

其中 Ti 是平移向量 T 的分量: T = [ T 0 , T 1 , T 2 ] T T=[T_0, T_1, T_2]^T T=[T0,T1,T2]T 。而且,该函数还可以计算基础矩阵 F:

F = c a m e r a M a t r i x 2 − T ⋅ E ⋅ c a m e r a M a t r i x 1 − 1 F = cameraMatrix2^{-T}\cdot E \cdot cameraMatrix1^{-1} F=cameraMatrix2−T⋅E⋅cameraMatrix1−1

除了立体相关的信息外,该函数还可以对两个相机进行完整的标定。然而,由于参数空间的高维性和输入数据中的噪声,函数可能会偏离正确解。如果可以高精度地单独估计每个相机的内参(例如,使用 calibrateCamera),建议这样做并将 CALIB_FIX_INTRINSIC 标志传递给该函数,同时提供计算得到的内参。否则,如果所有参数一次性估计,限制某些参数是有意义的,例如传递 CALIB_SAME_FOCAL_LENGTH 和 CALIB_ZERO_TANGENT_DIST 标志,这通常是一个合理的假设。

类似于 calibrateCamera,该函数最小化来自两个相机所有可用视图的所有点的总重投影误差。函数返回最终的重投影误差值。

代码示例

cpp 复制代码
#include <iostream>
#include <opencv2/opencv.hpp>
#include <vector>

using namespace cv;
using namespace std;

int main()
{
    // 假设我们有以下数据
    vector< vector< Point3f > > objectPoints;  // 物体坐标空间中的3D点数组
    vector< vector< Point2f > > imagePoints1;  // 第一个相机的图像点数组
    vector< vector< Point2f > > imagePoints2;  // 第二个相机的图像点数组

    // 检查是否已经填充了足够的点
    if ( objectPoints.empty() || imagePoints1.empty() || imagePoints2.empty() )
    {
        cerr << "Error: No calibration points provided." << endl;
        return -1;
    }

    // 确保所有数组大小一致
    if ( objectPoints.size() != imagePoints1.size() || objectPoints.size() != imagePoints2.size() )
    {
        cerr << "Error: The number of object points, image points from camera 1, and image points from camera 2 do not match." << endl;
        return -1;
    }

    // 相机内参矩阵 (假设有初始估计)
    Mat cameraMatrix1 = ( Mat_< double >( 3, 3 ) << 520.9, 0, 325.1, 0, 521.0, 249.7, 0, 0, 1 );

    Mat cameraMatrix2 = ( Mat_< double >( 3, 3 ) << 520.9, 0, 325.1, 0, 521.0, 249.7, 0, 0, 1 );

    // 畸变系数 (假设有初始估计)
    Mat distCoeffs1 = Mat::zeros( 8, 1, CV_64F );  // 8参数模型
    Mat distCoeffs2 = Mat::zeros( 8, 1, CV_64F );  // 8参数模型

    // 图像尺寸
    Size imageSize( 640, 480 );

    // 输出变量
    Mat R, T, E, F;
    vector< Mat > rvecs, tvecs;
    vector< float > perViewErrors;

    // 标定标志和终止条件
    int flags = CALIB_FIX_INTRINSIC;
    TermCriteria criteria( TermCriteria::COUNT + TermCriteria::EPS, 30, 1e-6 );

    // 执行立体相机标定
    double rms = stereoCalibrate( objectPoints,   // 输入的物体点
                                  imagePoints1,   // 第一个相机的图像点
                                  imagePoints2,   // 第二个相机的图像点
                                  cameraMatrix1,  // 第一个相机的内参矩阵
                                  distCoeffs1,    // 第一个相机的畸变系数
                                  cameraMatrix2,  // 第二个相机的内参矩阵
                                  distCoeffs2,    // 第二个相机的畸变系数
                                  imageSize,      // 图像尺寸
                                  R,              // 输出的旋转矩阵
                                  T,              // 输出的平移向量
                                  E,              // 输出的本质矩阵
                                  F,              // 输出的基础矩阵
                                  rvecs,          // 每个视图的旋转向量
                                  tvecs,          // 每个视图的平移向量
                                  perViewErrors,  // 每个视图的重投影误差
                                  flags,          // 标定标志
                                  criteria        // 终止条件
    );

    cout << "RMS re-projection error: " << rms << endl;
    cout << "Rotation Matrix:\n" << R << endl;
    cout << "Translation Vector:\n" << T << endl;
    cout << "Essential Matrix:\n" << E << endl;
    cout << "Fundamental Matrix:\n" << F << endl;

    // 可选:打印每个视图的重投影误差
    for ( size_t i = 0; i < perViewErrors.size(); ++i )
    {
        cout << "Reprojection error for view " << i << ": " << perViewErrors[ i ] << endl;
    }

    return 0;
}

运行结果

数据提供了就会有运行结果

相关推荐
mirrornan7 小时前
3D可视化产品定制,应用于哪些行业领域?
3d·3d建模·3d模型·3d可视化
西猫雷婶10 小时前
python学opencv|读取图像(三十六)(反)零值处理
人工智能·opencv·计算机视觉
pchmi11 小时前
C# OpenCV机器视觉:图片去水印
opencv·计算机视觉·c#·机器视觉·opencvsharp
mirrornan13 小时前
Web3D交互展示:重塑产品展示的新维度
3d·web3·3d模型·web3d·3d展示·3d预览
xhload3d14 小时前
正泰电工×图扑软件:变电站数字孪生巡检平台
3d·智慧城市·html5·webgl·数字孪生·可视化·变电站·工业互联网·智慧电力·轻量化·电力能源·合作共赢
大哥喝阔落18 小时前
opencv_图像处理_去噪声_采用中值滤波
图像处理·opencv·计算机视觉
AI视觉网奇21 小时前
python 寻找数据拐点
开发语言·python·opencv
yzx9910131 天前
图像识别opencv翻转
开发语言·python·opencv
坐井观老天1 天前
使用 WPF 和 C# 绘制覆盖网格的 3D 表面
3d·c#·wpf