摘要:
本文将从以下几个方面展开,结合典型代码深入解析 OpenCV 中的相机标定过程,重点阐述重投影误差的计算方法与实际意义,并通过一个calcBoardCornerPositions()
函数详细讲解棋盘格角点三维坐标的构建逻辑。
在计算机视觉领域,相机标定(Camera Calibration)是获取相机内参数和畸变参数的关键步骤。而重投影误差(Reprojection Error)则是衡量标定精度的重要指标。在使用 OpenCV 进行标定时,我们经常会接触到一个名为 computeReprojectionErrors()
的函数,它用于计算重投影误差,帮助我们评估标定结果的准确性。
↓↓↓↓↓↓ 以下正文 ↓↓↓↓↓↓
在相机标定中,我们使用一个带有已知几何尺寸的标定板(如棋盘格)进行拍摄,通过提取图像中的角点并与其在世界坐标系中的真实三维位置进行比较,来拟合相机的内参(焦距、主点)与畸变参数。
重投影误差定义为:
将三维点通过估计得到的相机内参、外参投影回图像平面后,与实际检测到的二维图像点之间的距离。
重投影误差越小,说明标定模型与实际相机系统越吻合。
在 OpenCV 中,这个误差通常用像素为单位来表示,计算结果常用于衡量整个标定质量的好坏。
computeReprojectionErrors(objectPoints, rvecs, tvecs, reprojectionErrors);
objectPoints
: 世界坐标系中的三维点数组rvecs
: 每一张标定图像的旋转向量tvecs
: 每一张标定图像的平移向量reprojectionErrors
: 输出每张图像的重投影误差一般经验值如下:
因此,如果你得到的误差值为 20.5 像素,就需要对标定流程和输入数据进行彻底排查。
当我们遇到过大的重投影误差(比如 10 像素以上)时,很可能是以下几个方面出现了问题:
drawChessboardCorners()
显示检测结果,手动验证角点匹配质量。CV_CALIB_RATIONAL_MODEL
。错误的模型可能造成拟合能力下降。相机矩阵的一般形式如下:
[ fx 0 cx ]
[ 0 fy cy ]
[ 0 0 1 ]
fx
, fy
: 焦距,单位为像素cx
, cy
: 图像主点(通常为图像中心)如果你得到了一个如下的相机矩阵:
[42880.11, 0, 959.5;
0, 42880.11, 539.5;
0, 0, 1]
说明焦距异常大,很可能是以下问题导致的:
建议检查棋盘格实际物理尺寸,并可尝试使用 OpenCV 的 calibrateCamera()
函数中的 CALIB_USE_INTRINSIC_GUESS
标志手动输入初值。
在相机标定时,我们需要构造真实世界中棋盘格角点的位置(objectPoints),这组点是在一个统一世界坐标系中的固定值,是整个标定过程的关键输入。
下面是一段典型的构造函数:
private void calcBoardCornerPositions(Mat corners) {
final int cn = 3;
float[] positions = new float[mCornersSize * cn];
for (int i = 0; i < mPatternSize.height; i++) {
for (int j = 0; j < mPatternSize.width * cn; j += cn) {
positions[(int) (i * mPatternSize.width * cn + j + 0)] =
(2 * (j / cn) + i % 2) * (float) mSquareSize;
positions[(int) (i * mPatternSize.width * cn + j + 1)] =
i * (float) mSquareSize;
positions[(int) (i * mPatternSize.width * cn + j + 2)] = 0;
}
}
corners.create(mCornersSize, 1, CvType.CV_32FC3);
corners.put(0, 0, positions);
}
mPatternSize
: 表示棋盘格的宽度(列数)和高度(行数)。mCornersSize
: 所有角点的总数,等于 rows * cols
mSquareSize
: 每个格子的边长(单位应与物理一致,比如毫米或米)positions
: 一维数组,存储所有角点的三维坐标(X, Y, Z)Mat corners
: 输出结果,一个 OpenCV 的矩阵,每一行为一个三维坐标点(CV_32FC3)(2 * (j / cn) + i % 2) * mSquareSize
这表示 x 轴的坐标,注意 (j / cn)
得到的是列索引 col
,乘以2再加上偶数行偏移 i % 2
,可能是为了构建某种 错位网格或蜂窝形图案,而不是标准矩形棋盘格。
i * mSquareSize
表示 y 轴坐标,也就是所在行数乘以边长。
z = 0
说明所有角点都在 z=0 的平面上,即假设标定板是平的、位于 XY 平面。
统一单位: 确保 mSquareSize
和 objectPoints 的单位统一,并与实际物理尺寸一致。
角点可视化: 使用 drawChessboardCorners()
函数确认每张图像角点是否准确。
图像多样性: 包括不同角度、远近、旋转的图片,有利于提高拟合精度。
重投影误差判断标准:
5px 时大概率是数据异常或逻辑错误。
参数初始化: 可尝试为 calibrateCamera()
提供初始猜测值,防止最优化陷入局部极值。
OpenCV 的相机标定流程虽然成熟,但对输入数据质量和逻辑严谨性要求较高。重投影误差是衡量标定质量的重要指标,若遇到过大数值,往往意味着标定逻辑、数据精度或单位设定存在问题。同时,正确构造棋盘格角点的三维坐标对于整个流程至关重要。