如何使用 OpenCV 或任何其他库对图像应用失真?

问题描述

我按照 here 所示执行校准,但使用 cv.CALIB_RATIONAL_MODEL。

我使用了大约 40 张图像,我的平均重投影误差(由 cv2.calibrateCamera 计算)始终小于 0.5。

现在,我希望能够拍摄任何其他图像并将其应用到我从校准中获得的失真。

我知道我可以使用我在校准期间保存的角点来计算和重新扭曲校准图像,但我想仅使用我可以保存和使用的内在和/或外在参数对完全不同的图像应用失真。>

有可能吗?

我尝试将 np.negative(distortion) 传递给 cv.undistort(),希望它不会因负值而失真,因此它实际上会失真,但它不起作用并且给我带来了完全混乱的结果。

我尝试将其他 (one,two,three) 线程上的答案从 C++ 翻译成 Python,并通过研究失真背后的理论来创建我自己的函数,但它是不工作。

我可以利用其他任何库或理论来解决这个问题吗?

解决方法

OpenCV 不提供图像扭曲功能,但您可以自己实现。您只需要:

  • 内在参数(相机矩阵和失真系数)和失真图像的大小。
    表示为 cam_mtxdis_cefimage_size
  • 未失真图像的内在参数(相机矩阵)和大小。
    表示为 cam_mtx_udimage_size_ud
  • 失真和未失真图像之间的校正变换(旋转矩阵)。
    表示为 R

整流变换矩阵R可以通过stereoRectify()计算,但在单相机系统中,它通常是identity(你可以使用空的Mat)。


回忆一下对图像进行失真处理的过程,需要两个步骤:

  1. 计算校正图:initUndistortRectifyMap(cam_mtx,dis_cef,R,cam_mtx_ud,image_size_ud,CV_32FC1,map_x,map_y)
  2. 重新映射图像以消除失真:remap(image,image_ud,map_y,INTER_LINEAR);

校正图(map_xmap_y)描述了从未失真图像到失真图像的像素坐标图。有了它们,未失真图像上的每个像素都可以找到它在失真图像上的位置,然后通过插值检索像素值。这就是 remap 的工作原理。

因此,要生成未失真校正图,您需要循环目标(未失真)图像的像素并失真点。


现在,对图像应用扭曲与不扭曲相似。

您需要通过循环目标(扭曲)图像的像素和去扭曲点来生成“扭曲贴图”。然后,使用 remap 应用扭曲。

代码如下:

Mat map_x = Mat(image_size,CV_32FC1);
Mat map_y = Mat(image_size,CV_32FC1);
vector<Point2f> pts_ud,pts_distort;
for (int y = 0; y < image_size.height; ++y)
    for (int x = 0; x < image_size.width; ++x)
        pts_distort.emplace_back(x,y);
undistortPoints(pts_distort,pts_ud,cam_mtx,cam_mtx_ud);
for (int y = 0; y < image_size.height; ++y) {
    float* ptr1 = map_x.ptr<float>(y);
    float* ptr2 = map_y.ptr<float>(y);
    for (int x = 0; x < image_size.width; ++x) {
        const auto& pt = pts_ud[y * image_size.width + x];
        ptr1[x] = pt.x;
        ptr2[x] = pt.y;
    }
}
Mat image_distort;
remap(image_ud,image_distort,INTER_LINEAR);

我不擅长python,所以我用C++编写了代码。很抱歉,但我认为代码不难阅读。