OpenCV 鱼眼校准 C++ 输出不同于 Python

OpenCV fisheye calibration C++ output differs from Python

我目前正在研究有鱼眼的相机(虽然不多但仍然如此),我正在努力消除它的失真。

作为初学者:我对 opencv 不是很熟悉,在尝试做任何事情时我总是喜欢看文档。 (and/or 在这里寻找我的问题的答案)。

所以我在网上看到了一些例子,我尝试了解决方案并得到了一些结果。

这是我的发现:

DIM=(1094, 729)
K=np.array([
    [1307.2807020496643, 0.0, 530.3754311563506], 
    [0.0, 1318.342691460933, 354.98352268131123], 
    [0.0, 0.0, 1.0]
])
D=np.array([
    [-0.2994762856767568],
    [0.5036082961388784],
    [-4.231072729639434],
    [3.8646397788794578]
])
def undistort(img_path):    
    img = cv2.imread(img_path)
    h,w = img.shape[:2]
    print(K)
    print(D)
    print(np.eye(3))
    print(DIM)
    map1, map2 = cv2.fisheye.initUndistortRectifyMap(K, D, np.eye(3), K, DIM, cv2.CV_16SC2)
    
    undistorted_img = cv2.remap(img, map1, map2, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT)
    cv2.imshow("undistorted", undistorted_img)
    cv2.imwrite("test.jpg", undistorted_img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
if __name__ == '__main__':
    for p in sys.argv[1:]:
        undistort(p)

这是我用来消除图像失真的 python 脚本。顶部的数据 (K & D) 是通过另一个脚本生成的。我没有提到它,因为我有一个 C++ 翻译,它显示相同 base_picture

的相同结果

对于这个函数,如果我给出一个扭曲的图像,比如: 我得到了这个结果:

所以我可以看到微小的失真已经解决了。

但是当我尝试在 C++ 中实现相同的功能时,如下所示:

    src = cv::imread(“path/to/image.jpg");

    cv::Size size = {src.cols, src.rows};

    cv::Mat K(3, 3, cv::DataType<double>::type);
    K.at<double>(0, 0) = 1307.2807020496643;
    K.at<double>(0, 1) = 0.0;
    K.at<double>(0, 2) = 530.3754311563506;

    K.at<double>(1, 0) = 0.0;
    K.at<double>(1, 1) = 1318.342691460933;
    K.at<double>(1, 2) = 354.98352268131123;

    K.at<double>(2, 0) = 0.0;
    K.at<double>(2, 1) = 0.0;
    K.at<double>(2, 2) = 1.0;

    cv::Mat D(4, 1, cv::DataType<double>::type);
    D.at<double>(0, 0) = -0.2994762856767568;
    D.at<double>(1, 0) = 0.5036082961388784;
    D.at<double>(2, 0) = -4.231072729639434;
    D.at<double>(3, 0) = 3.8646397788794578;
    cv::Mat E = cv::Mat::eye(3, 3, cv::DataType<double>::type);

    cv::Mat map1;
    cv::Mat map2;

    std::cout << K << std::endl;
    std::cout << D << std::endl;
    std::cout << E << std::endl;
    std::cout << size << std::endl;

    cv::initUndistortRectifyMap(K, D, E, K, size, CV_16SC2, map1, map2);

    cv::Mat undistort;
    cv::remap(src, undistort, map1, map2, CV_INTER_LINEAR,
              CV_HAL_BORDER_CONSTANT);

基本图像仍然相同,但我得到的结果是:

如您所知,情况变得更糟了……

我在我的 python 脚本和 C++ 程序中丢弃了 K、D 和 E(对于相同的基本图片,两者给出相同的结果)(我的意思是当我计算数据时)

从 initUndistortRectifyMap 到重新映射都出错,最后 imshow 完全不是我所期望的。

我尝试在 python 脚本和 C++ 程序中转储 map1 和 map2(没有查看所有数据),我注意到其中一张地图的末尾(没有两者都看)结果不同。

由于我使用相同的参数调用该函数(据我所知),我希望两个程序之间的映射相等。

我做错了什么吗?喜欢弄乱类型之类的吗?

从 cv::imread 或从相机获取的帧计算图像会改变什么吗?

(只是让你知道,进行计算的帧(.jpg)是来自相机帧采集的cv::imwrite,那么我打算不再使用图像而只是工作cv::Mat 填充了相机采集的数据。)

(我知道最后枚举不一样,但即使使用 cv::BORDER_CONSTANT 我仍然有同样的问题。)

您使用了 cv::initUndistortRectifyMap 而不是 cv::fisheye::initUndistortRectifyMap

使用这段代码我得到了正确的结果:

int main()
{
    cv::Mat src = cv::imread("C:/Whosebug/Input/fisheyeCalib.jpg");

        cv::Size size = { src.cols, src.rows };

    cv::Mat K(3, 3, cv::DataType<double>::type);
    K.at<double>(0, 0) = 1307.2807020496643;
    K.at<double>(0, 1) = 0.0;
    K.at<double>(0, 2) = 530.3754311563506;

    K.at<double>(1, 0) = 0.0;
    K.at<double>(1, 1) = 1318.342691460933;
    K.at<double>(1, 2) = 354.98352268131123;

    K.at<double>(2, 0) = 0.0;
    K.at<double>(2, 1) = 0.0;
    K.at<double>(2, 2) = 1.0;

    cv::Mat D(4, 1, cv::DataType<double>::type);
    D.at<double>(0, 0) = -0.2994762856767568;
    D.at<double>(1, 0) = 0.5036082961388784;
    D.at<double>(2, 0) = -4.231072729639434;
    D.at<double>(3, 0) = 3.8646397788794578;
    cv::Mat E = cv::Mat::eye(3, 3, cv::DataType<double>::type);

    cv::Mat map1;
    cv::Mat map2;

    std::cout << K << std::endl;
    std::cout << D << std::endl;
    std::cout << E << std::endl;
    std::cout << size << std::endl;

    // Here's the error:
    //cv::initUndistortRectifyMap(K, D, E, K, size, CV_16SC2, map1, map2);
    cv::fisheye::initUndistortRectifyMap(K, D, E, K, size, CV_16SC2, map1, map2);

    cv::Mat undistort;
    cv::remap(src, undistort, map1, map2, CV_INTER_LINEAR,
        CV_HAL_BORDER_CONSTANT);

    cv::imwrite("C:/Whosebug/Input/fisheyeCalib_output.jpg", undistort);
    cv::imshow("undist", undistort);
    cv::waitKey(0);
}