Opencv—张正友标定流程及标定结果评价

来源:互联网 发布:淘宝代运营被骗 编辑:程序博客网 时间:2024/05/22 14:56

1.相机标定的目的 :

相机标定的输入:标定图像上所有内点(inliers)的图像坐标,标定板上所有inliers的空间三维坐标(一般情况下假设Z=0平面上)。

相机标定的输出:获取摄像机的内参和外参矩阵,同时也会得到每一副标定图像的旋转和平移矩阵,内参和外参可以对之后相机拍摄的图像就进行矫正,得到畸变相对很小的图像。

使用平台: Ubuntu14.04 、Xtion 、13x8棋盘格标定板(尺寸20x20mm)

2.标定需要用到的函数详解:

(1)使用findChessboardCorners函数提取角点,这里的角点提取的是标定图像上的内点(inliers),函数原型为:

CV_EXPORTS_W bool findChessboardCorners( InputArray image, Size patternSize,                                           OutputArray corners,                                    int flags=CALIB_CB_ADAPTIVE_THRESH+CALIB_CB_NORMALIZE_IMAGE );

第一个参数image:传入拍摄的棋盘图Mat图像,必须为8位或者rgb图像;
第二个参数patternSize:棋盘图的内角点的行列数,行列一般不同。
第三个参数corners:存储检测到的角点二维坐标位置,类型Point2f,vector<Point2f>image_corners
第四个参数:用于查找棋盘格角点的方式,有默认值。

这里函数是布尔类型的,一般可以用来判断该标定版是否检测到角点,如果是,可进行find4QuadCornerSubpix 函数,输出亚像素。

(2)为了提高标定精度,需要在提取的角点信息基础上得到其精确位置,这里我们用find4QuadCornerSubpix,有时候我们也用cornerSubPix。

CV_EXPORTS bool find4QuadCornerSubpix(InputArray img, InputOutputArray corners, Size region_size);

第一个参数img:输入的Mat矩阵,最好是8位灰度图像,检测效率更高;
第二个参数corners:初始的角点坐标向量,既是输入也是输出,因为是亚像素坐标位置的输出,所以需要用浮点型数据,一般用Point2f/Point3d,即 vector<Point2f/Point2d> image_corners
第三个参数region_size,角点搜索窗口的尺寸;

** 在一般情况下,其实我们用得较多的是cornerSubPix,但是我们这里用的是棋盘格,而
find4QuadCornerSubpix是专门用来获取棋盘图上内角点的精确位置的。

(3)在棋盘图上绘制找到的内角点drawChessboardCorners

CV_EXPORTS_W void drawChessboardCorners( InputOutputArray image, Size patternSize,                                         InputArray corners, bool patternWasFound );

第一个参数image:8位灰度或者彩色图像;
第二个参数patterSize:与findChessboardCorners()函数的patternSize是一样的,指的是棋盘图的内角点的行列数,行列一般不同。
第三个参数corners:与上面俩个corners是一致的,vector<Point2f/Point2d> image_corners
第四个参数patternWasFound:用来指示定义的棋盘内角点是否被完全的探测到,true表示被完整探测到,依次连接各个角点,大概示意图如下:

这里写图片描述

(4)获取到棋盘标定图的内角图像坐标后,使用calibrateCamera()函数进行标定,计算相机内参和外参系数。

CV_EXPORTS_W double calibrateCamera( InputArrayOfArrays objectPoints,                                     InputArrayOfArrays imagePoints,                                     Size imageSize,                                     CV_OUT InputOutputArray cameraMatrix,                                     CV_OUT InputOutputArray distCoeffs,                                     OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs,                                     int flags=0, TermCriteria criteria = TermCriteria(                                     TermCriteria::COUNT+TermCriteria::EPS, 30, DBL_EPSILON) );

第一个参数obejectPoints:为世界坐标系中的三维点,在使用时,应该输入一个三维坐标点的向量的向量,即vector<vector<Point3f>> object_points。需要根据棋盘上单个黑白矩阵大小,计算出每个内角点的世界坐标。
第二个参数imagePoints,为每一个内角点对应的图像坐标点。和obejectPoints一样,应该输入vector<vector<Point3f>> image_points的变量。
第三个参数imageSize,为图像的像素尺寸大小,在计算内参和畸变矩阵时需要使用到。
第四个参数cameraMatrix:为相机内参矩阵。输入一个Mat cameraMatix即可,如Mat cameraMatix=Mat(3,3,CV_32FC1,Scalar::all(0));
第五个参数distCoeffs为畸变矩阵,输入Mat distCoeffs=Mat(1,5,CV_32FC1,Scalar::all(0));
第六个参数rvecs为旋转向量:输出一个Mat类型的vector,即vector<Mat> rvecs
第七个参数rvecs为平移向量:输出一个Mat类型的vector,即vector<Mat> tvecs
第八个参数flag为标定时采用的算法(这里不展开,一般使用时默认为0)
第九个参数criteria是最终优化迭代终止条件设定。

在使用该函数进行标定运算之前,需要对棋盘上每个角点的空间坐标系位置坐标进行初始化(就是对其进行赋值),算出相机内参矩阵、相机畸变、另外每张图片会生成属于自己的平移向量和旋转向量。

(5)对标定结果进行评价的方法是通过得到摄像机内外参对,利用projectPoints()函数对空间的三维点进行重新投影计算,得到空间三维点在图像上新的投影点的坐标,计算投影坐标和亚像素角点坐标之间的偏差,偏差越小,标定结果越好。

CV_EXPORTS_W void projectPoints( InputArray objectPoints,                                 InputArray rvec, InputArray tvec,                                 InputArray cameraMatrix, InputArray distCoeffs,                                 OutputArray imagePoints,                                 OutputArray jacobian=noArray(),                                 double aspectRatio=0 );

第一个参数obejectPoints:为相机坐标系中的三维坐标点;
第二个参数revc:图像对应的旋转向量;
第三个参数tvec:图像对应的位移向量;
第四个参数cameraMatrix:相机的内参;
第五个参数distCoeffs:相机的畸变;
第六个参数imagePoints:投影完后的图像上的坐标点,即obejectPoints对应的像素点。
第七个参数是雅克比矩阵;
第八个参数aspectRatio跟相机传感器感光单元有关,如果设置为非0,则函数默认感光单元dx/dy是固定的,会对雅克比矩阵进行调整。

(6)查看标定效果,有俩种方法:1.使用initUndistortRectifyMap()和reamap()俩个函数配合使用,initUndistortRectifyMap( )用来计算畸变映射,remap把求得的映射应用到图像上。

initUndistortRectifyMap( )函数原型

CV_EXPORTS_W void initUndistortRectifyMap( InputArray cameraMatrix, InputArray distCoeffs,                           InputArray R, InputArray newCameraMatrix,                           Size size, int m1type, OutputArray map1, OutputArray map2 );

第一个参数cameraMatrix:为之前求得的相机的内参;
第二个参数distcoeffs:为之前求得的相机畸变矩阵;
第三个参数R:可选的输入,是相机第一和第二相机坐标系之间的旋转矩阵;
第四个参数newCameraMatrix:,输入校正后的摄像机矩阵;
第五个参数size:摄像机采集的无失真的图像尺寸;
第六个参数m1type,定义map1的数据类型,可以是CV_32FC1或者CV_16SC2;
第七个参数map1和第八个参数map2,输出的X/Y坐标重映射参数;

remap函数原型:

CV_EXPORTS_W void remap( InputArray src, OutputArray dst,                         InputArray map1, InputArray map2,                         int interpolation, int borderMode=BORDER_CONSTANT,                         const Scalar& borderValue=Scalar());

第一个参数src,输入参数,代表畸变的原始图像;
第二个参数dst,矫正后的输出图像,跟输入图像具有相同的类型和大小;
第三个参数cameraMatrix为之前求得的相机的内参矩阵;
第四个参数distCoeffs为之前求得的相机畸变矩阵;
第五个参数newCameraMatrix,默认跟cameraMatrix保持一致;

为了实现上面的方式,还可以使用undistort( )函数实现,但是效率较慢,这里我们就不展开了。

未完待续。。。。

阅读全文
0 0
原创粉丝点击