Skip to content

使用方格棋盘进行相机标定

本教程的目标是学习如何在一组棋盘图像的基础上标定一台相机。

测试数据:使用 data/chess 文件夹中的图像。

  • 通过在 cmake 配置中将 BUILD_EXAMPLES 设为 ON,从而带示例编译 OpenCV。

  • 进入 bin 文件夹,使用 imagelist_creator 创建你的图像的 XML/YAML 列表。

  • 然后,运行标定示例以获取相机参数。方格尺寸设为 3cm。

现在,让我们编写代码来检测图像中的棋盘,并求出它与相机之间的距离。你可以将此方法应用于任何具有已知三维几何形状、且能在图像中检测到的物体。

测试数据:使用 data 文件夹中的 chess_test*.jpg 图像。

  • 创建一个空的控制台项目。加载一张测试图像:
Mat img = imread(argv[1], IMREAD_GRAYSCALE);
  • 使用 findChessboard 函数检测该图像中的棋盘:
bool found = findChessboardCorners( img, boardSize, ptvec, CALIB_CB_ADAPTIVE_THRESH );
  • 现在,编写一个函数,在任意坐标系中生成一个棋盘三维坐标的 vector<Point3f> 数组。为简单起见,我们选择这样一个坐标系:棋盘的某个角点位于原点,且棋盘位于 z = 0 平面。

  • 从 XML/YAML 文件读取相机参数:

FileStorage fs( filename, FileStorage::READ );
Mat intrinsics, distortion;
fs["camera_matrix"] >> intrinsics;
fs["distortion_coefficients"] >> distortion;
  • 现在我们可以通过运行 `solvePnP` 来求解棋盘位姿了:
vector<Point3f> boardPoints;
// fill the array
...
solvePnP(Mat(boardPoints), Mat(foundBoardCorners), cameraMatrix,
distCoeffs, rvec, tvec, false);
  • 像标定示例中那样计算重投影误差(参见 opencv/samples/cpp/calibration.cpp 中的 computeReprojectionErrors 函数)。

问题:你会如何计算从相机原点到任意一个角点的距离? 回答:在使用 solvePnP 求得相机位姿后,旋转向量(rvec)和平移向量(tvec)定义了世界(棋盘)坐标系与相机坐标系之间的变换。要计算从相机原点到任意一个棋盘角点的距离,首先将该三维点从棋盘坐标系变换到相机坐标系(如果尚未变换的话),然后使用 L2 范数计算其欧几里得距离,例如:

// assuming 'point' is the 3D position of a chessboard corner in the camera coordinate system
double distance = norm(point);

这等价于对该三维点坐标 (x, y, z) 应用 L2 范数。