精华内容
下载资源
问答
  • 相机标定

    2018-01-31 21:30:16
    我们首先的工作就是标定它,怎么标定呢? 通过拍照程序给它拍几张照片,利用张正友标定标定相机的内外参数。 标定好相机之后我们用扫地机放在一个标定环境下进行录数据,看看录的照片怎么样,如果照片可以,...

    刚刚相机标定完,趁热打铁,复习一波。

    首先我们选择的是这款相机

    我们首先做的工作就是标定它,怎么标定呢?

    通过拍照程序给它拍几张照片,利用张正友标定法标定相机的内外参数。

    标定好相机之后我们用扫地机放在一个标定环境下进行录数据,看看录的照片怎么样,如果照片可以,直接用。

    标记三个点(左右前),用我们已经标定好的相机进行拍摄,根据PNP原理计算出相机的R,T。

    展开全文
  • 毕业设计了相机标定相关的工作,想着把理论和实现方法总结一下发出来,算是个记录,如果能帮助到有需要的人就更好了。 提前说明,这篇文章主要是将我的本科毕业论文中的相关部分进行提取、修改的结果,文中公式...
    毕业设计做了相机标定相关的工作,想着把理论和实现方法总结一下发出来,算是个记录,如果能帮助到有需要的人就更好了。
    

    提前说明,这篇文章主要是将我的本科毕业论文中的相关部分进行提取、修改的结果,文中公式采用截图的方式给出(不知道怎么用公式编辑器…),所以对应的公式号与章节号可能不符,读者请注意。

    摘要

    本文使用的方法是张正友的相机标定法

    Z. Zhang, “A flexible new technique for camera calibration,” in IEEE Transactions on Pattern Analysis and Machine Intelligence, vol. 22, no. 11, pp. 1330-1334, Nov. 2000.

    相机标定是整个标定过程的前提,其目的是为了得到相机的内参数外参数,内参数包括相机的焦距、镜头畸变参数、主点等信息,外参数包括像素坐标系相对于世界坐标系的旋转、平移矩阵。通过相机标定,我们可以知道像素坐标系与世界坐标系直接的转换关系,也就是要求的单应性矩阵,通过相机标定我们可以知道的是,在图像上看到的物体在实际中相对相机坐标系的位姿。

    1、相机标定各坐标系的介绍

    相机标定中共4个坐标系:世界坐标系(x_w,y_w,z_w)、相机坐标系(x_c,y_c,z_c)、图像坐标系(x,y)、像素坐标系(u,v)。
    各坐标系对应位置关系如图1所示。
    相机标定各坐标系
    世界坐标系(x_w,y_w,z_w):在真实世界中的坐标系,相机标定中所选用的世界坐标系通常是以标定板所在平面为坐标系的XoY面。
    相机坐标系(x_c,y_c,z_c):相机所在的坐标系,用于描述相机的位姿状态,在相机标定中通常用于连接世界坐标系与图像坐标系。
    图像坐标系(x_p,y_p):即相机传感器所在的坐标系,用于描述物体在成像过程中的投射关系,在相机标定中用于连接相机坐标系与像素坐标系。
    像素坐标系(u,v):是我们在屏幕上所看到的图片所在的坐标系,在相机标定中用于直观的展示物体的位姿信息。

    2、各坐标系之间的齐次坐标转换

    本文采用张正友相机标定法[2],该方法将上文介绍的不同坐标系之间的关系转换为矩阵相乘的形式,最终得到世界坐标系与像素坐标系之间的对应关系,即单应性矩阵。坐标系之间的转换分为以下几个步骤,分别是:(1)世界坐标系与相机坐标系之间的转换;(2) 相机坐标系与图像坐标系之间的转换;(3) 图像坐标系与像素坐标系之间的转换;(4)内参矩阵的求解;(5)单应性矩阵的求解,将上述几个个转换关系和计算过程进行结合就得到像素坐标系与世界坐标系之间的转换关系,也就是说可以从相机捕捉到的图片中推导出物体在三维世界中的位置信息。下面将一一介绍这几个关系转换的推导步骤。

    2.1、世界坐标系与相机坐标系之间的转换

    在相机标定中,通常使用旋转矩阵和平移向量来表示物体在世界坐标系下与相机坐标系的相对位姿关系,即:
    在这里插入图片描述

    在上述公式中,为了计算方便,假设标定板所在平面为世界坐标系的XOY平面,即世界坐标系的Z=0。而变换矩阵[R33 T31](第二条等式左边的矩阵)就是外参矩阵。

    2.2、相机坐标系与图像坐标系之间的转换

    该变换过程将被摄物体从三维坐标转换至二维坐标,所用到的原理是投影透视原理。

    假设相机坐标系中有一点C(x_c,y_c,z_c),则在理想图像坐标系下(无畸变)的成像点P(x_p,y_p)的坐标为:

    在这里插入图片描述

    将上式转换为矩阵形式,得:
    在这里插入图片描述

    其中f为相机的焦距。

    2.3、图像坐标系与像素坐标系之间的转换

    由于像素坐标系原点与图像坐标系原点不重合,假设图像坐标系原点在像素坐标系下的坐标为 (u_0,v_0),每个像素点在图像坐标系x轴、y轴方向的尺寸为:dx、dy,且像点在图像坐标系下的坐标为(x_p,y_p),于是可得到像点在像素坐标系下的坐标为:

    在这里插入图片描述
    转换为矩阵形式:
    在这里插入图片描述

    2.4、内参矩阵的求解

    将3式与5式相乘,得到内参矩阵:
    在这里插入图片描述
    其中,
    在这里插入图片描述
    综上所述,可得像素坐标系与世界坐标系的转换关系,即:
    在这里插入图片描述

    其中
    (u,v)为像素坐标,可从图片中获取;
    (x_w,y_w)为世界坐标系下的坐标,在相机标定中即为标定棋盘角点的坐标;
    s为尺度因子,无实际意义,仅用于方便计算,u_0、v_0、r_1、r_2、t、γ为待求量。

    2.5、单应性矩阵的求解

    单应性矩阵用于描述物体在世界坐标系下的位姿与像素坐标系的位姿的相对关系,通过上述的推导,可以将单应性矩阵表示如下:
    在这里插入图片描述
    则式(2.7)可表示为:
    在这里插入图片描述

    在这里插入图片描述
    其中h_33为齐次坐标,值为1。则在H矩阵中有8个未知量,对于世界坐标系和像素坐标系中的一对点(x_w,y_w) 和(u,v),由可知式(2.9)存在两个方程,则至少需要4对点就可以求出H矩阵中的全部值。

    3、相机内外参数求解

    在上文中已经求解出H矩阵,接下来就要分别求解内参矩阵和外参矩阵。在张正友相机标定中使用的方法为先求解内参矩阵,再代入H矩阵求解外参矩阵。具体方法如下。

    3.1、求解内参矩阵

    首先令
    在这里插入图片描述
    则可得关于h的方程组:
    在这里插入图片描述
    方程组(2.12)可转换为关于r的方程组:
    在这里插入图片描述
    关于上式可得出两个约束条件:
    r_1与r_2正交。
    r_1与r_2的模相等。
    即:
    在这里插入图片描述

    在这里插入图片描述
    从矩阵中可以看出,B为对称矩阵,因此共有6个未知数。令这六个未知数构成向量b:
    在这里插入图片描述
    对式(2.14)做进一步化简:
    在这里插入图片描述
    其中
    在这里插入图片描述
    于是,可将两个约束条件表示为矩阵的形式:
    在这里插入图片描述
    对于式(2.20)中系数矩阵中的值已在求单应性矩阵时得到,所以仅需求b中六个未知数。

    对于一张图片可得一组式(2.20)表示的矩阵,若要求b中6个参数,则至少需要3张图片。

    在求解出b向量后将数据带入B矩阵,再用cholesky分解得内参矩阵A。

    3.2、基于内参矩阵求解外参矩阵

    由式(2.12)可得外参矩阵各参数的求解公式:
    在这里插入图片描述
    其中
    在这里插入图片描述
    至此,已经完成了相机标定的初始参数求解部分。

    4、基于极大似然估计求解畸变参数

    4.1、极大似然估计

    在上述部分已经求得了相机的初始参数,接下来将求得的参数带入似然函数对所求得的参数进行优化,使得参数更接近真实值,似然函数如下:
    在这里插入图片描述
    再结合L-M算法即可求得最优参数。

    4.2、径向畸变处理

    相机的畸变主要包括径向畸变与切向畸变,在张正友相机标定法中仅考虑径向畸变,因此在本文中也只进行径向畸变处理。
    假设(u,v)为理想像素坐标系下的坐标,(u ̅,v ̅)为实际像素坐标系下的坐标,(x,y)为理想图像坐标系下的坐标,(x ̅,y ̅)为实际图像坐标系下的坐标。k_1、k_2为径向畸变系数。于是有:
    在这里插入图片描述
    在上式中,理想坐标系的坐标由推导得来,世界坐标系的坐标通过读取相机、图片的数据得来,均为已知量,未知量为k_1、k_2。

    在图像坐标系和像素坐标系上的每一对点都可得上述的一组矩阵。已知n副图的m个点,则有2nm个等式。利用最小二乘法可求得K矩阵中的值,即:
    在这里插入图片描述
    再将求得的畸变系数k_1、k_2进行极大似然估计,得到最优参数,公式如下:
    在这里插入图片描述
    同上文一样,再次使用L-M算法进行求解,最终可得相机标定的最优参数。

    5、代码实现及文件共享

    至此,就是张正友相机标定法的理论部分的全部内容了,关于代码实现的部分,读者可以参考下面的链接

    测试代码所需的图片我上传到了百度云,各位没有积分的可以去这里下载,提取码为pr1y
    为了防止百度云链接失效,再上传一份至CSDN

    展开全文
  • 双目测距属于立体视觉这一块,我觉得应该有很多人踩过这个坑了,但网上的资料依旧是云里雾里的,要么是理论讲一大堆,最后发现还不知道怎么做,要么就是直接代码一贴,让你懵逼。 所以今天我想做的,是尽量给大家一...

    转自:https://www.cnblogs.com/daihengchen/p/5492729.html

        双目测距属于立体视觉这一块,我觉得应该有很多人踩过这个坑了,但网上的资料依旧是云里雾里的,要么是理论讲一大堆,最后发现还不知道怎么做,要么就是直接代码一贴,让你懵逼。 所以今天我想做的,是尽量给大家一个明确的阐述,并且能够上手做出来。

    一、 标定

        首先我们要对摄像头做标定,具体的公式推导在learning opencv中有详细的解释,这里顺带提一句,这本书虽然确实老,但有些理论、算法类的东西里面还是讲的很不错的,必要的时候可以去看看。

       Q1:为什么要做摄像头标定?

          A:  标定的目的是为了消除畸变以及得到内外参数矩阵,内参数矩阵可以理解为焦距相关,它是一个从平面到像素的转换,焦距不变它就不变,所以确定以后就可以重复使用,而外参数矩阵反映的是摄像机坐标系与世界坐标系的转换,至于畸变参数,一般也包含在内参数矩阵中。从作用上来看,内参数矩阵是为了得到镜头的信息,并消除畸变,使得到的图像更为准确,外参数矩阵是为了得到相机相对于世界坐标的联系,是为了最终的测距。

         ps1:关于畸变,大家可以看到自己摄像头的拍摄的画面,在看矩形物体的时候,边角处会有明显的畸变现象,而矫正的目的就是修复这个。

         ps2:我们知道双目测距的时候两个相机需要平行放置,但事实上这个是很难做到的,所以就需要立体校正得到两个相机之间的旋转平移矩阵,也就是外参数矩阵。  

                    

       Q2:如何做摄像头的标定?

          A:这里可以直接用opencv里面的sample,在opencv/sources/sample/cpp里面,有个calibration.cpp的文件,这是单目的标定,是可以直接编译使用的,这里要注意几点:

                   1.棋盘

           棋盘也就是标定板是要预先打印好的,你打印的棋盘的样式决定了后面参数的填写,具体要求也不是很严谨,清晰能用就行。之所用棋盘是因为他检测角点很方便,and..你没得选。。

                   2. 参数

           一般设置为这个样子:-w 6 -h 8 -s 2 -n 10 -o camera.yml -op -oe [<list_of_views.txt>]  ,这是几个重要参数的含义:

                       -w <board_width>         # 图片某一维方向上的交点个数
                       -h <board_height>        # 图片另一维上的交点个数
                       [-n <number_of_frames>]  # 标定用的图片帧数
                       [-s <square_size>]       # square size in some user-defined units (1 by default)
                       [-o <out_camera_params>] # the output filename for intrinsic [and extrinsic] parameters
                       [-op]                    # write detected feature points
                       [-oe]                    # write extrinsic parameters
                
                 
                 
               可以发现 -w -h是棋盘的长和高,也就是有几个黑白交点,-s是每个格子的长度,单位是cm 
                 长和高一定要数对,不然程序在识别角点的时候会识别不出来的。

               最终得到的yml文件,就是单目标定的参数矩阵,之后使用它就可以得到校正后的图像啦。                                                 

               3. 需要对程序做一些修改,这是我遇到的问题,就是他的读取摄像头的代码在我这边没有用,所以我自己重新修改了,不知道大家会  不会碰到这个问题。

                 

                   然后就是双目标定了,同样的地方,找到stereo_calib.cpp,这个参数比较简单,只要确定长、宽和输入的一个xml文件(在之前          的文件夹里面),这个文件是为了读取图片用的,你需要自己用固定好的双目摄像头拍14对棋盘图片,命名为 left01,right01......这样          一系列的名字,另外,最简单的方法就是把自己拍的照片放到相应的工程下,以及stereo开头的那个xml文件也复制过去这个程序代码            并不复杂,可以稍微研究一下,工程向的代码确实严谨,各种情况都考虑到了,比起自己之前做的那个小项目不知道高到哪里去了

            这里也有几个注意点(坑):

     1.老生常谈的问题,长宽一定要写对!!! 这个不多说了,都是泪。

     2.代码的核心函数 static void  StereoCalib(const vector<string>& imagelist, Size boardSize, bool useCalibrated=true, bool  showRectified=true),注意搞清楚参数的意义,因为我是用的单目标定好的摄像头拍摄的图片,不需要再校正了,所以第三个参数要用false,这样最后的结果才能看,不说了,都是泪...

    3.另外注意到计算rms误差的时候,结束条件的几个参数是可以调整的,

    double rms = stereoCalibrate(objectPoints, imagePoints[0], imagePoints[1],
    cameraMatrix[0], distCoeffs[0],
    cameraMatrix[1], distCoeffs[1],
    imageSize, R, T, E, F,
    TermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 100, 1e-5),
    CV_CALIB_FIX_ASPECT_RATIO +CV_CALIB_ZERO_TANGENT_DIST +CV_CALIB_SAME_FOCAL_LENGTH +CV_CALIB_RATIONAL_MODEL +CV_CALIB_FIX_K3 + CV_CALIB_FIX_K4 + CV_CALIB_FIX_K5)

    下面这段话是某度百科上的:

            这个函数计算了两个摄像头进行立体像对之间的转换关系。如果你有一个立体相机的相对位置,并且两个摄像头的方向是固定的,以及你计算了物体相对于第一照相机和第二照相机的姿态,(R1,T1)和(R2,T2),各自(这个可以通过solvepnp()做到)通过这些姿态确定。你只需要知道第二相机相对于第一相机的位置和方向。

            除了立体的相关信息,该函数也可以两个相机的每一个做一个完整的校准。然而,由于在输入数据中的高维的参数空间和噪声的,可能偏离正确值。如果每个单独的相机内参数可以被精确估计(例如,使用calibratecamera()),建议这样做,然后在本征参数计算之中使CV_CALIB_FIX_INTRINSIC的功能。否则,如果一旦计算出所有的参数,它将会合理的限制某些参数,例如,传CV_CALIB_SAME_FOCAL_LENGTH and CV_CALIB_ZERO_TANGENT_DIST,这通常是一个合理的假设。

            

          Q3:标定之后做什么呢?

           

          A: 写到这我发现把单目和双目的一起写确实有点乱...不过,开弓没有回头箭!(不是因为懒!!)

              首先还是单目,单目的使用很简单,使用标定得到的参数进行校正就行了,代码如下:

    void loadCameraParams(Mat &cameraMatrix, Mat &distCoeffs)
    {
    FileStorage fs("camera.yml", FileStorage::READ);//这个名字就是你之前校正得到的yml文件
    
    fs["camera_matrix"] >> cameraMatrix;
    fs["distortion_coefficients"] >> distCoeffs;
    }
    
    Mat calibrator(Mat &view)//需要校正处理的图片
    {
    vector<string> imageList;
    static bool bLoadCameraParams = false;
    static Mat cameraMatrix, distCoeffs, map1, map2;
    Mat rview;
    Size imageSize, newImageSize;
    
    if (!view.data)
    return Mat();
    
    imageSize.width = view.cols;
    imageSize.height = view.rows;
    
    newImageSize.width = imageSize.width;
    newImageSize.height = imageSize.height;
    
    if (bLoadCameraParams == false)
    {
    loadCameraParams(cameraMatrix, distCoeffs);
    bLoadCameraParams = true;
    initUndistortRectifyMap(cameraMatrix, distCoeffs, Mat(),
    getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, 1, newImageSize, 0), newImageSize, CV_16SC2, map1, map2);
    }
    
    //undistort( view, rview, cameraMatrix, distCoeffs, cameraMatrix );
    remap(view, rview, map1, map2, INTER_LINEAR);
    
    imshow("左图", rview);
    //int c = 0xff & waitKey();
    
    rview.copyTo(view);
    
    return view;
    }

                         这样最后就可以得到校正后消除畸变的图片。

                         OK,接下来显然就是双目啦,双目校正之后的工作就比较多了,我准备另开一节来说...                                  

     二、立体匹配

        这是一个很大的题目,网上的资料也很多,所以我想说的是我的一些理解。

           这里最好的方法是从后往前说,我们首先需要理解测距的原理。这个很多人看了一大堆还不明白(其实只有我自己吧..),相似三角形测距,这种东西小学生都能搞清楚,但两摄像头到底怎么做到的,就是我们需要搞清楚的。

          首先需要搞清楚一个非常重要的概念,视差,搞清楚视差,后面的就简单了 ,老生常谈的问题我不想多说,网上那些一大堆,我希望给大家的是一些明了的东西

                                                                                           

                                                                                            

                                                                                                

           这三幅图看明白了就行,其实视差确实很简单,但很多人都没去理清楚,第一幅图是三维世界的一个点在两个相机的成像,我们可以相信的是,这两个在各自相机的相对位置基本不可能是一样的,而这种位置的差别,也正是我们眼睛区别3D和2D的关键,将右边的摄像机投影到左边,怎么做呢?因为他的坐标和左边相机的左边相距Tx(标定测出来的外参数),所以它相当于在左边的相机对三维世界内的(x-tx,y,z)进行投影,所以这时候,一个完美的形似三角形就出来,这里视差就是d=x-x‘,

                      

                  得到视差以后,再用相似三角形......也就得到了深度也就是距离啦。

           结束了么??并没有....这样做确实很完美,但是问题来了:1.当我在左边相机确定一个点的时候,我怎么在右边找到这个点? 2.我左边点所在的行一点跟右边点所在的行上的像素一定完全一样么?

                 解决第一个问题的方法就是立体匹配了。

              Q1:立体匹配是什么,怎么进行立体匹配?

              A:简单的回答就是:立体匹配就是解决上面问题的东西啦....其实我觉得这样就是也够了,有些成熟的算法,未必需要钻研太深,毕竟我这种实在的菜鸡,还是工程导向的..学术的事,日后再说! 

                  opencv中提供了很多的立体匹配算法,类似于局部的BM,全局的SGBM等等,这些算法的比较大概是,速度越快的效果越差,如果不是很追究时效性,并且你的校正做的不是很好的话..推荐使用SGBM,算法的具体原理大家可以去百度,不难。这里我想提一下的是为什么做立体匹配有用,原因就是极线约束,这也是个很重要的概念,理解起来并不难,左摄像机上的一个点,对应三维空间上的一个点,当我们要找这个点在右边的投影点时,有必要把这个图像都遍历一边么,当然不用...

                                                                   

                 如上图,显然,PL对应的P这个点一定在一条极线上,只要在这条线上找就行了,更明显的是下面这个图:

                                                             

          最后,怎么在opencv里面实现呢..机智的我又找到了sample..找到stereo_match.cpp这个文件,命令行设置为:left01.jpg right02.jpg --algorithm=hh --blocksize=5 --max-disparity=256  --scale=1.0 --no-display -i intrinsics.yml -e extrinsics.yml -o disparity.jpg同意给几个建议:

                  1.参数的意义:

    -max-disparity 是最大视差,可以理解为对比度,越大整个视差的range也就越大,这个要求是16的倍数

     --blocksize 一般设置为5-29之间的奇数,应该是局部算法的窗口大小。

    另,注意带上参数-i intrinsics.yml -e extrinsics.yml,毕竟咱有校正参数...

                  2.后面有两行代码:

                                       reprojectImageTo3D(disp, xyz, Q, true);

                                       saveXYZ(point_cloud_filename, xyz);

                          这个就是得到图片的三维坐标,Z也就是我们最终要求的深度啦。

               

           第二个问题,行和行是对应的么?   之前我们说过,双目校正的目的就是为了得到两个平行的摄像头,所以当程序运行完毕以后,它会把两幅图像显示出来,并作出一系列的平行线,这样你会看到线上的点大致是呈对应关系,左边的角点对应右边的交点,所以,经过匹配和校正后,是对应的。

    三、总结

       双目拖了很久,一直没做,最重要的原因就是...我没有两个一样的摄像头,所以最后也没有贴出效果图,因为两个不一样的摄像头,做出来的东西画面太美我不敢看,不过最终搞清楚了整个流程和原理,还是比较开心的。这里面像校正和匹配的算法,我只是有所理解,因为以后不一定走3D这一块,所以也没有过去深入,如果用到在去研究,其实也不晚..总之,第一篇博客,完工啦~

       

    效果:参考 https://www.cnblogs.com/zhanxiage1994/p/6673892.html

                 https://blog.csdn.net/setella/article/details/77193846     

     

    实现参考:https://blog.csdn.net/Angle_Cal/article/details/57974608

     

    原理参考:https://www.cnblogs.com/yuanlibin/p/9460419.html      

     

    微信公众号:ML_Study

    展开全文
  •  双目测距属于立体视觉这一块,我觉得应该有很多人踩过这个坑了,但网上的资料依旧是云里雾里的,要么是理论讲一大堆,最后发现还不知道怎么做,要么就是直接代码一贴,让你懵逼。 所以今天我想做的,是尽量给大家...

    最近在做双目测距,觉得有必要记录点东西

     双目测距属于立体视觉这一块,我觉得应该有很多人踩过这个坑了,但网上的资料依旧是云里雾里的,要么是理论讲一大堆,最后发现还不知道怎么做,要么就是直接代码一贴,让你懵逼。 所以今天我想做的,是尽量给大家一个明确的阐述,并且能够上手做出来。

    一、 标定

        首先我们要对摄像头做标定,具体的公式推导在learning opencv中有详细的解释,这里顺带提一句,这本书虽然确实老,但有些理论、算法类的东西里面还是讲的很不错的,必要的时候可以去看看。

       Q1:为什么要做摄像头标定?

          A:  标定的目的是为了消除畸变以及得到内外参数矩阵,内参数矩阵可以理解为焦距相关,它是一个从平面到像素的转换,焦距不变它就不变,所以确定以后就可以重复使用,而外参数矩阵反映的是摄像机坐标系与世界坐标系的转换,至于畸变参数,一般也包含在内参数矩阵中。从作用上来看,内参数矩阵是为了得到镜头的信息,并消除畸变,使得到的图像更为准确,外参数矩阵是为了得到相机相对于世界坐标的联系,是为了最终的测距。

         ps1:关于畸变,大家可以看到自己摄像头的拍摄的画面,在看矩形物体的时候,边角处会有明显的畸变现象,而矫正的目的就是修复这个。

         ps2:我们知道双目测距的时候两个相机需要平行放置,但事实上这个是很难做到的,所以就需要立体校正得到两个相机之间的旋转平移矩阵,也就是外参数矩阵。  

                    

       Q2:如何做摄像头的标定?

          A:这里可以直接用opencv里面的sample,在opencv/sources/sample/cpp里面,有个calibration.cpp的文件,这是单目的标定,是可以直接编译使用的,这里要注意几点:

                   1.棋盘

           棋盘也就是标定板是要预先打印好的,你打印的棋盘的样式决定了后面参数的填写,具体要求也不是很严谨,清晰能用就行。之所用棋盘是因为他检测角点很方便,and..你没得选。。

                   2. 参数

           一般设置为这个样子:-w 6 -h 8 -s 2 -n 10 -o camera.yml -op -oe [<list_of_views.txt>]  ,这是几个重要参数的含义:

                       -w <board_width>         # 图片某一维方向上的交点个数
                       -h <board_height>        # 图片另一维上的交点个数
                       [-n <number_of_frames>]  # 标定用的图片帧数
                       [-s <square_size>]       # square size in some user-defined units (1 by default)
                       [-o <out_camera_params>] # the output filename for intrinsic [and extrinsic] parameters
                       [-op]                    # write detected feature points
                       [-oe]                    # write extrinsic parameters
                
                 
                 
               可以发现 -w -h是棋盘的长和高,也就是有几个黑白交点,-s是每个格子的长度,单位是cm 
                 长和高一定要数对,不然程序在识别角点的时候会识别不出来的。

                          最终得到的yml文件,就是单目标定的参数矩阵,之后使用它就可以得到校正后的图像啦。                                                            

               3. 需要对程序做一些修改,这是我遇到的问题,就是他的读取摄像头的代码在我这边没有用,所以我自己重新修改了,不知道大家会  不会碰到这个问题。

                 

                   然后就是双目标定了,同样的地方,找到stereo_calib.cpp,这个参数比较简单,只要确定长、宽和输入的一个xml文件(在之前          的文件夹里面),这个文件是为了读取图片用的,你需要自己用固定好的双目摄像头拍14对棋盘图片,命名为 left01,right01......这样          一系列的名字,另外,最简单的方法就是把自己拍的照片放到相应的工程下,以及stereo开头的那个xml文件也复制过去这个程序代码            并不复杂,可以稍微研究一下,工程向的代码确实严谨,各种情况都考虑到了,比起自己之前做的那个小项目不知道高到哪里去了

            这里也有几个注意点(坑):

                  1.老生常谈的问题,长宽一定要写对!!! 这个不多说了,都是泪。

     

     2.代码的核心函数 static void  StereoCalib(const vector<string>& imagelist, Size boardSize, bool useCalibrated=true, bool  showRectified=true),注意搞清楚参数的意义,因为我是用的单目标定好的摄像头拍摄的图片,不需要再校正了,所以第三个参数要用false,这样最后的结果才能看,不说了,都是泪...

     

                  3.另外注意到计算rms误差的时候,结束条件的几个参数是可以调整的,

    double rms = stereoCalibrate(objectPoints, imagePoints[0], imagePoints[1],
    cameraMatrix[0], distCoeffs[0],
    cameraMatrix[1], distCoeffs[1],
    imageSize, R, T, E, F,
    TermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 100, 1e-5),
    CV_CALIB_FIX_ASPECT_RATIO +CV_CALIB_ZERO_TANGENT_DIST +CV_CALIB_SAME_FOCAL_LENGTH +CV_CALIB_RATIONAL_MODEL +CV_CALIB_FIX_K3 + CV_CALIB_FIX_K4 + CV_CALIB_FIX_K5)

    下面这段话是某度百科上的:

            这个函数计算了两个摄像头进行立体像对之间的转换关系。如果你有一个立体相机的相对位置,并且两个摄像头的方向是固定的,以及你计算了物体相对于第一照相机和第二照相机的姿态,(R1,T1)和(R2,T2),各自(这个可以通过solvepnp()做到)通过这些姿态确定。你只需要知道第二相机相对于第一相机的位置和方向。
            除了立体的相关信息,该函数也可以两个相机的每一个做一个完整的校准。然而,由于在输入数据中的高维的参数空间和噪声的,可能偏离正确值。如果每个单独的相机内参数可以被精确估计(例如,使用calibratecamera()),建议这样做,然后在本征参数计算之中使CV_CALIB_FIX_INTRINSIC的功能。否则,如果一旦计算出所有的参数,它将会合理的限制某些参数,例如,传CV_CALIB_SAME_FOCAL_LENGTH and CV_CALIB_ZERO_TANGENT_DIST,这通常是一个合理的假设。
            
          Q3:标定之后做什么呢?
           
          A: 写到这我发现把单目和双目的一起写确实有点乱...不过,开弓没有回头箭!(不是因为懒!!)
              首先还是单目,单目的使用很简单,使用标定得到的参数进行校正就行了,代码如下:

    void loadCameraParams(Mat &cameraMatrix, Mat &distCoeffs)
    {
    FileStorage fs("camera.yml", FileStorage::READ);//这个名字就是你之前校正得到的yml文件

    fs["camera_matrix"] >> cameraMatrix;
    fs["distortion_coefficients"] >> distCoeffs;
    }

    Mat calibrator(Mat &view)//需要校正处理的图片
    {
    vector<string> imageList;
    static bool bLoadCameraParams = false;
    static Mat cameraMatrix, distCoeffs, map1, map2;
    Mat rview;
    Size imageSize, newImageSize;

    if (!view.data)
    return Mat();

    imageSize.width = view.cols;
    imageSize.height = view.rows;

    newImageSize.width = imageSize.width;
    newImageSize.height = imageSize.height;

    if (bLoadCameraParams == false)
    {
    loadCameraParams(cameraMatrix, distCoeffs);
    bLoadCameraParams = true;
    initUndistortRectifyMap(cameraMatrix, distCoeffs, Mat(),
    getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, 1, newImageSize, 0), newImageSize, CV_16SC2, map1, map2);
    }

    //undistort( view, rview, cameraMatrix, distCoeffs, cameraMatrix );
    remap(view, rview, map1, map2, INTER_LINEAR);

    imshow("左图", rview);
    //int c = 0xff & waitKey();

    rview.copyTo(view);

    return view;
    }

                         这样最后就可以得到校正后消除畸变的图片。

                         OK,接下来显然就是双目啦,双目校正之后的工作就比较多了,我准备另开一节来说...                                  

     二、立体匹配

        这是一个很大的题目,网上的资料也很多,所以我想说的是我的一些理解。

           这里最好的方法是从后往前说,我们首先需要理解测距的原理。这个很多人看了一大堆还不明白(其实只有我自己吧..),相似三角形测距,这种东西小学生都能搞清楚,但两摄像头到底怎么做到的,就是我们需要搞清楚的。

          首先需要搞清楚一个非常重要的概念,视差,搞清楚视差,后面的就简单了 ,老生常谈的问题我不想多说,网上那些一大堆,我希望给大家的是一些明了的东西

                                                                                           

                                                                                            

                                                                                                

           这三幅图看明白了就行,其实视差确实很简单,但很多人都没去理清楚,第一幅图是三维世界的一个点在两个相机的成像,我们可以相信的是,这两个在各自相机的相对位置基本不可能是一样的,而这种位置的差别,也正是我们眼睛区别3D和2D的关键,将右边的摄像机投影到左边,怎么做呢?因为他的坐标和左边相机的左边相距Tx(标定测出来的外参数),所以它相当于在左边的相机对三维世界内的(x-tx,y,z)进行投影,所以这时候,一个完美的形似三角形就出来,这里视差就是d=x-x‘,

                      

                  得到视差以后,再用相似三角形......也就得到了深度也就是距离啦。

           结束了么??并没有....这样做确实很完美,但是问题来了:1.当我在左边相机确定一个点的时候,我怎么在右边找到这个点? 2.我左边点所在的行一点跟右边点所在的行上的像素一定完全一样么?

                 解决第一个问题的方法就是立体匹配了。

              Q1:立体匹配是什么,怎么进行立体匹配?

              A:简单的回答就是:立体匹配就是解决上面问题的东西啦....其实我觉得这样就是也够了,有些成熟的算法,未必需要钻研太深,毕竟我这种实在的菜鸡,还是工程导向的..学术的事,日后再说! 

                  opencv中提供了很多的立体匹配算法,类似于局部的BM,全局的SGBM等等,这些算法的比较大概是,速度越快的效果越差,如果不是很追究时效性,并且你的校正做的不是很好的话..推荐使用SGBM,算法的具体原理大家可以去百度,不难。这里我想提一下的是为什么做立体匹配有用,原因就是极线约束,这也是个很重要的概念,理解起来并不难,左摄像机上的一个点,对应三维空间上的一个点,当我们要找这个点在右边的投影点时,有必要把这个图像都遍历一边么,当然不用...

                                                                   

                 如上图,显然,PL对应的P这个点一定在一条极线上,只要在这条线上找就行了,更明显的是下面这个图:

                                                             

          最后,怎么在opencv里面实现呢..机智的我又找到了sample..找到stereo_match.cpp这个文件,命令行设置为:left01.jpg right02.jpg --algorithm=hh --blocksize=5 --max-disparity=256  --scale=1.0 --no-display -i intrinsics.yml -e extrinsics.yml -o disparity.jpg同意给几个建议:

                  1.参数的意义:

    -max-disparity 是最大视差,可以理解为对比度,越大整个视差的range也就越大,这个要求是16的倍数

     --blocksize 一般设置为5-29之间的奇数,应该是局部算法的窗口大小。

    另,注意带上参数-i intrinsics.yml -e extrinsics.yml,毕竟咱有校正参数...

                  2.后面有两行代码:

                                       reprojectImageTo3D(disp, xyz, Q, true);

                                       saveXYZ(point_cloud_filename, xyz);

                          这个就是得到图片的三维坐标,Z也就是我们最终要求的深度啦。

               

           第二个问题,行和行是对应的么?   之前我们说过,双目校正的目的就是为了得到两个平行的摄像头,所以当程序运行完毕以后,它会把两幅图像显示出来,并作出一系列的平行线,这样你会看到线上的点大致是呈对应关系,左边的角点对应右边的交点,所以,经过匹配和校正后,是对应的。

    三、总结

       双目拖了很久,一直没做,最重要的原因就是...我没有两个一样的摄像头,所以最后也没有贴出效果图,因为两个不一样的摄像头,做出来的东西画面太美我不敢看,不过最终搞清楚了整个流程和原理,还是比较开心的。这里面像校正和匹配的算法,我只是有所理解,因为以后不一定走3D这一块,所以也没有过去深入,如果用到在去研究,其实也不晚..


    展开全文
  • 相机标定的思考

    2020-04-30 14:12:30
    这里一个记录。 还是拿标准的张正友标定来说: 这个式子很简单了,从世界坐标系到像素坐标系的映射,那我们先考虑下面的那个式子,对于Xw,Yw缩放相同的倍数会怎么样?(至于Zw,因为标定对象是一个平面,所以...
  •  最近在做双目测距,觉得有... 双目测距属于立体视觉这一块,我觉得应该有很多人踩过这个坑了,但网上的资料依旧是云里雾里的,要么是理论讲一大堆,最后发现还不知道怎么做,要么就是直接代码一贴,让你
  • HALCON相机标定相机内参相机外参

    万次阅读 多人点赞 2019-08-27 11:54:48
    接下来我就给大家介绍一下标定,侧重点在怎么做。1.相机标定是什么 首先镜头有畸变,也就是说照出的图像与实际不符产生了形变。即使号称无畸变的工业镜头也是有千分之几的畸变率的。上个图告诉大家畸变 这个图里...
  • 相机标定的前世今生

    千次阅读 2015-08-23 16:13:22
    标定什么?怎么标定? 这些天看了很多相关文档,资料,都快被那些东西给淹没了,浮出来,好好吸一口新鲜空气   得出相机内参外参的过程就叫标定 内参就是相机固有的参数,比如焦距,主点
  • 红外相机的标定

    千次阅读 2020-01-08 21:18:12
    这个标定的难度主要来源于标定图像的获取,有人...另外还有一个就是 如果有两个双目相机,该怎么去转换,看到一个论文,大致是分别利用两个双目相机的左目作为基础(操作对象),在对这两个刚体变换的操作。 ...
  • RGB-D相机的标定

    千次阅读 2020-02-21 11:06:33
    看自刘国庆的演讲,简单的总结。(没有ppt,全靠截图) kinect的结构 一个彩色相机(1920*1080) 一个深度相机(一个灰度相机512*414可以感知红外光+红外发射) 这里提出了几个问题: 图像畸变(来源自相机自身...
  • 最近在双目摄像机标定,有好多疑惑,急求大神帮忙。想知道世界坐标系建好了以后,实验中怎么样获取标定点 的世界坐标?请大神帮忙
  • 我们图像处理为的就是要得到图像的数据,在得到这些数据之后怎么对这些数据进行处理,这才是我们主要关心的问题 但是,在此之前,我们还需要一个非常主要的步骤-------对摄像头的参数进行参数标定 安装标定功能...
  • 的是6*6的标靶,每格间隔33mm。。拍5副图片。。噪声在(-0.3,0.3)之间,像素噪声的编程是(u=u1+0.6*(rand(1)-0.5)其中u1是仿真算出来的像素坐标。。再把这个加了噪声的像素坐标u,v带到张正友模型里算。。...
  • 之前,我写过一篇标定文章,但是只说明了相机和机械手分离的情况的标定方法,为了提供完整的标定方案,这边介绍一下怎么利用我标定助手完成相机和机械手绑定的情况的标定方法。  由文章“工业现场相机坐标系和...
  • 最近在整理自己以前过的一些东西,这是基于opencv的鱼眼摄像头畸变校正程序的github地址(https://github.com/WordZzzz/fisheye_calibration)(不知道怎么设置免积分下载,所以只能贴上github了)。 其中: ...
  • 蛮遗憾的一次建模……怎么说呢,在当时的能力下可以的更好的。 题附下面git库了……。感觉前两问回答的比较正常第4问相当于没怎么写…… 思路 第四问太糟糕了不管了…… 1 第一题的成像图 然后把两条...
  • 2.工程一:BMS通信

    2021-01-06 06:23:01
    (8) 怎么做知识产权保护,让别人无法破解芯片。 (9) 怎么用git进行多人协作开发。 (10) 工作和生活的一些感悟。 一切都是站在面向对象和状态机的角度思考问题… 2.1. 介绍 很多产品都需要使用到电池,有了电池,就有...
  • Deep Active Learning(深度主动学习)

    千次阅读 2020-10-06 16:55:54
    具体怎么做呢?一图胜千言: 大概的意思是:如果模型遇到了迷惑的地方,就主动的询问专家(这也是为什么要叫主动学习),然后由专家标定完,将这个标定了的新样本纳入到样本集中,再一起训练,这样可能逐步改善模型...
  • OpenCV的深度图

    千次阅读 2011-12-19 21:32:34
    用OpenCV 的视差图,感觉效果不怎么样啊。而且再次标定后,效果更差,深度图中连瓶子也找不到了 怎么回事呢
  • 相机标定对于刚入手的人来说有很多疑惑的点,我总结个人的入手的方法和需要弄明白的问题: 相机标定是干什么的,需要什么器材才能?双目校正目标是什么,又需要什么设备? 二、相机(针孔)模型是...
  • 作者介绍: 大学毕业之后去了一家SOC原厂Linux驱动,当时负责jtag、adc、gpio key、adc key、watchdog驱动的维护,一年半后跳槽到了一家产品的公司...(5) 支持上位机或手机标定功能的代码怎么写。 (6) 电机驱动和控
  • 2、 他们怎么做这个研究 (方法,尤其是与之前不同之处) ? 本文要解决的问题就是如何在相机和激光雷达标定没那么准的情况的下还能保证较高的性能,归根结底就是扩大搜索空间,但也不能太大,用2D检测的目标就是限制...
  • 3.从像素坐标系到相机坐标系的转换如果不考虑相机畸变可以参考该博客:https://www.cnblogs.com/ailitao/p/11787519.html ,我想问如果考虑畸变应该怎么做,或者是不是opencv中有相关函数,但是我并没有找到?
  • 1。讨论行人检测标定过程时实施方案,这边的技术细节已经基本确定,写成一个类或者cpp文件,有tracker....行人检测着一块,用svm检测现在的问题是运行出现段错误内存转出,沟通后现在需要调试看怎么解决 @tld_t...

空空如也

空空如也

1 2 3
收藏数 48
精华内容 19
关键字:

标定怎么做