OpenCV双目视觉:Bouguet立体校正

  • 原创
  • |
  • 浏览:8040
  • |
  • 更新:

绪:

一个完整的双目视觉测量系统包括:图像采集、双目标定、立体校正、立体匹配和三维重建。

其中,立体校正是利用双目标定的内外参数对左右两个图像平面进行变换以达到同行共面的效果,减小了立体匹配的计算复杂度。

本经验目录:

Bouguet立体校正原理;

具体步骤;

重投影矩阵Q;

opencv函数介绍;

源码实现;

OpenCV双目视觉:Bouguet立体校正

工具/原料

  • VS2010
  • OpenCV2.4.10

方法/步骤

  1. 1

    Bouguet立体校正

    理想双目系统:两摄像机图像平面平行,光轴和图像平面平行。

    在相机标定步骤中,获得了右相机相对于左相机的旋转矩阵R和平移向量T。

    由于相机摆放的差异使偏离理想双目系统,因此需要进行立体校正。

    思想:通过建立左右相机的合成矩阵和行对准转换矩阵。

    校正过程如图所示:

    OpenCV双目视觉:Bouguet立体校正
  2. 1
    本页面非法爬取自百度经验
  3. 2

    具体步骤:

    (1)共面:将相机旋转矩阵R划分为左右相机的合成矩阵r1,rr,目的是实现图像平面共面。但是行没有对齐。

    (2)行对准:建立行对准换行矩阵Rrect使极点转换到无穷远处。

    Rrect的创建:

    OpenCV双目视觉:Bouguet立体校正
    OpenCV双目视觉:Bouguet立体校正
  4. 3

    重投影矩阵Q:

    是立体校正的输出矩阵,其实现了世界坐标系和图像像素坐标系之间的转换。

    非常重要,

    具体公式如下:

    OpenCV双目视觉:Bouguet立体校正
  5. 4

    opencv程序:

    opencv编写立体校正分三个过程:

    ①计算左右相机旋转矩阵R1R2和投影矩阵P1P2;

    ②计算校正查找映射表;

    ③校正两幅图像检验效果;

    opencv提供了stereoRectify()函数计算R1R2P1P2Q:

    【注】:相机畸变系数顺序为:k1,k2,p1,p2,k3

    OpenCV双目视觉:Bouguet立体校正
  6. 5

    计算校正查找映射表

    功能:将原图像和校正后图像上的点一一映射。

    opencv中提供initUndistortRectifyMap()函数

    【注】:分别对左右相机进行校正查找映射表。

    OpenCV双目视觉:Bouguet立体校正
  7. 6

    分析结果

    载入两张图片,校正后,将其画到一张图像上,并每个i行画一条直线,查看物体上的点在左右校正图像上的点是否在一条直线上。

    如果不在,校正失败:查看参数是否标定正确以及左右图像是否反了。

    如果在,校正成功。

    OpenCV双目视觉:Bouguet立体校正
  8. 7

    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;

    }

    OpenCV双目视觉:Bouguet立体校正
    END

注意事项

  • 【注】:相机畸变系数顺序为:k1,k2,p1,p2,k3
  • 【注】:分别对左右相机进行校正查找映射表。
  • 【注】:矩阵的数据类型,维数都有可能导致程序出错
经验内容仅供参考,如果您需解决具体问题(尤其法律、医学等领域),建议您详细咨询相关领域专业人士。
作者声明:本篇经验系本人依照真实经历原创,未经许可,谢绝转载。
展开阅读全部