相机标定规范及opencv实现

一、标定规范:
对于张正友相机标定的标定规范,版本也有很多,我这里只写一下我个人使用的方法和遇到的问题以及解决办法。
1. 标定的棋盘格一定要选黑白间隔的,而且不要有边框,就白色底色上话黑白格就可以,如果有边框的棋盘格,可能会检测不到角点。
2. 拍摄棋盘格的时候,要保证棋盘格大概占据视野范围的三分之二,最少不能少于二分之一,太小的话会因为角点局限在比较小的范围内,造成拟合的误差。如图:
opencv定位文字 opencv标定_计算机视觉
3. 如果只是矫正图像不测距的话,那么拍照的张数在10到15张就差不多了,但是拍照的时候要尽量保证棋盘格的移动范围能够覆盖整个视野,这样才能有效的采集各个位置的角点,能够更准确的矫正图像。
4. 如果考虑测距,那么就需要固定相机到物体的距离,而且如果是张正友标定的话,还需要保证相机与被测物体的角度垂直,然后要用格子大小已知且准确的棋盘格,在标定时需要计算像素和实际距离的比例关系,这个可以直接从棋盘格获取,也可以用其他参照物。如果是测距的话,需要的精度较高,参照物的选取很重要,而且矫正拍照最好在20到30张图片。
5. 标定拍照操作,保持相机与棋盘格绝对的垂直,拍照时要不断的在相机的视野内移动棋盘格的位置,保证棋盘格的角点要尽量多的分布在相机视野内,因为相机矫正是通过散点拟合多项式的系数,所以点的获取对于矫正参数的计算非常重要。

二、代码实现
vector worldPoints3;
for (int j = 0; j < ya; j++) {
for (int k = 0; k < xa; k++) {
worldPoints3.push_back(Point3f(k1.0, j1.0, 0.0f));
}
}
这部分代码是为了生成世界坐标的,通俗的讲就是给棋盘格的角点编个序号,这个序号对应棋盘格角点的位置,是opencv的findChessboardCorners方法中必备的条件之一。
bool found = findChessboardCorners(src, Size(xa, ya), z_points1, CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_NORMALIZE_IMAGE);
这行代码是寻找角点的坐标的,找到的角点坐标就存在z_points1里面,可以画出来看一下。

得到角点后,接下来就是矫正了,接下来使用OpenCV的cv::calibrateCamera方法。

cv::calibrateCamera(worldPoints2, corners2, images[0].size(), cameraMatrix_, distCoeffs_, rvecs, tvecs, cv::CALIB_FIX_PRINCIPAL_POINT);

首先来看一下参数介绍

	cameraMatrix为内参数矩阵。输入一个cv::Mat cameraMatrix即可。
	distCoeffs为畸变矩阵。输入一个cv::Mat distCoeffs即可。
	rvecs为旋转向量;应该输入一个cv::Mat的vector
	vector<cv::Mat> rvecs因为每个vector<Point3f>会得到一个rvecs。
	tvecs为位移向量;和rvecs一样,也应该为vector<cv::Mat> tvecs

得到矫正参数之后,可以通过cv::undistort方法得到矫正后的图像。

cv::undistort(image, realImage, cameraMatrix_, distCoeffs_);

另外,还可以利用cv::initUndistortRectifyMap的方法和remap的方法得到矫正后的图像,但是initUndistortRectifyMap返回的mapx和mapy具体有什么用我也没搞明白。
如果要获取图像中每个点标定后的修正坐标,还需要使用cv::undistortPoints方法,输入的是以左上角为原点,向右为x轴正方向,
向下为y轴正方向的点,得到的点是相对于图像正中心的,如果得到的是一个小于零的数,那说明是得到了偏移量,
需要对应乘上图像的行列数,如果要直接得出像素坐标,则需要在最后加上cameraMatrix_参数。

cv::undistortPoints(obj_p, res_p, cameraMatrix_, distCoeffs_, cv::noArray(), cameraMatrix_);