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

server/2025/1/17 19:04:51/
  • 操作系统:ubuntu22.04
  • OpenCV版本:OpenCV4.9
  • IDE:Visual Studio Code
  • 编程语言:C++11

算法描述

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

函数原型

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= 0T2T1T20T0T1T00 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=cameraMatrix2TEcameraMatrix11

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

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

代码示例

#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;
}

运行结果

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


http://www.ppmy.cn/server/159161.html

相关文章

Python----Python爬虫(Scrapy的应用:CrawlSpider 使用,爬取小说,CrawlSpider版)

一、CrawlSpider 使用 1.1、CrawlSpider CrawSpiders 是 Scrapy 框架中的一个特殊爬虫类&#xff0c;它用于处理需要跟随链接并抓取多个页面的情况。相比于基本的 Spider 类&#xff0c;CrawSpiders 提供了一个更灵活、更强大的方式来定义爬取规则。 在Scrapy中Spider是所有爬…

[Effective C++]条款47 萃取器

本文初发于 “天目中云的小站”&#xff0c;同步转载于此。 条款47 : 请使用traits classes表现类型信息 traits classes(萃取器类), 如你所见萃取器其实是一个模板类, 在C中萃取器是一个神奇且有趣的存在, 它被广泛引用于标准库STL的编写中, 我们将在本条款中了解萃取器的功能…

设计模式-工厂模式/抽象工厂模式

工厂模式 定义 定义一个创建对象的接口&#xff0c;让子类决定实列化哪一个类&#xff0c;工厂模式使一个类的实例化延迟到其子类&#xff1b; 工厂方法模式是简单工厂模式的延伸。在工厂方法模式中&#xff0c;核心工厂类不在负责产品的创建&#xff0c;而是将具体的创建工作…

深入理解JavaScript闭包:原理、实践和优化

引言 在JavaScript中&#xff0c;闭包是一个非常重要的概念。它允许函数访问其外部作用域中的变量&#xff0c;即使这些变量在其定义的作用域之外。闭包的出现使得JavaScript能够实现许多高级功能&#xff0c;如模块封装、事件处理、异步编程等。然而&#xff0c;闭包的使用也…

长安“战疫”网络安全公益赛的一些随想

起因 今年刚进入大学&#xff0c;开始带校队&#xff0c;为了培养校队新成员&#xff0c;也就一直计划着和当地的一些高校合作交流&#xff0c;但是由于种种原因一直被搁置下来。正巧学校信息中心和四叶草有一个培训项目的合作&#xff0c;学校的网安协会也算是沾了光成为了培…

浏览器安全(同源策略及浏览器沙箱)

一、同源策略&#xff08;Same Origin Policy&#xff09; 1.定义 同源策略&#xff08;Same - origin Policy&#xff09;是一种浏览器的安全机制。它规定一个网页的脚本只能访问和操作与它同源的资源。这里的 “源” 包括协议&#xff08;如 http、https&#xff09;、域名&…

大数据组件常用端口(hdfs端口、hive端口、yarn端口)

1、不要记端口 用多了自然习惯了 为什么&#xff1f;因为端口没意义&#xff0c;只是映射一个地址而已&#xff0c;每套环境都可能有区别&#xff0c;比如CDH的8088&#xff0c;hadoop3的50070&#xff0c;腾讯的TBDS&#xff0c;华为&#xff0c;这些都不一样。 2、怎么去查…

Springboot项目启动优化详解

Springboot项目启动优化详解 目录 SpringBoot 简介项目启动优化详解 启动优化方案具体实现步骤 常见配置最佳实践 SpringBoot 简介 SpringBoot 是一个用于简化 Spring 应用开发的框架。它消除了设置 Spring 应用程序所需的复杂配置。 项目启动优化详解 启动优化方案 懒加…