说明
1、先calibrateCamera()
确定相机内参与畸变向量;再stereoCalirate()
确定右相机相对于左相机的R、T,本征矩阵E,基本矩阵F;再立体标定stereoRectify()
确定R1, R2, P1, P2, Q; 根据R1 , R2 重投影得到立体校正图像(共面行对齐);再使用StereoBM or StereoSGBM
计算Disparity ; 再reprojectImageTo3D()
得到视差图的所有三维坐标(单位为mm,这里Tx(两相机之间的基线距离是以mm为单位))
2、本征矩阵E,基本矩阵F的关系:本征矩阵包含了两个摄像机之间的所有几何信息,但不包含摄像机的任何信息,基本矩阵F在本征矩阵的基础上引入了两个相机的内参数信息;
1、本征矩阵E将左侧摄像机所观察到的点P的物理坐标位置与右侧摄像机所看到的
相同的点位置相关联起来;
2、基本矩阵F将图像坐标系(像素)中一个摄像机的像平面上的点与另一个摄像机
的像平面上的点关联起来;
3、立体标定函数stereoCalibrate()
原理:不要使用该函数一次性计算出所有参数,可能导致异常结果;
①使用calibrateCamera()
函数计算相机的内参数,畸变向量;
②根据如下图的关系,每幅图像对都可以计算出一对R、T;
③采用鲁棒的Levenberg-Marquardt迭代算法找到最小投影误差,计算出最佳R,T作为立体标定参数;
4、立体测量的数学原理:
5、三维深度的测量方法:测量三维坐标为(X/W , Y/W , Z/W);实现函数:reporjectImageTo3D()
;
Code
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace cv;
using namespace std;
void createCalibImg();
bool SingleCalib(string calibdata, string calibimgname, Size Pattern_size, int Square_size, int& imgNum,
Mat& CameraMatrix, Mat& DistCoeffs, vector<Mat>& Rvecs, vector<Mat>& Tvecs, double& totalerror,
vector<vector<Point3f>>& _objectPoints, vector<vector<Point2f>>& _imgPoints, Size& _image_size);
double Stereo_Calib_Quanlity_Check(vector<vector<Point2f>>& _leftimgPoints, int& leftimgNum, vector<vector<Point2f>>& _rightimgPoints, int& rightimgNum,
const Mat& leftCameraMatrix, const Mat& leftDistCoeffs, const Mat& _R1, const Mat& _P1,
const Mat& rightCameraMatrix, const Mat& rightDistCoeffs, const Mat& _R2, const Mat& _P2,
Mat& _F, Size _pattern_size);
int main(int argc, char** argv)
{
/*1.生成读取用的照片序列文件*/
//createCalibImg();
/*2.左右相机标定(内参矩阵、畸变向量)*/
Size board_size = Size(6, 9); //棋盘格行列角点数量
int square_size = 50; //棋盘格方块大小
int leftimgNum = 0, rightimgNum = 0;
Mat leftCamMatrix = Mat(3, 3, CV_32FC1, Scalar::all(0));
Mat rightCamMatrix = Mat(3, 3, CV_32FC1, Scalar::all(0));
Mat leftDistCoeffs = Mat(1, 5, CV_32FC1, Scalar::all(0));
Mat rightDistCoeffs = Mat(1, 5, CV_32FC1, Scalar::all(0));
vector<Mat> leftRvec, leftTvec;
vector<Mat> rightRvec, rightTvec;
vector<vector<Point3f>> leftobjPoints; //这些数据供第三步立体标定使用
vector<vector<Point3f>> rightobjPoints;
vector<vector<Point2f>> leftimgPoints;
vector<vector<Point2f>> rightimgPoints;
Size leftImgSize;
Size rightImgSize;
double leftTotalerror = 0.0, rightTotalerror = 0.0;
SingleCalib("calibimg.yaml", "leftimg", board_size, square_size, leftimgNum,
leftCamMatrix, leftDistCoeffs, leftRvec, leftTvec, leftTotalerror,leftobjPoints,leftimgPoints,leftImgSize); //左相机标定
SingleCalib("calibimg.yaml", "rightimg", board_size, square_size, rightimgNum,
rightCamMatrix, rightDistCoeffs, rightRvec, rightTvec, rightTotalerror,rightobjPoints,rightimgPoints, rightImgSize); //右相机标定
/*3.立体标定(右相机相对左相机的旋转矩阵与平移向量)*/
Mat R = Mat(3, 3, CV_32FC1, Scalar::all(0));
Mat T = Mat(3,1,CV_32FC1,Scalar::all(0));
Mat E = Mat(3, 3, CV_32FC1, Scalar::all(0)); //3 * 3 矩阵
Mat F = Mat(3, 3, CV_32FC1, Scalar::all(0));
stereoCalibrate(leftobjPoints, leftimgPoints, rightimgPoints, leftCamMatrix, leftDistCoeffs,
rightCamMatrix, rightDistCoeffs, leftImgSize, R, T, E, F, CALIB_FIX_INTRINSIC);
/*4.立体校正(Bougut算法)Calculate R1 R2 P1 P2 Q */
Mat R1, R2, P1, P2, Q;
stereoRectify(leftCamMatrix, leftDistCoeffs, rightCamMatrix, rightDistCoeffs, leftImgSize,
R, T, R1, R2, P1, P2, Q, CALIB_ZERO_DISPARITY); //立体校正,计算校正参数
//4.1 衡量立体校正效果
double Stereoerr = Stereo_Calib_Quanlity_Check(leftimgPoints, leftimgNum, rightimgPoints, rightimgNum, leftCamMatrix, leftDistCoeffs, R1, P1,
rightCamMatrix, rightDistCoeffs, R2, P2, F, board_size);
cout << "stereo calib quanlity:" << Stereoerr << endl;
Mat lmap1, lmap2;
Mat rmap1, rmap2;
initUndistortRectifyMap(leftCamMatrix, leftDistCoeffs, R1, P1, leftImgSize, CV_16SC2, lmap1, lmap2); //计算左相机视图矫正映射
initUndistortRectifyMap(rightCamMatrix, rightDistCoeffs, R2, P2, rightImgSize, CV_16SC2, rmap1, rmap2); //计算右相机视图矫正映射
//4.2 生成立体校正后的图像(共面行对准)
FileStorage fs2 = FileStorage("calibimg.yaml", FileStorage::READ);
FileNode leftimgSeq = fs2["leftimg"];
FileNode rightimgSeq = fs2["rightimg"];
FileNodeIterator lit = leftimgSeq.begin(), lit_end = leftimgSeq.end(); //在第5步中继续使用
FileNodeIterator rit = rightimgSeq.begin(), rit_end = rightimgSeq.end();
Mat lsrc, ldst,rsrc,rdst;
for (; lit != lit_end && rit != rit_end; lit++,rit++)
{
lsrc = imread((string)(*lit));
rsrc = imread((string)(*rit));
Mat s = Mat(lsrc.rows, (lsrc.cols * 2), CV_8UC3, Scalar(0, 0, 0));
Mat part1 = Mat(s, Rect(0, 0, lsrc.cols, lsrc.rows)); //浅复制
Mat part2 = Mat(s, Rect(lsrc.cols, 0, lsrc.cols, lsrc.rows));
remap(lsrc, ldst, lmap1, lmap2, INTER_LINEAR);
remap(rsrc, rdst, rmap1, rmap2, INTER_LINEAR);
resize(ldst, part1, part1.size(), 0, 0, INTER_LINEAR);
resize(rdst, part2, part2.size(), 0, 0, INTER_LINEAR);
Mat d = Mat(lsrc.rows, (lsrc.cols * 2), CV_8UC3, Scalar(0, 0, 0));
Mat dpart1 = d(Rect(0, 0, lsrc.cols, lsrc.rows));
Mat dpart2 = d(Rect(lsrc.cols, 0, lsrc.cols, lsrc.rows));
lsrc.copyTo(dpart1); rsrc.copyTo(dpart2);
for (int i = 0; i < lsrc.rows; i += 20)
{
line(s, Point(0, i), Point(s.cols, i), Scalar(0, 255, 0), 1); //绘制扫描线
line(d, Point(0, i), Point(s.cols, i), Scalar(0, 255, 0), 1); //绘制扫描线
}
imshow("原始图", d);
imshow("stereo rectify", s);
waitKey(0);
}
/*5.生成视差图(块匹配BM算法)*/
Ptr<StereoBM> bm = StereoBM::create();
bm->setBlockSize(15); //SAD窗口大小设置为15
bm->setNumDisparities(64); //搜寻的最大视差64
bm->setMinDisparity(0); //最小视差点
bm->setUniquenessRatio(10); //最佳匹配与第二好匹配之间的差异程度,取值一般在5-15之间
//以下参数不是很关键 ROI1与ROI2参数不用设置,因为stereoRectify()函数没有输出对应参数
bm->setDisp12MaxDiff(-1); //左视差图与右视差图最大的容许差异(默认-1)
bm->setPreFilterCap(31); //预过滤饱和度阈值
bm->setPreFilterSize(15); //NORMALIZED RESPONSE模式下预过滤窗口大小
bm->setPreFilterType(StereoBM::PREFILTER_NORMALIZED_RESPONSE); //只归一化窗口中的强度
bm->setSpeckleRange(32); //视差变化阈值(散斑阈值),当窗口内视差变化大于阈值时,该窗口内的视差清零
bm->setSpeckleWindowSize(200); //散斑窗口大小
bm->setTextureThreshold(10); //纹理阈值,保证有足够的纹理以克服噪声
//生成查看视差图
Mat dist,dist8U; //存储视差图(Disparity)
lit = leftimgSeq.begin(); //迭代器重新定位
rit = rightimgSeq.begin();
for (; lit != lit_end && rit != rit_end; lit++, rit++)
{
lsrc = imread((string)(*lit),IMREAD_GRAYSCALE); //注意BM算法只能处理灰度图
rsrc = imread((string)(*rit),IMREAD_GRAYSCALE);
bm->compute(lsrc, rsrc, dist); //dist为CV_16S格式
dist.convertTo(dist, CV_32F, 1.0 / 16); //除16得到真正的视差图
//归一化显示(imshow只能显示8位图)
dist8U = Mat(dist.size(), CV_8UC1);
normalize(dist, dist8U, 0, 255, NORM_MINMAX, CV_8UC1); //归一化
imshow("Disparity Image", dist8U);
waitKey(0);
}
/*6.三维重投影,计算左相机图像像素上每个像素点的三维坐标(reprojectImageTo3D())*/
Mat objxyz; //存储三维重投影计算得到的三维坐标
//vector<Mat> objxyz_set; //存储所有图像的三维计算坐标(输出),共有13幅图像
lit = leftimgSeq.begin(); //迭代器重新定位
rit = rightimgSeq.begin();
for (; lit != lit_end && rit != rit_end; lit++, rit++)
{
lsrc = imread((string)(*lit), IMREAD_GRAYSCALE); //注意BM算法只能处理灰度图
rsrc = imread((string)(*rit), IMREAD_GRAYSCALE);
bm->compute(lsrc, rsrc, dist); //dist为CV_16S格式
dist.convertTo(dist, CV_32F, 1.0 / 16); //除16得到真正的视差图
reprojectImageTo3D(dist, objxyz, Q, true); //三维重投影,objxyz默认是CV_32FC3类型,每个像素3个通道,存储摄像机坐标系下的三维坐标, 异常值对应的三维坐标将极大
//objxyz_set.push_back(objxyz);
cout << (string)(*lit) + " : "<< objxyz.at<Vec3f>(100,100) << endl << endl; //查看每幅图像坐标(100,100)处的计算三维坐标(单位为像素)
}
fs2.release(); //释放fs2
//保存所有数据
FileStorage fs1 = FileStorage("calibresult.yaml", FileStorage::WRITE);
fs1 << "leftCamMatrix" << leftCamMatrix;
fs1 << "leftDistCoeffs" << leftDistCoeffs;
fs1 << "leftTotalerror" << leftTotalerror;
fs1 << "rightCamMatrix" << rightCamMatrix;
fs1 << "rightDistCoeffs" << rightDistCoeffs;
fs1 << "rightTotalerror" << rightTotalerror;
fs1 << "Camera Rotation Matrix" << R;
fs1 << "Camera Translation Matrix" << T;
fs1 << "Essential Matrix" << E;
fs1 << "Fundamental Matrix" << F;
fs1 << "left rectification matrix" << R1;
fs1 << "right rectification matrix" << R2;
fs1 << "left Projection matrix" << P1;
fs1 << "right Projection matrix" << P2;
fs1 << "Q " << Q;
fs1 << "stereo calib error" << Stereoerr;
fs1.release();
return 0;
}
//生成用于读写的照片序列
void createCalibImg()
{
FileStorage fs = FileStorage("calibimg.yaml", FileStorage::WRITE);
fs << "leftimg" << "[";
fs << "left01.jpg" << "left02.jpg" << "left03.jpg" << "left04.jpg" << "left05.jpg"
<< "left06.jpg" << "left07.jpg" << "left08.jpg" << "left09.jpg" << "left11.jpg"
<< "left12.jpg" << "left13.jpg" << "left14.jpg";
fs << "]";
fs << "rightimg" << "[";
fs << "right01.jpg" << "right02.jpg" << "right03.jpg" << "right04.jpg" << "right05.jpg"
<< "right06.jpg" << "right07.jpg" << "right08.jpg" << "right09.jpg" << "right11.jpg"
<< "right12.jpg" << "right13.jpg" << "right14.jpg";
fs << "]";
fs.release();
std::cout << "文件写操作完成!请在工程目录下查看..." << endl;
}
/* 单个相机标定去畸变(求解内参矩阵、畸变向量) string calibdata yaml文件名(包含标定图像名) string calibimgname yaml文件中的序列名 Size Pattern_size 棋盘格行列角点数 int Square_size 棋盘格尺寸大小(默认宽高相同,单位mm) int& imgNum 返回处理图像数 Mat& CameraMatrix 输出相机内参矩阵 Mat& DistCoeffs 输出相机畸变向量 vector<Mat>& Rvecs 输出每幅图像的旋转向量(3*1) vector<Mat>& Tvecs 输出每幅图像的平移矩阵 double& totalerror 返回总体标定误差 vector<Point3f> _objectPoints 返回棋盘格三维坐标 vector<vector<Point2f>> _imgPoints 返回棋盘角点二维坐标(返回的是未校准的点) */
bool SingleCalib(string calibdata,string calibimgname, Size Pattern_size , int Square_size , int& imgNum,
Mat& CameraMatrix , Mat& DistCoeffs,vector<Mat>& Rvecs,vector<Mat>& Tvecs, double& totalerror,vector<vector<Point3f>>& _objectPoints,
vector<vector<Point2f>>& _imgPoints, Size& _image_size)
{
FileStorage fs(calibdata, FileStorage::READ); //打开文件
FileNode calibimg = fs[calibimgname]; //读取对应序列
if (calibimg.type() != FileNode::SEQ)
{
cerr << "error! input is not a sequence..." << endl;
return false;
}
FileNodeIterator it = calibimg.begin(), it_end = calibimg.end(); //创建迭代器
Size pattern_size = Pattern_size; //棋盘格行列角点数
Mat inputimg;
Mat grayimg;
vector<Point2f> corners; //存储一幅图像的棋盘角点数
vector<vector<Point2f>> corners_set; //存储所有图像的棋盘角点数
Size imagesize; //图像大小
int imgnum = 0; //标定图像数
namedWindow(calibimgname, CV_WINDOW_AUTOSIZE); //创建一个窗体
for (; it != it_end; it++)
{
imgnum++; //标定图像计数
inputimg = imread((string)(*it), IMREAD_COLOR); //读入图像
cvtColor(inputimg, grayimg, CV_BGR2GRAY);
if (calibimg.begin() == it) //读入第一张图片时保存图片大小
{
imagesize.width = inputimg.cols;
imagesize.height = inputimg.rows;
}
if (false == findChessboardCorners(grayimg, pattern_size, corners))
{
//如果没有找到所有角点,则报错
cerr << "没有检测到所有角点:" << (string)(*it) << endl;
continue;
}
else
{
find4QuadCornerSubpix(grayimg, corners, Size(11, 11)); //亚像素级精确化角点坐标
corners_set.push_back(corners); //存储每幅图像的角点
drawChessboardCorners(inputimg, pattern_size, corners, true); //绘制角点,棋盘上所有角点均被找到
imshow(calibimgname , inputimg); //显示一下
waitKey(100);
}
}
destroyWindow(calibimgname); //显示完毕后销毁窗口
fs.release(); //读取完毕释放文件
std::cout << imgnum << endl;
int squaresize = Square_size; //棋盘格尺寸大小
vector<vector<Point3f>> objectpoints; //存储所有棋盘格的空间坐标
//设置棋盘格坐标objectpoints
for (int count = 0; count < imgnum; count++)
{
vector<Point3f> temppoint;
for (int i = 0; i < pattern_size.height; i++)
{
for (int j = 0; j < pattern_size.width; j++)
{
Point3f realPoint;
realPoint.x = j * squaresize; //还是觉得应该是先j后i
realPoint.y = i * squaresize;
realPoint.z = 0; //棋盘格Z轴为0
temppoint.push_back(realPoint); //存储一幅图像中所有坐标
}
}
objectpoints.push_back(temppoint); //存储所有棋盘点坐标
}
//相机标定
Mat cameraMatrix = Mat(3, 3, CV_32FC1, Scalar::all(0));
Mat distCoeffs = Mat(1, 5, CV_32FC1, Scalar::all(0));
vector<Mat> rvecs; //存储所有图片相对于摄像机坐标系的旋转向量(3 * 1)
vector<Mat> tvecs; //存储所有图片相对于摄像机坐标系的平移向量
cv::calibrateCamera(objectpoints,corners_set,imagesize,cameraMatrix,distCoeffs,rvecs,tvecs,0); //没给定的值使用默认值
//vector<Mat> rvecs_trans(rvecs.size()); //存储转换后的旋转矩阵(3 * 3)
/*for (int i = 0; i < rvecs.size(); i++) { Rodrigues(rvecs[i], rvecs_trans[i]); }*/
//相机标定结果评价
double err = 0.0;
double total_err = 0.0;
vector<Point3f> objecttemp;
vector<Point2f> imagetemp;
vector<Point2f> projectionpoints;
for (int i = 0; i < imgnum; i++)
{
objecttemp = objectpoints[i]; //读取一幅图像的棋盘点
projectPoints(objecttemp, rvecs[i], tvecs[i], cameraMatrix, distCoeffs,projectionpoints); //计算反向投影点
imagetemp = corners_set[i]; //读取对应图像的角点
/*计算投影误差*/
Mat proobj = Mat(1, projectionpoints.size(), CV_32FC2); //注意是32位2通道,注意是重投影后图像坐标点的大小
Mat img = Mat(1, imagetemp.size(), CV_32FC2);
for (int j = 0; j < imagetemp.size(); j++) //写入数据
{
proobj.at<Vec2f>(0, j) = Vec2f(projectionpoints[j].x, projectionpoints[j].y);//注意填充的一定是重投影的图像点
img.at<Vec2f>(0, j) = Vec2f(imagetemp[j].x, imagetemp[j].y);
}
err = norm(proobj, img, NORM_L2); //矩阵范数运算
total_err += (err /= (pattern_size.width * pattern_size.height));
}
total_err = (total_err / imgnum);
std::cout << total_err << endl;
//返回计算参数
CameraMatrix = cameraMatrix;
DistCoeffs = distCoeffs;
Rvecs = rvecs;
Tvecs = tvecs;
totalerror = total_err;
imgNum = imgnum;
_objectPoints = objectpoints; //返回所有棋盘空间坐标点供下一步使用
_imgPoints = corners_set; //返回所有棋盘图像坐标点供下一步使用
_image_size = imagesize; //返回图像大小
return true;
}
/*衡量立体校正效果 vector<vector<Point2f>>& _leftimgPoints 去畸变的左相机视图角点集合 int& leftimgNum 左相机总视图数 vector<vector<Point2f>>& _rightimgPoints 去畸变的右相机视图角点集合 int& rightimgNum 右相机总视图数 Mat& _F 基本矩阵 Size _pattern_size 每行列棋盘点数 返回值 左右视图每个点到极线的平均偏移距离 */
double Stereo_Calib_Quanlity_Check(vector<vector<Point2f>>& _leftimgPoints, int& leftimgNum, vector<vector<Point2f>>& _rightimgPoints, int& rightimgNum,
const Mat& leftCameraMatrix, const Mat& leftDistCoeffs, const Mat& _R1 , const Mat& _P1,
const Mat& rightCameraMatrix, const Mat& rightDistCoeffs, const Mat& _R2, const Mat& _P2,
Mat& _F, Size _pattern_size)
{
double err = 0.0, totalerr = 0.0;
int board_n = (_pattern_size.width * _pattern_size.height); //每幅图像总的角点数
float a, b, c;
float x, y;
vector<Point2f> rimg,limg;
Mat leftLine = Mat(1, board_n, CV_32FC3, Scalar::all(0)); //存储左相机每一幅图像的极线
Mat rightLine = Mat(1, board_n, CV_32FC3, Scalar::all(0)); //存储右相机每一幅图像的极线
/* 极线存储还有另一种更好的方式: vector<Point3f> leftLine; //(三维坐标x,y,z分别代表a,b,c) vector<Point3f> rightLine; */
vector<vector<Point2f>> leftPoints; //存储校正后的图像点集
vector<vector<Point2f>> rightPoints;
vector<Point2f> tempPoint;
for (int i = 0; i < _leftimgPoints.size(); i++)
{
undistortPoints(_leftimgPoints[i], tempPoint, leftCameraMatrix, leftDistCoeffs,Mat(),leftCameraMatrix); //去畸变处理
leftPoints.push_back(tempPoint); //保存相关点
}
for (int i = 0; i < _rightimgPoints.size(); i++)
{
undistortPoints(_rightimgPoints[i], tempPoint, rightCameraMatrix, rightDistCoeffs,Mat(),rightCameraMatrix);
rightPoints.push_back(tempPoint);
}
//计算左相机图像点与极线距离
for (int i = 0; i < rightimgNum; i++)
{
rimg = rightPoints[i]; //注意 使用右相机图像计算的才是左相机内的极线
limg = leftPoints[i];
computeCorrespondEpilines(rimg, 2, _F, leftLine); //计算左相机视图中的极线
float* l_temp = (float*)leftLine.ptr(0); //获取行指针
for (int j = 0; j < board_n; j++) //这里实际上一共是54条极线
{
a = (*l_temp); //极线值
b = (*(l_temp + 1));
c = (*(l_temp + 2));
l_temp += 3; //更新指针的位置
x = limg[j].x; //左相机图像去畸变的点
y = limg[j].y;
err = fabs(a * x + b * y + c) / sqrt(a * a + b * b); //点到直线的距离公式
cout << "left: " << err << endl;
totalerr += err;
}
}
//计算右相机图像点与极线距离
for (int i = 0; i < leftimgNum; i++)
{
rimg = rightPoints[i]; //注意 使用左相机图像计算的才是右相机内的极线
limg = leftPoints[i];
computeCorrespondEpilines(limg, 1, _F, rightLine); //计算右相机视图中的极线
float * r_temp = (float*)rightLine.ptr(0); //定位到矩阵头
for (int j = 0; j < board_n; j++) //计算每个点到极线的距离
{
a = *r_temp;
b = *(r_temp + 1);
c = *(r_temp + 2);
r_temp += 3;
x = rimg[j].x;
y = rimg[j].y;
err = fabs(a * x + b * y + c) / sqrt(a * a + b * b);//点到直线的距离公式
cout << "right: " << err << endl;
totalerr += err;
}
}
totalerr /= (2 * leftimgNum * board_n); //求取每个点到极线的平均偏移距离
return totalerr;
}
效果
1、绘制角点:
2、未校正的图像:
3、立体校正的共面行对准图像:
4、视差图(CV_8UC1):
5、左相机每幅图像(350,170)像素处测量的三维坐标,Z值为10000代表测量失败,只有left01.jpg、left05.jpg深度测量成功;
6、立体校正偏移误差:0.344624像素(共面行对准)
7、保存的文件:
%YAML:1.0
---
leftCamMatrix: !!opencv-matrix
rows: 3
cols: 3
dt: d
data: [ 5.3172114589370665e+02, 0., 3.4059397869967120e+02, 0.,
5.3165275202126293e+02, 2.3218163956721483e+02, 0., 0., 1. ]
leftDistCoeffs: !!opencv-matrix
rows: 1
cols: 5
dt: d
data: [ -2.6496241080749372e-01, -6.1791447271371112e-02,
7.4441869557696826e-04, -6.7734037466286705e-04,
3.5892739140212027e-01 ]
leftTotalerror: 5.8422314361454647e-02
rightCamMatrix: !!opencv-matrix
rows: 3
cols: 3
dt: d
data: [ 5.3707652474832639e+02, 0., 3.2446264774840478e+02, 0.,
5.3688888158513885e+02, 2.4813174334653809e+02, 0., 0., 1. ]
rightDistCoeffs: !!opencv-matrix
rows: 1
cols: 5
dt: d
data: [ -2.9752913190311114e-01, 1.5768191747141277e-01,
-6.4179876358640912e-04, -1.2016815825458044e-04,
-7.8165194533429322e-02 ]
rightTotalerror: 5.9504322884020584e-02
Camera Rotation Matrix: !!opencv-matrix
rows: 3
cols: 3
dt: d
data: [ 9.9997369979298278e-01, 3.7417641627110268e-03,
6.2128031744264536e-03, -3.6870887231558363e-03,
9.9995458103248225e-01, -8.7887000688689539e-03,
-6.2454062382753806e-03, 8.7655617677141213e-03,
9.9994207823644232e-01 ]
Camera Translation Matrix: !!opencv-matrix
rows: 3
cols: 1
dt: d
data: [ -1.6648015327782122e+02, 1.9779789412307625e+00,
2.7109730298627279e+00 ]
Essential Matrix: !!opencv-matrix
rows: 3
cols: 3
dt: d
data: [ -2.3576839315534621e-03, -2.6935118036821470e+00,
2.0016903020564629e+00, 1.6711655428804784e+00,
1.4694358883844729e+00, 1.6648735319559174e+02,
-1.3640998241952227e+00, -1.6647999305186403e+02,
1.4508553407330742e+00 ]
Fundamental Matrix: !!opencv-matrix
rows: 3
cols: 3
dt: d
data: [ 2.7112467616625021e-09, 3.0978344954601152e-06,
-1.9441354262530049e-03, -1.9224484139607071e-06,
-1.6906033714389786e-06, -1.0078848076102437e-01,
1.3186327782052762e-03, 1.0224855455965888e-01, 1. ]
left rectification matrix: !!opencv-matrix
rows: 3
cols: 3
dt: d
data: [ 9.9991607855733788e-01, -8.2799227516537500e-03,
-9.9638708212500676e-03, 8.2361509727174598e-03,
9.9995628680007076e-01, -4.4260937822668822e-03,
1.0000082983181544e-02, 4.3436583937348523e-03,
9.9994056371970830e-01 ]
right rectification matrix: !!opencv-matrix
rows: 3
cols: 3
dt: d
data: [ 9.9979689547098194e-01, -1.1878756511288764e-02,
-1.6280753985364708e-02, 1.1950036508966637e-02,
9.9991940200931673e-01, 4.2879030731850926e-03,
1.6228506832756312e-02, -4.4815877851695426e-03,
9.9985826542410650e-01 ]
left Projection matrix: !!opencv-matrix
rows: 3
cols: 4
dt: d
data: [ 5.3427081680320089e+02, 0., 3.4392805862426758e+02, 0., 0.,
5.3427081680320089e+02, 2.4199363708496094e+02, 0., 0., 0., 1.,
0. ]
right Projection matrix: !!opencv-matrix
rows: 3
cols: 4
dt: d
data: [ 5.3427081680320089e+02, 0., 3.4392805862426758e+02,
-8.8963556374480846e+04, 0., 5.3427081680320089e+02,
2.4199363708496094e+02, 0., 0., 0., 1., 0. ]
Q : !!opencv-matrix
rows: 4
cols: 4
dt: d
data: [ 1., 0., 0., -3.4392805862426758e+02, 0., 1., 0.,
-2.4199363708496094e+02, 0., 0., 0., 5.3427081680320089e+02, 0.,
0., 6.0055020120177681e-03, 0. ]
stereo calib error: 3.4462384683656455e-01
参考
1、https://blog.csdn.net/xuxunjie147/article/details/79219774
2、https://blog.csdn.net/lijiayu2015/article/details/53079661
3、https://www.cnblogs.com/polly333/p/5130375.html
4、Learning OpenCV3