我正在尝试让 opencv 相机校准工作,但无法让它输出有效数据。我有一个未校准的相机,我想要校准,但为了测试我的代码,我使用 Azure Kinect 相机(彩色相机),因为 SDK 为其提供了正确的内在函数,我可以验证它们。我从稍微不同的角度收集了 30 个棋盘图像,我认为这应该足够了,并运行校准函数,但无论我传入什么标志,我得到的 fx 和 fy 值与正确的 fx 非常不同和fy,以及截然不同的失真系数。难道我做错了什么?我需要更多或更好的数据吗?
我正在使用的图像示例可以在这里找到:https://www.dropbox.com/sh/9pa94uedoe5mlxz/AABisSvgWwBT-bY65lfzp2N3a?dl=0
将它们保存在 c:\calibration_test 中以运行下面的代码。
#include <filesystem>
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
using namespace std;
namespace fs = experimental::filesystem;
static bool extractCorners(cv::Mat colorImage, vector<cv::Point3f>& corners3d, vector<cv::Point2f>& corners)
{
// Each square is 20x20mm
const float kSquareSize = 0.020f;
const cv::Size boardSize(7, 9);
const cv::Point3f kCenterOffset((float)(boardSize.width - 1) * kSquareSize, (float)(boardSize.height - 1) * kSquareSize, 0.f);
cv::Mat image;
cv::cvtColor(colorImage, image, cv::COLOR_BGRA2GRAY);
int chessBoardFlags = cv::CALIB_CB_ADAPTIVE_THRESH | cv::CALIB_CB_NORMALIZE_IMAGE;
if (!cv::findChessboardCorners(image, boardSize, corners, chessBoardFlags))
{
return false;
}
cv::cornerSubPix(image, corners, cv::Size(11, 11), cv::Size(-1, -1),
cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 30, 0.1));
// Construct the corners
for (int i = 0; i < boardSize.height; ++i)
for (int j = 0; j < boardSize.width; ++j)
corners3d.push_back(cv::Point3f(j * kSquareSize, i * kSquareSize, 0) - kCenterOffset);
return true;
}
int main()
{
vector<cv::Mat> frames;
for (const auto& p : fs::directory_iterator("c:\\calibration_test\\"))
{
frames.push_back(cv::imread(p.path().string()));
}
int numFrames = (int)frames.size();
vector<vector<cv::Point2f>> corners(numFrames);
vector<vector<cv::Point3f>> corners3d(numFrames);
int framesWithCorners = 0;
for (int i = 0; i < numFrames; ++i)
{
if (extractCorners(frames[i], corners3d[framesWithCorners], corners[framesWithCorners]))
{
++framesWithCorners;
}
}
numFrames = framesWithCorners;
corners.resize(numFrames);
corners3d.resize(numFrames);
// Camera intrinsics come from the Azure Kinect API
cv::Matx33d cameraMatrix(
914.111755f, 0.f, 960.887390f,
0.f, 913.880615f, 551.566528f,
0.f, 0.f, 1.f);
vector<float> distCoeffs = { 0.576340079f, -2.71203661f, 0.000563957903f, -0.000239689150f, 1.54344523f, 0.454746544f, -2.53860712f, 1.47272563f };
cv::Size imageSize = frames[0].size();
vector<cv::Point3d> rotations;
vector<cv::Point3d> translations;
int flags = cv::CALIB_USE_INTRINSIC_GUESS | cv::CALIB_FIX_PRINCIPAL_POINT | cv::CALIB_RATIONAL_MODEL;
double result = cv::calibrateCamera(corners3d, corners, imageSize, cameraMatrix, distCoeffs, rotations, translations,
flags);
// After this call, cameraMatrix has different values for fx and fy, and WILDLY different distortion coefficients.
cout << "fx: " << cameraMatrix(0, 0) << endl;
cout << "fy: " << cameraMatrix(1, 1) << endl;
cout << "cx: " << cameraMatrix(0, 2) << endl;
cout << "cy: " << cameraMatrix(1, 2) << endl;
for (size_t i = 0; i < distCoeffs.size(); ++i)
{
cout << "d" << i << ": " << distCoeffs[i] << endl;
}
return 0;
}
一些示例输出是:
fx: 913.143
fy: 917.965
cx: 960.887
cy: 551.567
d0: 0.327596
d1: -73.1837
d2: -0.00125972
d3: 0.002805
d4: -7.93086
d5: 0.295437
d6: -73.481
d7: -3.25043
d8: 0
d9: 0
d10: 0
d11: 0
d12: 0
d13: 0
知道我做错了什么吗?
额外问题:为什么我得到 14 个失真系数而不是 8 个?如果我放弃 CALIB_RATIONAL_MODEL,那么我只会得到 5 个(三个径向和两个切向)。
最佳答案
您需要从相机的整个视场拍摄图像,才能正确捕捉镜头畸变特征。您提供的图像仅显示棋盘在一个位置,略有角度。
理想情况下,棋盘图像应该均匀分布在图像平面的 x 和 y 轴上,一直到图像的边缘。确保板周围有足够的白边框始终可见,以保证检测的稳健性。
您还应该尝试捕捉棋盘离相机较近和较远的图像,而不仅仅是统一的距离。另一方面,您提供的不同角度看起来不错。
您可以在此答案中找到如何确保良好校准结果的详细指南:How to verify the correctness of calibration of a webcam?
将您的相机矩阵与来自 Azure Kinect API 的相机矩阵进行比较,它看起来并没有那么糟糕。原理点非常准确,焦距也在合理范围内。如果您使用我的提示和我提供的 SO 答案来提高输入的质量,结果应该会更加接近。通过距离来比较失真系数集并不能很好地工作,误差函数不是凸的,因此您可以有很多产生相对较好结果的局部最小值,但它们距离产生最佳结果的全局最小值还很远。如果这个解释对你来说有意义。
关于你的奖励问题:我只看到你返回的输出中填写了8个值,其余的是0,所以没有任何影响。我不确定输出是否与该函数不同。
关于opencv calibrateCamera 函数产生不好的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60553097/