操作注意事项
失败方案:
- matlab双目标定工具箱 + stereoRectify+initUndistortRectifyMap
- opencv双目标定 stereoCalibrate+ stereoRectify+initUndistortRectifyMap
经查发现stereoCalibrate需要初始相机内参以及畸变参数来进行迭代,故 - matlab双目标定工具箱的单目标定结果+stereoCalibrate+ stereoRectify+initUndistortRectifyMap,仍失败
成功方案:全在opencv上执行
左右相机均执行calibrateCamera+stereoCalibrate+stereoRectify+initUndistortRectifyMap
重要函数:calibrateCamera、stereoCalibrate、stereoRectify、initUndistortRectifyMap、remap
头文件:QDebug、string、vector、opencv2/opencv.hpp、fstream
操作:将左右相的图像分别放在标定路径下的left和right文件夹中,确保图像都能完全提取角点,,并均从0开始命名。执行完双目标定后,将输出的结果拷入极线校正部分的变量中(懒得写读数据的代码)
数据准备
//标定参数
int board_size = 10;//棋盘格尺寸,单位mm
cv::Size Boardsize = cv::Size(11,8);//棋盘格内角点个数
cv::Size ImgSize = cv::Size(1920,1200);//图像大小
int cal_num =21;//单个标定用图片张数
std::string cal_dir = "F://QTprojector//calibrate//0//";//标定板图片保存路径
双目标定
std::ofstream fout(cal_dir + "calibration_result.txt");
std::vector<cv::Point3f> worldpoint;
std::vector<std::vector<cv::Point3f>> worldpoints;
for(int i = 0;i < Boardsize.height;i++)
{
for(int j = 0;j < Boardsize.width; j++)
{
worldpoint.push_back(cv::Point3f(board_size*j,board_size*i,0.f));
}
}
std::vector<cv::Point2f> leftpoint;
std::vector<std::vector<cv::Point2f>> leftpoints;
for(int i = 0;i < cal_num;i++ )
{
cv::Mat src_l = cv::imread(cal_dir+"left//"+std::to_string(i)+".bmp",cv::IMREAD_GRAYSCALE);
cv::findChessboardCorners(src_l,Boardsize,leftpoint);
find4QuadCornerSubpix(src_l, leftpoint, cv::Size(5, 5));
leftpoints.push_back(leftpoint);
drawChessboardCorners(src_l, Boardsize, leftpoint, true);
cv::imwrite(cal_dir+"L_"+std::to_string(i)+".bmp",src_l);
leftpoint.clear();
src_l.release();
worldpoints.push_back(worldpoint);
}
qDebug()<< "左相机角点提取完成";
std::vector<cv::Point2f> rightpoint;
std::vector<std::vector<cv::Point2f>> rightpoints;
for(int i = 0;i < cal_num;i++ )
{
cv::Mat src_r = cv::imread(cal_dir+"right//"+std::to_string(i)+".bmp",cv::IMREAD_GRAYSCALE);
cv::findChessboardCorners(src_r,Boardsize,rightpoint);
find4QuadCornerSubpix(src_r, rightpoint, cv::Size(5, 5));
rightpoints.push_back(rightpoint);
drawChessboardCorners(src_r, Boardsize, rightpoint, true);
cv::imwrite(cal_dir+"R_"+std::to_string(i)+".bmp",src_r);
rightpoint.clear();
src_r.release();
}
qDebug()<< "右相机角点提取完成";
cv::Mat cl,dl,cr,dr,RM,TM,E,F,ERRO;
cv::Mat RVL,TVL,RVR,TVR;
//左相机标定
cv::calibrateCamera(worldpoints,leftpoints,ImgSize,cl,dl,RVL,TVL);
//右相机标定
cv::calibrateCamera(worldpoints,rightpoints,ImgSize,cr,dr,RVR,TVR);
//双目标定
cv::stereoCalibrate(worldpoints,leftpoints,rightpoints,cl,dl,cr,dr,ImgSize,RM,TM,E,F,ERRO,cv::CALIB_USE_INTRINSIC_GUESS);
qDebug()<< "read images finished. " ;
fout << "左相机内参\n";
fout << cl <<std::endl<<std::endl;
fout << "左相机畸变系数\n";
fout << dl.t() <<std::endl<<std::endl;
fout << "右相机内参\n";
fout << cr <<std::endl<<std::endl;
fout << "右相机畸变系数\n";
fout << dr.t() <<std::endl<<std::endl;
fout << "旋转矩阵\n";
fout << RM <<std::endl<<std::endl;
fout << "平移矩阵\n";
fout << TM <<std::endl<<std::endl;
fout << "本征矩阵\n";
fout << E <<std::endl<<std::endl;
fout << "基本矩阵\n";
fout << F <<std::endl<<std::endl;
fout << "标定误差\n";
fout << ERRO <<std::endl<<std::endl;
fout.close();
极线校正
//左相机内参
Klc = (cv::Mat_<double>(3, 3) << 2758.266244298792, 0, 964.3093188206248,
0, 2756.649721374597, 599.0685647176358,
0, 0, 1 );
//左相机畸变系数
dist_Lcamera = (cv::Mat_<double>(5, 1) << -0.1092895141220531,0.1709550981177383,0.0003496963629340831,-0.0002841358794049307,2.453078655573308 );
//右相机内参
Krc = (cv::Mat_<double>(3, 3) << 2752.979724475208, 0, 954.7456432806124,
0, 2752.176228996552, 584.5201879665763,
0, 0, 1);
//右相机畸变系数
dist_Rcamera = (cv::Mat_<double>(5, 1) << -0.1185467205680283,0.401784209533114, 0.0004741916057003427, 0.0001076136580291588, 1.010086196673059);
//两相机旋转矩阵
Rotate_L2R = (cv::Mat_<double>(3, 3) << 0.9582378966356847, 0.005803821522993841, 0.2859133594411915,
-0.006268375080149004, 0.9999801017619692, 0.0007096153721196322,
-0.2859035517881393, -0.002472192519003117, 0.9582552099201317 );
//两相机平移矩阵
Trans_L2R = (cv::Mat_<double>(3, 1) << -175.5406593037085,1.887640145490209,18.4933869297144);
//计算双目校正所用矩阵
cv::Mat RL,RR,PL,PR,Q;//左相机校正旋转矩阵,右相机校正旋转矩阵,左相机校正平移矩阵,右相机校正平移矩阵,Q深度映射矩阵
cv::stereoRectify(Klc,dist_Lcamera,Krc,dist_Rcamera,ImgSize,Rotate_L2R,Trans_L2R,RL,RR,PL,PR,Q, cv::CALIB_ZERO_DISPARITY);
qDebug()<< "计算双目校正所用矩阵 成功!";
//畸变校正
cv::Mat undistmap1l,undistmap2l,undistmap1r,undistmap2r;//左相机输出1/2映射,右相机输出1/2映射
initUndistortRectifyMap( Klc,dist_Lcamera, RL, PL, ImgSize, CV_32FC1, undistmap1l, undistmap2l );
initUndistortRectifyMap( Krc,dist_Rcamera, RR, PR, ImgSize, CV_32FC1, undistmap1r, undistmap2r );
cv::Mat dst_r,dst_l;
cv::Mat src_r = cv::imread(cal_dir+"right//8.bmp",cv::IMREAD_GRAYSCALE);
cv::Mat src_l = cv::imread(cal_dir + "left//8.bmp",cv::IMREAD_GRAYSCALE);
cv::remap(src_l,dst_l,undistmap1l,undistmap2l,cv::INTER_LINEAR);
cv::remap(src_r,dst_r,undistmap1r,undistmap2r,cv::INTER_LINEAR);
qDebug()<< "畸变校正 成功!";
//比较校正前后图像
cv::Mat res,ori;
cv::hconcat(dst_r,dst_l,res);
cv::hconcat(src_r,src_l,ori);
for(int i = 0;i<38;++i)
{
cv::line(res,cv::Point(0,50*i),cv::Point(3840,50*i),cv::Scalar(0));
cv::line(ori,cv::Point(0,50*i),cv::Point(3840,50*i),cv::Scalar(0));
}
cv::imwrite(cal_dir+"res.bmp",res);
cv::imwrite(cal_dir+"ori.bmp",ori);