【双目标定+极线校正】opencv&C++(stereoCalibrate + stereoRectify)

该文详细介绍了如何使用OpenCV库进行双摄像头的标定和极线校正过程,包括calibrateCamera函数用于单个相机标定,stereoCalibrate进行双目标定,stereoRectify和initUndistortRectifyMap进行畸变校正,最后通过remap函数实现图像的畸变矫正。整个流程强调了正确提取角点和配置参数的重要性。
摘要由CSDN通过智能技术生成

操作注意事项

失败方案:

  1. matlab双目标定工具箱 + stereoRectify+initUndistortRectifyMap
  2. opencv双目标定 stereoCalibrate+ stereoRectify+initUndistortRectifyMap
    经查发现stereoCalibrate需要初始相机内参以及畸变参数来进行迭代,故
  3. 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);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值