OpenCV3.0 alpha在8月21日发布,其中增加了鱼眼镜头模型,提供了标定、去畸变等一系列api,其实现方法参考了{Camera Calibration Toolbox for Matlab}。本文简单介绍了OpenCV 中实现的鱼眼镜头模型,给出调用demo的关键代码、注释和去畸变的结果。
鱼眼镜头模型
鱼眼镜头的内参模型可以表示为,与普通镜头的内参一样,但畸变参数不同,为
,含义如下:
设(X,Y,Z)为一个三维坐标点,投影在图像上的二维坐标为(u,v),如果不考虑畸变,投影关系如下:
R和t分别代表相机外参中的旋转矩阵和平移向量。
当考虑鱼眼镜头的畸变后,投影关系转化为:
标定流程
首先调用OpenCV的FindChessboardCorners()来寻找图像上的标定板的角点,再根据标定板的尺寸指定这些角点对应的三维点的三维坐标,再调用fisheye::calibrate()来进行标定,利用标定结果中的内参和畸变参数调用fisheye::undistortImage()对图像做去畸变操作。
代码片段
tuple<Mat, Mat, double> calibrate_fisheye(const vector<Mat>& images, const Settings& s) { /*寻找二维角点*/ auto corners = chessboard_corners(images, s); /*计算二维角点对应的三维点坐标*/ auto object_points = vector<vector<Point3d>>(corners.size(), object_positions(s)); cv::Matx33d K; cv::Vec4d D;int flag = 0; flag |= cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC; flag |= cv::fisheye::CALIB_CHECK_COND; flag |= cv::fisheye::CALIB_FIX_SKEW;/*非常重要*/ double rms = fisheye::calibrate(object_points, corners, s.imageSize, K, D, cv::noArray(), cv::noArray(), flag, cv::TermCriteria(3, 20, 1e-6)); return make_tuple(Mat(K), Mat(D), rms); }
代码非常简单,和标定普通的镜头的区别在于:
- 角点坐标和和对应的三维点坐标为double类型,普通镜头为float类型,弄混后不能正确执行
- flag必须指定CALIB_FIX_SKEW,代表求解时假设内参中fx=fy,与鱼眼镜头标定论文中一致,没有这个假设的话是得不到结果的
结果
测试了OpenCV的测试数据,34张图像进行标定,重投影误差均值为0.343542。
左边为源图像,右边为去畸变结果:
未完成工作
本来以为在畸变图像上找棋盘格角点会比一般的方法复杂一些,没想到利用FindChessboardCorners就可以成功找到,所以就暂时这样用了,对于畸变比较大的图像,或者手工标出角点,或者实现论文《Automatic Detection of Checkerboards on Blurred and Distorted Images》中自动提取棋盘格的方法。
参考:
http://docs.opencv.org/master/modules/calib3d/doc/calib3d.html