Opencv自带的sample code有关于camera calibration的示例代码,但是在这里我使用的是Learning OpenCV3的示例,在其代码基础上上稍微做了一点改动。之所以不用opencv自带的例子,是因为Learning OpenCV3的代码更加简单,可以更容易的抓住代码的核心。本节使用的项目代码可以在这里下载到。
在下载完整个工程以后,按照工程使用说明,下载配置Opencv,运行VS2019项目即可。正常情况下,运行结果如下图所示:
上图显示了标定代码的三个主要步骤,实际上代码中还有一步,但是在dos窗口中没有打印任何信息,这个在后面的代码分析中再进一步说明。
程序运行的第一步是加载图片信息,程序中只是获取了图片序列的文件名。第二步则是棋盘格角点检测,对序列图片中的每一张图片进行角点检测,并选出角点检测成功的图片打印信息,仔细观察打印信息发现没有IMG_0195.jpg的信息,说明这张图片角点检测失败了,猜测是因为标定板严重倾斜导致。第三步就是标定,将检测的棋盘格角点以及设置的3D坐标点输入到opencv现成的函数中即可得到相机内参、畸变系数以及相机外参,这里程序还计算了重投影误差,可以根据重投影误差来帮助我们判断标定的精度。
这里主要是对上面运行的代码做一些简单的介绍,因为Opencv封装的已经很好了,所以代码很简短,说明起来也很轻松。Opencv单目标定流程主要分为三步:
CV_EXPORTS_W bool findChessboardCorners(InputArray image,
Size patternSize,
OutputArray corners,
int flags = CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE );
这个函数检测效果貌似精度不是很高,配合cornerSubPix可以进一步提高检测精度,进而提高标定精度。
CV_EXPORTS_W double calibrateCamera( InputArrayOfArrays objectPoints,
InputArrayOfArrays imagePoints,
Size imageSize,
InputOutputArray cameraMatrix,
InputOutputArray distCoeffs,
OutputArrayOfArrays rvecs,
OutputArrayOfArrays tvecs,
int flags = 0,
TermCriteria criteria = TermCriteria(
TermCriteria::COUNT + TermCriteria::EPS, 30, DBL_EPSILON) );
CV_EXPORTS_W void initUndistortRectifyMap(InputArray cameraMatrix,
InputArray distCoeffs,
InputArray R,
InputArray newCameraMatrix,
Size size,
int m1type,
OutputArray map1,
OutputArray map2 );
这个函数计算得到两个map,然后利用cv::remap函数对畸变图像进行映射变换,得到最终的去畸变图像。