基于Emgu的摄像机标定和畸变矫正

本文介绍了使用 Emgu CV 库进行摄像头标定及畸变校正的方法,包括 CalibrateCamera 函数的使用及不同畸变校正方式,并对比了各自的优缺点。

一、简介

本文主要介绍用Emgu库函数进行摄像机标定和畸变矫正时所用到的几个函数,主要有CalibrateCamera, Undistort, Undistort2, cvInitUndistortRectifyMap和cvRemap.  其中函数语法摘抄自Emgu CV Library Documentation.对于相关函数的理解和使用必定有不足之处,望有看到者及时批评指正。

二、标定函数CalibrateCamera

1)语法

public static double CalibrateCamera(
	MCvPoint3D32f[][] objectPoints,
	PointF[][] imagePoints,
	Size imageSize,
	IntrinsicCameraParameters intrinsicParam,
	CALIB_TYPE calibrationType,
	out ExtrinsicCameraParameters[] extrinsicParams
)

说明:

objectPoints为标志点的世界坐标,是二维的,第一维是图像的索引(即第几幅图像),第二维是点的索引。

imagePoints为各标志点对应的图像坐标,同样是两维的,第一维是图像的索引,第二维是点的索引。

imageSize图像的大小,即宽和高,以像素为单位

intrinsicParam表示摄像机内参数,IntrinsicCameraParameters类的属性和方法可以技术手册中查看。

calibrationType是标定方法的标志位,通过设置该标志位可以对标定做些细微的控制,以使标定能够完成的更好。每种标志代表的具体含义可查阅《Learning OpenCV 中文版》一书的第429页。本人在项目中主要用其来控制是按照有畸变进行标定还是按照没有畸变进行标定,是否设置fx = fy, 是否设置主点在图像的中心等。

extrinsicParams是标定得到的外参数,主要包括旋转矩阵,每个方向的旋转量和平移向量。

2)举例

定义变量:

MCvPoint3D32f[][] corners_object_list;
PointF[][] corners_points_list; 
IntrinsicCameraParameters IC = new IntrinsicCameraParameters(); 
ExtrinsicCameraParameters[] EX_Param;

调用函数:

CameraCalibration.CalibrateCamera(corners_object_list, corners_points_list, ImgOri.Size, IC, CALIB_TYPE.CV_CALIB_FIX_ASPECT_RATIO, out EX_Param);

三、畸变矫正

1)方法一

ImgDst = IC.Undistort(ImgOri);
//IC是IntrinsicCameraParameters类的一个对象

最简单的方法便是用IntrinsicCameraParameters类的方法Undistort,但该方法的缺点是不能控制矫正后图像的大小,默认矫正后的图像与矫正前的图像大小一致,但由于矫正得到的图像往往是被放大(枕形畸变)了或者被缩小(桶形畸变)了,因此得到的畸变图像与原图像的范围不一样。如果想要得到同样大小同样场景范围的矫正图像则可以采用下面两种任一种方法。

2) 方法二

Image<Bgr, byte> ImgDst = ImgOri.CopyBlank();
IC.IntrinsicMatrix.CopyTo(newIntrinsicMatrix);
newIntrinsicMatrix[0, 0] = newIntrinsicMatrix[0, 0] * Scale;
newIntrinsicMatrix[1, 1] = newIntrinsicMatrix[1, 1] * Scale;
CvInvoke.cvUndistort2(ImgOri.Ptr, ImgDst.Ptr, IC.IntrinsicMatrix.Ptr, IC.DistortionCoeffs.Ptr, newIntrinsicMatrix.Ptr);

其中newIntrinsicMatrix与IC类型一样,用其来存储矫正后图像的内参数矩阵。Scale是矫正图像相对于原图像的缩放因子,由用户来定。
该方法可以通过修改Scale的值来控制矫正后图像的范围。如果矫正的是枕形失真,则Scale的值要小于1,才能使矫正图像不被裁掉一圈;如果矫正的是桶形失真,则Scale的值要大于1,才能使得矫正后图像周围黑边尽量少。

3)方法三

Image<Bgr, byte> ImgDst = ImgOri.CopyBlank(); 
IC.IntrinsicMatrix.CopyTo(newIntrinsicMatrix); 
newIntrinsicMatrix[0, 0] = newIntrinsicMatrix[0, 0] * Scale; 
newIntrinsicMatrix[1, 1] = newIntrinsicMatrix[1, 1] * Scale; 
Matrix<float> mapx, mapy; 
mapx = new Matrix<float>(imgHeight, imgWidth); 
mapy = new Matrix<float>(imgHeight, imgWidth); 
MCvScalar msc = new MCvScalar(0);
 
CvInvoke.cvInitUndistortRectifyMap(IC.IntrinsicMatrix.Ptr, IC.DistortionCoeffs.Ptr, IntPtr.Zero, newIntrinsicMatrix.Ptr, mapx.Ptr, mapy.Ptr); 
CvInvoke.cvRemap(ImgOri.Ptr, ImgDst.Ptr, mapx.Ptr, mapy.Ptr, 16, msc); 

该方法与方法二类似,只是把方法二拆分为两步来完成:cvInitUndistortRectifyMap和cvRemap。这样做的一个好处是,在对同一个相机拍出的大量图像进行畸变矫正时,第一步cvInitUndistortRectifyMap只需做一次便可,因此可以大大提高矫正的效率。

 

转载请注明出处:http://blog.csdn.net/xywy2008/article/details/18560475

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值