opencv 双目立体视觉
单目标定
1.先单目标定每个相机,获得单个相机内参,外参,畸变参数。
双目标定
2.然后双面标定
2.1 stereoCalibrate (标定函数):
double stereoCalibrate(含世界坐标系的)objectPoints(左图像点)、imagePoints2(右图像点)、cameraMatrix1(可输出的)、distCoeffs1、cameraMatrix2、distCoeffs2、Size imageSize、OutputArray R(旋转)、T(平移)、E(本征矩阵)、F(基础矩阵),其中criteria设为TermCriteria(count=30, epsilon=1e-6),flags采用CALIB-fix_intrinsic
输入参数: 标定板上标定点的世界坐标数组,左相机对应的相应的像素点坐标数组,右相机对应的像素点坐标数组,左相机内参,畸变参数,右相机内参,右相机畸变参数
OutputArray R, // 两相机坐标系间的旋转矩阵
OutputArray T, // 两相机坐标系间的平移向量
OutputArray E, // 本质矩阵
OutputArray F, // 基本矩阵
2.2 stereoRectify (双目矫正函数):对标定过的摄像机进行校正
void stereoRectify(InputArray cameraMatrix1, InputArray distCoeffs1, InputArray cameraMatrix2, InputArray distCoeffs2, Size imageSize, InputArray R, InputArray T, OutputArray R1, OutputArray R2, OutputArray P1, OutputArray P2, OutputArray Q, int flags=CALIB_ZERO_DISPARITY, double alpha=-1, Size newImageSize=Size(), Rect* validPixROI1=0, Rect* validPixROI2=0 )
以下是输入内容
2.3 initUndistortRectifyMap:计算摄像机校正映射
void initUndistortRectifyMap( InputArray cameraMatrix, InputArray distCoeffs,
InputArray R, InputArray newCameraMatrix,
Size size, int m1type, OutputArray map1, OutputArray map2 );
函数功能:计算无畸变和修正转换映射。
参数说明:
cameraMatrix:输入相机矩阵
distCoeffs:输入参数,相机的畸变系数:,有4,5,8,12或14个元素。如果这个向量是空的,就认为是零畸变系数。
R:可选的修正变换矩阵,是个3*3的矩阵。通过stereoRectify计算得来的R1或R2可以放在这里。如果这个矩阵是空的,就假设为单位矩阵。在cvInitUndistortMap中,R被认为是单位矩阵。
newCameraMatrix:新的相机矩阵,通过stereoRectify计算得来的P1或P2可以放在这里
size:未畸变的图像尺寸。
m1type:第一个输出的映射的类型,可以为 CV_32FC1, CV_32FC2或CV_16SC2,参见cv::convertMaps。
map1:第一个输出映射。
map2:第二个输出映射。
2.4 remap:把一幅图像中某位置的像素放置到另一幅图像指定位置的过程
void remap( InputArray src, //源图像
OutputArray dst, //目标图像
InputArray map1,//第一个映射关系
InputArray map2, //第二个映射关系
int interpolation,//插值方法
int borderMode=BORDER_CONSTANT,//边界处理方式设置为BORDER_CONSTANT
const Scalar& borderValue=Scalar()//边界值设置为默认值Scalar()
)
双目标定例子
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 = c v::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);
在这里插入代码片
//计算双目校正所用矩阵
cv::Mat RL,RR,PL,PR,Q;//左相机校正旋转矩阵,右相机校正旋转矩阵,左相机校正平移矩阵,右相机校正平移矩阵,Q深度映射矩阵
cv::stereoRectify(cl,dl,cr,dr,ImgSize,RM,TM,RL,RR,PL,PR,Q, cv::CALIB_ZERO_DISPARITY);
qDebug()<< "计算双目校正所用矩阵 成功!";
//畸变校正
cv::Mat undistmap1l,undistmap2l,undistmap1r,undistmap2r;//左相机输出1/2映射,右相机输出1/2映射
initUndistortRectifyMap( CL,DL, RL, PL, ImgSize, CV_32FC1, undistmap1l, undistmap2l );
initUndistortRectifyMap( CR,DR, 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);
