【问题标题】:How to apply distortion on an image using OpenCV or any other library?如何使用 OpenCV 或任何其他库对图像应用失真?
【发布时间】:2021-06-27 21:30:28
【问题描述】:

我正在执行校准,如 here 所示,但使用 cv.CALIB_RATIONAL_MODEL。

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

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

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

有可能吗?

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

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

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

【问题讨论】:

    标签: python opencv computer-vision camera-calibration opencv-python


    【解决方案1】:

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

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

    校正变换矩阵R可以通过stereoRectify()计算,但在单机系统中,它通常是恒等式(你可以使用空的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_x, 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, dis_cef, R, 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, map_x, map_y, INTER_LINEAR);
    

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

    【讨论】:

    • 嘿,这真的很有帮助,我现在可以真正理解发生了什么,即使我无法让它工作。
    • @VictorBian 你碰巧测试过代码吗?这不起作用。它创建灰色图像。我不明白你如何生成pts_distort。它只是创建了一个像 0,1 0,2 0,3 这样的网格,当馈送到 undistortPoints() 时似乎没有任何合理的价值
    • @Arya S. 这本书Learning OpenCV 3 可以帮助你了解更多关于initUndistortRectifyMap的信息
    • 好的,网格创建实际上是有意义的,因为它只是将像素位置输出为点。但是,是的,代码仍然无法工作,因为pts_ud 处于相对坐标中,您必须先将其带到相机坐标(乘以 K),然后再将其提供给重新映射。所以ptr1[x] = pt.x * fx + cy; ptr2[x] = pt.y * fy + cy;。然后它可以工作了,在 Python 和 C++ 中都试过了。
    • @Arya S. 代码有效,here 是一个演示,老兄。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-01
    • 1970-01-01
    • 2013-09-15
    • 1970-01-01
    相关资源
    最近更新 更多