标定立体相机设置。此函数找到两个相机各自的内参以及两个相机之间的外参。
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)
)
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,该函数最小化来自两个相机所有可用视图的所有点的总重投影误差。函数返回最终的重投影误差值。
#include
#include
#include
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;
}
数据提供了就会有运行结果