OpenCV双目视觉:Bouguet立体校正
- 原创
- |
- 浏览:8040
- |
- 更新:
方法/步骤
Bouguet立体校正
理想双目系统:两摄像机图像平面平行,光轴和图像平面平行。
在相机标定步骤中,获得了右相机相对于左相机的旋转矩阵R和平移向量T。
由于相机摆放的差异使偏离理想双目系统,因此需要进行立体校正。
思想:通过建立左右相机的合成矩阵和行对准转换矩阵。
校正过程如图所示:
- 本页面非法爬取自百度经验
具体步骤:
(1)共面:将相机旋转矩阵R划分为左右相机的合成矩阵r1,rr,目的是实现图像平面共面。但是行没有对齐。
(2)行对准:建立行对准换行矩阵Rrect使极点转换到无穷远处。
Rrect的创建:
重投影矩阵Q:
是立体校正的输出矩阵,其实现了世界坐标系和图像像素坐标系之间的转换。
非常重要,
具体公式如下:
opencv程序:
opencv编写立体校正分三个过程:
①计算左右相机旋转矩阵R1R2和投影矩阵P1P2;
②计算校正查找映射表;
③校正两幅图像检验效果;
opencv提供了stereoRectify()函数计算R1R2P1P2Q:
【注】:相机畸变系数顺序为:k1,k2,p1,p2,k3
计算校正查找映射表
功能:将原图像和校正后图像上的点一一映射。
opencv中提供initUndistortRectifyMap()函数
【注】:分别对左右相机进行校正查找映射表。
分析结果
载入两张图片,校正后,将其画到一张图像上,并每个i行画一条直线,查看物体上的点在左右校正图像上的点是否在一条直线上。
如果不在,校正失败:查看参数是否标定正确以及左右图像是否反了。
如果在,校正成功。
opencv校正完整源码:
/********************************************************************
创建 : 2017/1/16
文件 : StereoRectify.cpp
类名 : StereoCalib
功能 : 摄像机立体矫正
*********************************************************************/
#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <iostream>
#include <opencv2/calib3d/calib3d.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
int main()
{
Mat img1=imread("..\\..\\待校正图像\\right04.jpg"),imgLr;
Mat img2=imread("..\\..\\待校正图像\\left04.jpg"),imgRr;
Mat M1,D1,M2,D2,R,T;
FileStorage fs_0("data\\M1.xml", FileStorage::READ);//②读取xml格式的标定参数文件,
FileStorage fs_1("data\\D1.xml", FileStorage::READ);
FileStorage fs_2("data\\M2.xml", FileStorage::READ);
FileStorage fs_3("data\\D2.xml", FileStorage::READ);
FileStorage fs_4("data\\R.xml", FileStorage::READ);
FileStorage fs_5("data\\T.xml", FileStorage::READ);
fs_0["camereMatrix_left_1"] >> M1;//相机参数,畸变系数,旋转矩阵,平移向量
fs_1["distCoffs_left_1"] >> D1;//k1,k2,p1,p2,k3
fs_2["camereMatrix_right_1"] >> M2;
fs_3["distCoffs_right_1"] >> D2;
fs_4["Rotation_1"] >> R;//3*3
fs_5["T_1"] >> T;
cout<<"M1: "<<M1<<"\n"
<<"M2: "<<M2<<"\n"
<<"D1: "<<D1<<"\n"
<<"D2: "<<D2<<"\n"
<<"R: "<<R<<"\n"
<<"T: "<<T<<"\n"
<<endl;
//校正之前,把om变为3*3;
//Mat m_Rotation;
//Rodrigues(R,m_Rotation);//注:matlab标定的参数中R为3*1,转换成3*3形式;
Size imageSize=img1.size();//图片尺寸
Mat R1,R2,P1,P2,Q;
double alpha=-1;
if (alpha < 0 || alpha > 1)//裁剪系数,阈值
alpha = -1;
Rect roi1,roi2;//感兴趣区域
stereoRectify(
M1,
D1,
M2,
D2,
imageSize,//图片尺寸
R,
T,
R1,//输出左相机的旋转矩阵
R2,//输出右相机的旋转矩阵
P1,//左投影矩阵
P2,//右投影矩阵
Q, //重投影矩阵
0//CALIB_ZERO_DISPARITY ,//主点坐标相同
//-1,//裁剪系数
//imageSize,
//&roi1,
//&roi2
);//③:执行双目校正
FileStorage fs_6("Q.xml",FileStorage::WRITE);//保存Q阵
fs_6<<"Q"<<Q;
fs_6.release();
cout<<"Q: "<<Q<<"\n"<<endl;
Mat remapmX1= Mat(imageSize,CV_32FC1);
Mat remapmY1= Mat(imageSize,CV_32FC1);
Mat remapmX2= Mat(imageSize,CV_32FC1);
Mat remapmY2= Mat(imageSize,CV_32FC1);
initUndistortRectifyMap(M1, //
D1,//
R1,//
P1,//
imageSize,
CV_16SC2,
remapmX1,
remapmY1
); //④计算校正查找映射表,分别求映射矩阵
initUndistortRectifyMap(M2, //
D2, //
R2, //
P2, //
imageSize,
CV_16SC2,
remapmX2,
remapmY2
);
if ( !remapmX1.empty() && !remapmY1.empty() )//⑤进行矫正,映射
{
remap( img1, imgLr, remapmX1, remapmY1, INTER_LINEAR );
}
if ( !remapmX2.empty() && !remapmY2.empty() )
{
remap( img2, imgRr, remapmX2, remapmY2, INTER_LINEAR );
}
imshow("imgLr",imgLr);
imshow("imgRr",imgRr);
imwrite("imgLr.png",imgLr);
imwrite("imgRr.png",imgRr);//保存图片
Mat img(imageSize.height*0.5, imageSize.width, CV_8UC3);//⑥创建IMG,高度一样,宽度双倍
Mat imgPart1 = img( Rect(0, 0, imageSize.width*0.5, imageSize.height*0.5) );//浅拷贝
Mat imgPart2 = img( Rect(imageSize.width*0.5, 0, imageSize.width*0.5, imageSize.height*0.5) );//浅拷贝
resize(imgLr, imgPart1, imgPart1.size(), 0, 0, CV_INTER_AREA);
resize(imgRr, imgPart2, imgPart2.size(), 0, 0, CV_INTER_AREA);//改变图像尺寸,调节0,0;
for( int i = 0; i < img.rows; i += 16 ) //画横线
line(img, Point(0, i), Point(img.cols, i), Scalar(0, 255, 0), 1, 8);
imshow("rectified", img);
imwrite("ret.png",img);
waitKey();
return 0;
}
END















