gpt4 book ai didi

c++ - OpenCV 3.0 : Calibration not fitting as expected

转载 作者:IT老高 更新时间:2023-10-28 14:01:34 25 4
gpt4 key购买 nike

当我使用 OpenCV 3.0 calibrateCamera 时,我得到了意想不到的结果。这是我的算法:

  1. 加载 30 个图像点
  2. 加载 30 个对应的世界点(在这种情况下共面)
  3. 使用点来校准相机,只是为了不失真
  4. 不扭曲图像点,但不要使用内在函数(共面世界点,所以内在函数很狡猾)
  5. 使用未失真的点找到单应性,转换为世界点(可以这样做,因为它们都是共面的)
  6. 使用单应性和透视变换将未失真的点映射到世界空间
  7. 将原始世界点与映射点进行比较

我的点很嘈杂,只是图像的一小部分。单个 View 有 30 个共面点,因此我无法获得相机内在函数,但应该能够获得失真系数和单应性以创建正面平行 View 。

正如预期的那样,误差因校准标志而异。然而,它的变化与我的预期相反。如果我允许所有变量进行调整,我希望错误会下降。我不是说我期待更好的模型;我实际上期望过度拟合,但这仍然应该减少错误。我看到的是,我使用的变量越少,我的错误就越低。最好的结果是使用直单应性。

我有两个可疑的原因,但它们似乎不太可能,我想在播放它们之前听到一个纯粹的答案。我已经提取了代码来做我正在谈论的事情。有点长,但是包含了加载点。

代码似乎没有错误;我使用了“更好”的点并且效果很好。我想强调的是,这里的解决方案不能是使用更好的点或进行更好的校准;练习的重点是了解各种校准模型如何响应不同质量的校准数据。

有什么想法吗?

已添加

明确地说,我知道结果会很糟糕,我希望如此。我也明白,当测试未用于训练模型的点时,我可能会学习到糟糕的失真参数,这会导致更糟糕的结果。我不明白的是,当使用训练集作为测试集时,失真模型如何有更多的错误。也就是说,如果 cv::calibrateCamera 应该选择参数来减少所提供的训练集上的误差,但它产生的误差比它刚刚为 K!, K2, ... K6, P1 选择 0 时产生的误差更大, P2。不管数据不好与否,它至少应该在训练集上做得更好。在我说这些数据不适合这个模型之前,我必须确保我正在尽我所能利用可用的数据,而且在这个阶段我不能这么说。

这里是示例图片

标有绿色引脚的点。这显然只是一个测试图像。 Example image

这里有更多示例

下面的图片是从上面的大图裁剪而来的。中心没有改变。这就是当我仅使用从绿色引脚手动标记的点并允许 K1(仅 K1)从 0 变化时发生的情况:

之前 Set A image, 1920 by 1080, distorted

之后 Set A image, 1920 by 1080, undistorted

我会把它归结为一个错误,但是当我使用覆盖更多屏幕的更大点集时,即使是从一个平面上,它也能很好地工作。这看起来很可怕。不过,这个错误并没有您从图片中想象的那么严重。

// Load image points
std::vector<cv::Point2f> im_points;
im_points.push_back(cv::Point2f(1206, 1454));
im_points.push_back(cv::Point2f(1245, 1443));
im_points.push_back(cv::Point2f(1284, 1429));
im_points.push_back(cv::Point2f(1315, 1456));
im_points.push_back(cv::Point2f(1352, 1443));
im_points.push_back(cv::Point2f(1383, 1431));
im_points.push_back(cv::Point2f(1431, 1458));
im_points.push_back(cv::Point2f(1463, 1445));
im_points.push_back(cv::Point2f(1489, 1432));
im_points.push_back(cv::Point2f(1550, 1461));
im_points.push_back(cv::Point2f(1574, 1447));
im_points.push_back(cv::Point2f(1597, 1434));
im_points.push_back(cv::Point2f(1673, 1463));
im_points.push_back(cv::Point2f(1691, 1449));
im_points.push_back(cv::Point2f(1708, 1436));
im_points.push_back(cv::Point2f(1798, 1464));
im_points.push_back(cv::Point2f(1809, 1451));
im_points.push_back(cv::Point2f(1819, 1438));
im_points.push_back(cv::Point2f(1925, 1467));
im_points.push_back(cv::Point2f(1929, 1454));
im_points.push_back(cv::Point2f(1935, 1440));
im_points.push_back(cv::Point2f(2054, 1470));
im_points.push_back(cv::Point2f(2052, 1456));
im_points.push_back(cv::Point2f(2051, 1443));
im_points.push_back(cv::Point2f(2182, 1474));
im_points.push_back(cv::Point2f(2171, 1459));
im_points.push_back(cv::Point2f(2164, 1446));
im_points.push_back(cv::Point2f(2306, 1474));
im_points.push_back(cv::Point2f(2292, 1462));
im_points.push_back(cv::Point2f(2278, 1449));

// Create corresponding world / object points
std::vector<cv::Point3f> world_points;
for (int i = 0; i < 30; i++) {
world_points.push_back(cv::Point3f(5 * (i / 3), 4 * (i % 3), 0.0f));
}

// Perform calibration
// Flags are set out so they can be commented out and "freed" easily
int calibration_flags = 0
| cv::CALIB_FIX_K1
| cv::CALIB_FIX_K2
| cv::CALIB_FIX_K3
| cv::CALIB_FIX_K4
| cv::CALIB_FIX_K5
| cv::CALIB_FIX_K6
| cv::CALIB_ZERO_TANGENT_DIST
| 0;

// Initialise matrix
cv::Mat intrinsic_matrix = cv::Mat(3, 3, CV_64F);
intrinsic_matrix.ptr<float>(0)[0] = 1;
intrinsic_matrix.ptr<float>(1)[1] = 1;
cv::Mat distortion_coeffs = cv::Mat::zeros(5, 1, CV_64F);

// Rotation and translation vectors
std::vector<cv::Mat> undistort_rvecs;
std::vector<cv::Mat> undistort_tvecs;

// Wrap in an outer vector for calibration
std::vector<std::vector<cv::Point2f>>im_points_v(1, im_points);
std::vector<std::vector<cv::Point3f>>w_points_v(1, world_points);

// Calibrate; only 1 plane, so intrinsics can't be trusted
cv::Size image_size(4000, 3000);
calibrateCamera(w_points_v, im_points_v,
image_size, intrinsic_matrix, distortion_coeffs,
undistort_rvecs, undistort_tvecs, calibration_flags);

// Undistort im_points
std::vector<cv::Point2f> ud_points;
cv::undistortPoints(im_points, ud_points, intrinsic_matrix, distortion_coeffs);

// ud_points have been "unintrinsiced", but we don't know the intrinsics, so reverse that
double fx = intrinsic_matrix.at<double>(0, 0);
double fy = intrinsic_matrix.at<double>(1, 1);
double cx = intrinsic_matrix.at<double>(0, 2);
double cy = intrinsic_matrix.at<double>(1, 2);

for (std::vector<cv::Point2f>::iterator iter = ud_points.begin(); iter != ud_points.end(); iter++) {
iter->x = iter->x * fx + cx;
iter->y = iter->y * fy + cy;
}

// Find a homography mapping the undistorted points to the known world points, ground plane
cv::Mat homography = cv::findHomography(ud_points, world_points);

// Transform the undistorted image points to the world points (2d only, but z is constant)
std::vector<cv::Point2f> estimated_world_points;
std::cout << "homography" << homography << std::endl;
cv::perspectiveTransform(ud_points, estimated_world_points, homography);

// Work out error
double sum_sq_error = 0;
for (int i = 0; i < 30; i++) {
double err_x = estimated_world_points.at(i).x - world_points.at(i).x;
double err_y = estimated_world_points.at(i).y - world_points.at(i).y;

sum_sq_error += err_x*err_x + err_y*err_y;
}
std::cout << "Sum squared error is: " << sum_sq_error << std::endl;

最佳答案

我会随机抽取 30 个输入点的样本,并在每种情况下计算单应性以及估计的单应性下的误差,一个 RANSAC 方案,并验证误差水平和单应性参数之间的一致性,这可以只是一个验证全局优化过程。我知道这似乎没有必要,但这只是对程序对输入(噪声级别、位置)的敏感程度的健全性检查

此外,修复大多数变量似乎可以使您的错误最少,因为最小化过程中的自由度较小。我会尝试修复不同的问题以建立另一个共识。至少这会让你知道哪些变量对输入的噪声水平最敏感。

希望图像的这么小部分靠近图像中心,因为它会产生最少的镜头失真。在您的情况下是否可以使用不同的失真模型?一种更可行的方法是在给定图案相对于图像中心的位置的情况下调整失真参数的数量。

在不知道算法约束的情况下,我可能误解了这个问题,这也是一种选择,在这种情况下我可以回滚。

我想将此作为评论,但我没有足够的积分。

关于c++ - OpenCV 3.0 : Calibration not fitting as expected,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31292266/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com