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

Posted

技术标签:

【中文标题】OpenCV 鱼眼校准 C++ 输出与 Python 不同【英文标题】:OpenCV fisheye calibration C++ output differs from Python 【发布时间】:2020-02-07 16:50:29 【问题描述】:

我目前正在制作一个有鱼眼的相机(虽然不多但仍然如此),并且我正在努力消除它的失真。

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

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

这是我发现的:

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: :填充了相机采集数据的垫子。)

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

【问题讨论】:

为什么你将 K 和 D 矩阵元素重新分配一个 by 而不是直接给一个 Mat?你能试着用cv::initUndistortRectifyMap(K, D, Mat(), Mat(), src.size(), CV_16SC2, map1, map2);替换cv::initUndistortRectifyMap(K, D, E, K, size, CV_16SC2, map1, map2); 好吧,我不知道我可能在哪里犯了错误,所以我决定这样做以确保我在做什么(保持与两个程序相同的数据)。好吧,nvm ...我使用了您的代码行cv::initUndistortRectifyMap(K, D, Mat(), Mat(), src.size(), CV_16SC2, map1, map2);,但不幸的是我仍然有相同的结果。我还注意到其他一些事情:使用静态相机和聚焦静态棋盘,当我计算 K&D 时,我得到了不同的垫子值。有时结果根本不接近! 通常只使用一张图像进行校准不会得到好的结果,我也很困惑你如何通过使用 python 代码获得好的结果。代码之间的差异原因应该是关于 K 和 D 矩阵,否则我看不到任何错误 好吧,我绝对不会使用单个图像进行校准。我在这里尝试做的是验证对于给定位置的给定图像,我能够不扭曲同一张图像,而且只有同一张。最后,是的,我肯定会有一个完整的校准过程,以不同的角度和位置评估棋盘的多张图片(但我的相机还没有自动对焦......所以......现在只有一张图片)(并且如前所述,K & D 具有相同的值(程序之间),但没有输出相同的结果) 在 C++ 中,您使用 cv::initUndistortRectifyMap 而不是 Fisheye。 Python 是 cv2.fisheye.initUndistortRectifyMap 【参考方案1】:

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

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

int main()

    cv::Mat src = cv::imread("C:/***/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:/***/Input/fisheyeCalib_output.jpg", undistort);
    cv::imshow("undist", undistort);
    cv::waitKey(0);

【讨论】:

以上是关于OpenCV 鱼眼校准 C++ 输出与 Python 不同的主要内容,如果未能解决你的问题,请参考以下文章

鱼眼校准 OpenCV Python

OpenCV - 鱼眼校准值(重用保存在 JSON 文件中的值)

使用 opencv 3.0 beta 进行鱼眼镜头校准

使用opencv3鱼眼模型的圆形鱼眼扭曲

如何通过openCV模拟鱼眼镜头效果?

如何使用 OpenCV 使裁剪后的鱼眼图像不失真