代码为cameraCalib.cpp
运行: roslaunch camera_lidar_calibration cameraCalib.launch
相片拍摄:准备20张以上的照片数据,各个角度和位置都要覆盖,拍摄的时候距离不要太近(3米左右),如图所示:
Mat imageInput = imread(filename);
Size board_size = Size(row_number, col_number); /* 标定板上每行、列的角点数 */
vector
0 == findChessboardCorners(imageInput, board_size, image_points_buf)
Mat view_gray; // 保存对应的灰度图
cvtColor(imageInput, view_gray, cv::COLOR_RGB2GRAY); // 转灰度图
/* 亚像素精确化 */
// image_points_buf 初始的角点坐标向量,同时作为亚像素坐标位置的输出
// Size(5,5) 搜索窗口大小
// (-1,-1)表示没有死区
// TermCriteria 角点的迭代过程的终止条件, 可以为迭代次数和角点精度两者的组合
cornerSubPix(view_gray, image_points_buf, Size(5, 5), Size(-1, -1), TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::MAX_ITER, 30, 0.1));
(具体的原理后面补上)
drawChessboardCorners(view_gray, board_size, image_points_buf, false); // 用于在图片中标记角点
这里的boad_size 的height为棋盘格的数值方向的角点数,width为水平方向角点数,这里注意不包含最外一圈黑块。下面图片对应的width = 8, height = 6。其中每个方块的尺寸为Size square_size(w,h),w和h单位为mm。
这里假定左上角的角点坐标为(0,0),按照格子的尺寸计算其他的角点的坐标,这里假定标定板位于世界坐标系z=0的平面上
/* 初始化标定板上角点的三维坐标,以(0,0)坐标开始,每个角点的长宽由测量确定 */
int i, j, t;
for (t = 0; t tempPointSet;
for (i = 0; i
/* 开始标定 */
// object_points 世界坐标系中的角点的三维坐标
// image_points_seq 每一个内角点对应的图像坐标点
// image_size 图像的像素尺寸大小
// cameraMatrix 输出,内参矩阵
// distCoeffs 输出,畸变系数
// rvecsMat 输出,旋转向量
// tvecsMat 输出,位移向量
// 0 标定时所采用的算法
calibrateCamera(object_points, image_points_seq, image_size, cameraMatrix, distCoeffs, rvecsMat, tvecsMat, 0); //
/* 通过得到的摄像机内外参数,对假定空间的三维点进行重新投影计算,得到新的投影点,保存在image_points2中 */
输入:假定的世界点,是世界点对应的旋转,平移矩阵,相机内参,畸变系数,输出投影到相机平面的点坐标
projectPoints(tempPointSet, rvecsMat[i], tvecsMat[i], cameraMatrix, distCoeffs, image_points2);
这里学习一个小知识:
CV_
CV_32FC2表示32位浮点数双通道
double total_err = 0.0; /* 所有图像的平均误差的总和 */
double err = 0.0; /* 每幅图像的平均误差 */
vector image_points2; /* 保存重新计算得到的投影点 */
fout << "Average error: \n";
for (i = 0; i tempPointSet = object_points[i];
/* 通过得到的摄像机内外参数,对假定空间的三维点进行重新投影计算,得到新的投影点,保存在image_points2中 */
projectPoints(tempPointSet, rvecsMat[i], tvecsMat[i], cameraMatrix, distCoeffs, image_points2);
/* 计算新的投影点和旧的投影点之间的误差*/
vector tempImagePoint = image_points_seq[i]; // 第i张图片的角点坐标
Mat tempImagePointMat = Mat(1, tempImagePoint.size(), CV_32FC2); // 双通道数据,每个存放Vec2f
Mat image_points2Mat = Mat(1, image_points2.size(), CV_32FC2);
for (unsigned int j = 0; j < tempImagePoint.size(); j++) {
image_points2Mat.at(0, j) = Vec2f(image_points2[j].x, image_points2[j].y);
tempImagePointMat.at(0, j) = Vec2f(tempImagePoint[j].x, tempImagePoint[j].y);
}
err = norm(image_points2Mat, tempImagePointMat, NORM_L2); // 计算L2距离
total_err += err /= point_counts[i];
fout << "The error of picture " << i + 1 << " is " << err << " pixel" << endl;
}
fout << "Overall average error is: " << total_err / image_count << " pixel" << endl << endl;
1个3x3的内参矩阵,5个畸变纠正参数(k1,k2,p1,p2,k3)
Matlab中的cameraCalibrator工具可以标定内参,我们只需要结果中的1,,2和11数据