项目实战——基于计算机视觉的物体位姿定位及机械臂抓取(单目标定)
        请各位读者朋友注意,这里面很多东西涉及到我的毕设,写作辛苦,请勿滥用,转载请务必注明出处!
        单目标定主要分为两个部分,一是确定摄像机的内在参数,二是确定摄像头畸变系数,消除畸变。在进行标定之前首先要建立摄像机模型,用数学语言描述三维世界中的点在摄像机中成像的过程。

全针孔摄像机模型的建立


1、针孔摄像机模型


        在实际应用中,所用摄像机成像的基本原理是小孔成像原理(如图2.2-1所示):真实物理世界中的光线穿过小孔,在摄像机的图像平面上形成一幅倒立的图像。
小孔成像物理模型

  由于成像是倒置的,因此将上述物理模型转化为便于计算的数学模型,处理方法是将成的像放在小孔和实物之间,如图所示,如此一来所成的像便为正像。这样做的目的是为了方便计算,计算结果与上图结果一致。

小孔成像数学模型

 为了方便说明,在这里首先定义几个坐标系,后面的内容很多都涉及到坐标系之间的变换:

(1) 世界坐标系:真实世界的三维空间坐标系,其坐标原点可以任意指定。
(2) 相机坐标系:以摄像机焦点为坐标原点创建的三维直角坐标系。
(3) 图像坐标系:以图像中心为原点,创建的二维坐标系,单位长度为毫米。
(4) 像素坐标系:以图像左上角为原点,创建的二维坐标系,单位长度为pixel。

 设上述坐标系(1)(2)重合,并且真实世界中的点  w=[u,v,w] T
 通过小孔在摄像机图像平面的投影为 x = [ x , y ] T 。这就是:针孔摄像机模型。

2、归一化相机模型

为了便于分析,首先引入归一化相机的模型。在该模型中,相机的 f = 1 ,且成像点的中心是图像坐标系的原点 ( x , y )。图像在vw平面的投影如图所示:

归一化相机模型

  根据相似三角形原理,不难得出:

x=u/w 
y = v / w

这样,就完成了从3D世界向2D平面的映射。

3、模型改进

          归一化相机在实际情况下是不存在的,它与真实摄像机存在两点差异:


        (1)焦距不为1,且由于图像的最终位置是利用像素进行测量的,因此模型必须将感光体的间距考虑在内,考虑到感光体在x方向和y方向上的间距是不同的,因此引入两个比例因子:φ_x 〖,φ〗_y称为焦距参数。原本的映射关系就变成了:

4、全针孔摄像机模型

        综上所述,可以得到从3D世界中的点在2D图像上的映射关系:

齐次坐标与单应性变换
        观察单目摄像机的投影模型不难发现:3D世界坐标中的点,在图像的投影上都要除以分母w,这就使得投影成为非线性的,不方便研究。因此对2D 图像点和3D世界点的表达形式做出修改,使得投影方程变为线性的。
        将2D图像点的坐标转化为3D齐次坐标x ̃:


张正友标定法

        张正友于1998年提出了求解相机内参Λ的方法,它仅需要一个标定棋盘即可完成(如图2.2-4所示)。该方法以其简单、实用、高效的特性,成为了目前单目相机标定的主流算法。

标定棋盘

张氏标定法的具体思路是:用于标定的棋盘是三维世界的一个平面 Π ,它在成像平面所成的像为另一个平面 π 。由于标定棋盘的角点坐标已知,图像的角点可以通过角点识别算法求得,通过两个平面的对应点的坐标,就可以求解出单应矩阵H。从而求出摄像机的内参数,完成标定。下面具体说明其算法。


        设棋盘所在平面为世界坐标系下的 z = 0 的平面。这样,棋盘上的任意角点在世界坐标系中可表示为 ( X , Y , 0 ) 。代入映射方程可得:

奇异值分解

摄像头畸变
        在进行理论计算时,假定透镜是没有畸变的,但在实际情况下,不存在真正无畸变的透镜。摄像机在生产的过程中,透镜的制造精度存在限制,同时在装配的时候,很难将透镜与成像装置完全对齐,因此,会使成像产生多种形式的畸变。

1、径向畸变
        径向畸变是一种沿着透镜半径方向分布的畸变,一般来说越靠近边缘,光线就越容易弯曲,畸变也就越严重。径向畸变根据畸变情况不同,可分为桶形畸变和枕形畸变。图2.2-1和图2.2-2展示了两种畸变情况。


桶形畸变枕形畸变

   对于镜头来说,径向畸变程度从光轴中心(畸变值为零)向边缘逐渐加剧,这种畸变可以用r=0附近的泰勒数级展开式的前两项来描述,即:k1、k2。对于畸变较大的相机,可以引入第三个径向畸变系数k3来矫正。成像装置上某点的径向位置可以根据下面的公式调整:

Harris角点检测
        在张氏标定法的具体思路中,对于标定棋盘图像角点坐标的获取,是通过Harris角点提取算法获得的,现在对这一算法方法进行详细说明。
        该算法的主要思路是:令一个 n × n 的窗口在图像上移动,通过比较临近像素点的灰度差,判断灰度是否发生较大变化,从而判断是否为角点、边缘、平滑区域。
        定义 E ( u , v ) 为窗口W在图像上移动 ( u , v ) 个像素的灰度变换:

这里的系数k一般取0.04~0.06。此时,可根据R值间接判断目标像素点的特征:


        当|R|比较小时,表示该区域为平坦区域; 
        当R<0且|R|较大时,表示该区域为边缘区域; 
        当R>0且|R|较大时,表示该区域为角点区域。
        综上,Harris角点检测算法的步骤总结如下:

OpenCV单目标定

        上面详细阐述了张正友标定法的具体算法,下面详细阐述其具体操作方法。

        目前有很多关于计算机视觉方面的库,其中以OpenCV(Open Source Computer Vision Library)最为出名。它以其丰富的视觉函数库,和强大的平台适用性,被广泛应用在图像降噪、产品质检、图像拼接、人脸识别、无人驾驶、人机交互、动作识别等领域,最新的OpenCV版本为4.1,还提供了机器学习模块。


        OpenCV提供了张正友标定法的实现。本文采用的C++语言开发,IDE为VS2015,OpenCV版本为4.0版本。以下介绍其主要实现函数:

1、寻找棋盘

        bool cv::findChessboardCorners( //如果寻找到角点则返回1,否则返回0
        cv::InputArray image, //输入的棋盘图
        cv::Size board_sz, //标定棋盘图像中的角点的个数
        cv::OutputArray corners, //记录角点位置的输出矩阵
        Int flags //实现一个或多个附加滤波:
        );
        /对flags的说明:
        CV_CALIB_CB_ADAPTIVE_THRESH – 采用自适应阈值滤波。
        CV_CALIB_CB_NORMALIZE_IMAGE – 首先对图像亮度进行平均化处理(采用函数: cvNormalizeHist),随后再进行滤波处理
        CV_CALIB_CB_FILTER_QUADS – 采用其他规则,剔除错误棋盘格块
        /

2、绘制棋盘


        void cv::drawChessboardCorners(
        cv::InputOutputArray image, //输入和输出的棋盘格图
        cv::Size patternSize, //标定棋盘图像中的角点的个数
        cv::InputArray corners, //从函数1中返回的角点
        bool patternWasFound //指出是否已找到所有的角点,0表示未找到
        )

3、摄像机单目标定


        double cv::calibrateCamera(
        cv::InputArrayOfArrays objectPoints, //世界坐标系中的点
        cv::InputArrayOfArrays imagePoints, //对应的图像点
        cv::Size imageSize, //仅用于储存摄像机内参矩阵图像
        cv::InputOutputArray cameraMatrix, //摄像机内参矩阵(3x3)
        cv::InputOutputArray distCoeffs, //畸变系数的输出矢量
        cv::OutputArrayOfArrays rvecs, //为每个模式视图估计旋转矩阵
        cv::OutputArrayOfArrays tvecs, //为每个模式视图估计平移矩阵
        int flags
        )
        /对flag的说明:
        CV_CALIB_USE_INTRINSIC_GUESS cameraMatrix采用高斯法优化摄像机内参矩阵;
        CV_CALIB_FIX_PRINCIPAL_POINT在进行优化的时候不改变主点位置;
        CV_CALIB_FIX_ASPECT_RATIO仅设置δ_y为可变参数,而不改变δ_y/δ_x 的值;
        CV_CALIB_ZERO_TANGENT_DIST k1=0,k2=0;
        CV_CALIB_RATIONAL_MODEL计算系数k4、k5和k6;
        CALIB_THIN_PRISM_MODEL计算系数s1,s2,s3和s4 ;
        CALIB_FIX_S1_S2_S3_S4在进行优化的过程中,不改变系数s的值
        CALIB_TILTED_MODEL计算系数tauX和tauY已启用;
        /

4、计算矫正映射


        void cv :: initUndistortRectifyMap( 
        cv::InputArray cameraMatrix, //输入相机矩阵
        cv::InputArray distcoeffs, //畸变系数的输入向量
        cv::InputArray R, //对象空间中的可选整流变换(3x3矩阵)
        cv::InputArray newCameraMatrix, //校正后的相机矩阵
        cv::Size , //理想无畸变的图像大小
        int mltype,//指定输出映射类型
        cv::OutputArray map1,//第一个输出图
        cv::OutputArray map2 //第二个输出图
        )

5、重映射(对图像进行无畸变化处理)


        void cv :: remap (
        InputArray src,//原始图像
        OutputArray dst,//目标图像
        InputArray map1,//(x,y)的第一个映射点
        InputArray map2,//(x,y)的第二个映射点
        int interpolation,//插值方法,有四中插值方式:
        /*
        (1)INTER_NEAREST——最近邻插值
        (2)INTER_LINEAR——双线性插值
        (3)INTER_CUBIC——双三样条插值
        (4)INTER_LANCZOS4——lanczos插值
        */
        int borderMode = BORDER_CONSTANT,//像素外推方法
        const Scalar& borderValue =Scalar() //一般取值为0
        ) 
        在本文程序中,利用张正友方法进行单目标定写成了一个单独的.c文件,名称为Camera_calibration,其主函数为:
        vectorcv::Mat Camera_calibration(
         int board_w, //棋盘的宽度
         int board_h, //棋盘的高度
         int n_boards, //监测标定图像的数目,后面在输入参数里面获取,为了保证参数的求解精度,我们至少需要10张以上的图像
        int delay, //相机的拍摄延时为1s
         double image_sf, //缩放比例为0.5
         int cap //选择调用相机

        对两个摄像机分别拍摄15幅棋盘标定板图像运用OpenCV进行单目标定,下面截取其中的两张标定图像:
左摄像机右摄像机

  最终求得的相机参数如表所示:


————————————————
版权声明:本文为CSDN博主「Hunt Tiger Tonight」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_32061503/article/details/102800176