【问题标题】:OpenCV fisheye calibration cuts too much of the resulting imageOpenCV 鱼眼校准削减了太多的结果图像
【发布时间】:2016-03-22 20:12:48
【问题描述】:

我正在使用 OpenCV 校准使用带鱼眼镜头的相机拍摄的图像。

我正在使用的功能是:

  • findChessboardCorners(...); 查找校准图案的角落。
  • cornerSubPix(...); 细化找到的角落。
  • fisheye::calibrate(...); 校准相机矩阵和畸变系数。
  • fisheye::undistortImage(...); 使用从校准获得的相机信息来消除图像失真。

虽然生成的图像看起来确实不错(直线等),但我的问题是该函数切除了太多图像。

这是一个真正的问题,因为我使用了四个摄像头,它们之间的夹角为 90 度,并且当这么多边被切掉时,它们之间没有重叠区域,因为我要缝合图像.

我研究过使用fisheye::estimateNewCameraMatrixForUndistortRectify(...),但我无法得到好的结果,因为我不知道我应该输入什么作为R 输入,因为fisheye::calibrate 的旋转矢量输出是3xN(其中 N 是校准图像的数量),fisheye::estimateNewCameraMatrixForUndistortRectify 需要 1x3 或 3x3。

下面的图片显示了我的未失真结果的图片,以及我理想中想要的那种结果的示例。

不失真:

想要的结果示例:

【问题讨论】:

    标签: c++ opencv computer-vision camera-calibration fisheye


    【解决方案1】:

    我想我遇到了类似的问题,在 getOptimalNewCameraMatrix 中寻找鱼眼的“alpha”结。

    原图:

    我用 cv2.fisheye.calibrate 进行了校准,得到了 K 和 D 参数

    K = [[ 329.75951163    0.          422.36510555]
     [   0.          329.84897388  266.45855056]
     [   0.            0.            1.        ]]
    
    D = [[ 0.04004325]
     [ 0.00112638]
     [ 0.01004722]
     [-0.00593285]]
    

    这就是我得到的

    map1, map2 = cv2.fisheye.initUndistortRectifyMap(K, d, np.eye(3), k, (800,600), cv2.CV_16SC2)
    nemImg = cv2.remap( img, map1, map2, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT)
    

    而且我认为它砍得太多了。我想看看整个魔方

    我修复它

    nk = k.copy()
    nk[0,0]=k[0,0]/2
    nk[1,1]=k[1,1]/2
    # Just by scaling the matrix coefficients!
    
    map1, map2 = cv2.fisheye.initUndistortRectifyMap(k, d, np.eye(3), nk, (800,600), cv2.CV_16SC2)  # Pass k in 1st parameter, nk in 4th parameter
    nemImg = cv2.remap( img, map1, map2, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT)
    

    多田!

    【讨论】:

    • 为什么图片不对称?
    【解决方案2】:

    正如Paul Bourkehere所提到的:

    鱼眼投影不是“扭曲”的图像,过程也不是 一个“去扭曲”。像其他投影一样的鱼眼是多种方法之一 将 3D 世界映射到 2D 平面上,它不会或多或少“扭曲” 与包括矩形透视投影在内的其他投影相比

    要在不裁剪图像的情况下进行投影(并且您的相机具有 ~180 度 FOV),您可以使用以下方式将 鱼眼 图像投影到正方形中:

    源代码:

    #include <iostream>
    #include <sstream>
    #include <time.h>
    #include <stdio.h>
    #include <opencv2/core/core.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    #include <opencv2/calib3d/calib3d.hpp>
    #include <opencv2/highgui/highgui.hpp>
    
    // - compile with:
    // g++ -ggdb `pkg-config --cflags --libs opencv` fist2rect.cpp -o fist2rect
    // - execute:
    // fist2rect input.jpg output.jpg
    
     using namespace std;
     using namespace cv;
     #define PI 3.1415926536
    
     Point2f getInputPoint(int x, int y,int srcwidth, int srcheight)
     {
        Point2f pfish;
        float theta,phi,r, r2;
        Point3f psph;
        float FOV =(float)PI/180 * 180;
        float FOV2 = (float)PI/180 * 180;
        float width = srcwidth;
        float height = srcheight;
    
        // Polar angles
        theta = PI * (x / width - 0.5); // -pi/2 to pi/2
        phi = PI * (y / height - 0.5);  // -pi/2 to pi/2
    
        // Vector in 3D space
        psph.x = cos(phi) * sin(theta);
        psph.y = cos(phi) * cos(theta);
        psph.z = sin(phi) * cos(theta);
    
        // Calculate fisheye angle and radius
        theta = atan2(psph.z,psph.x);
        phi = atan2(sqrt(psph.x*psph.x+psph.z*psph.z),psph.y);
    
        r = width * phi / FOV;
        r2 = height * phi / FOV2;
    
        // Pixel in fisheye space
        pfish.x = 0.5 * width + r * cos(theta);
        pfish.y = 0.5 * height + r2 * sin(theta);
        return pfish;
    }
    int main(int argc, char **argv)
    {
        if(argc< 3)
            return 0;
        Mat orignalImage = imread(argv[1]);
        if(orignalImage.empty())
        {
            cout<<"Empty image\n";
            return 0;
        }
        Mat outImage(orignalImage.rows,orignalImage.cols,CV_8UC3);
    
        namedWindow("result",CV_WINDOW_NORMAL);
    
        for(int i=0; i<outImage.cols; i++)
        {
            for(int j=0; j<outImage.rows; j++)
            {
    
                Point2f inP =  getInputPoint(i,j,orignalImage.cols,orignalImage.rows);
                Point inP2((int)inP.x,(int)inP.y);
    
                if(inP2.x >= orignalImage.cols || inP2.y >= orignalImage.rows)
                    continue;
    
                if(inP2.x < 0 || inP2.y < 0)
                    continue;
                Vec3b color = orignalImage.at<Vec3b>(inP2);
                outImage.at<Vec3b>(Point(i,j)) = color;
    
            }
        }
    
        imwrite(argv[2],outImage);
    
    }
    

    【讨论】:

      【解决方案3】:

      你做得很好,你只需要使用getOptimalNewCameraMatrix()undistort() 中设置newCameraMatrix。为了让所有像素可见,您必须在getOptimalNewCameraMatrix() 中将alpha 设置为1。

      【讨论】:

      • 我试过了,对于常规图像(使用 opencv 示例文件夹中的图像),它给出了我想要的结果类型,但是当我在鱼眼图像上使用它时,它没有给出想要的结果。
      • 您的图像似乎来自广角相机(约 180 度 fov)。如果您想包含所有像素 - 您将制作一个无限大小的图像(因为与主相机轴的角度 >= 180 的像素将被投影到无限远)。因此,您必须丢弃其中的一些才能获得有限大小的图像。顺便问一下,你用的是什么 alpha?
      • 是的,如上所述,这是一款具有非常宽视野的鱼眼镜头相机。正如您在之前的评论中建议的那样,我正在使用 1.0。
      • 嗯,那么也许你最好自己构建新的校准矩阵。似乎opencv在规模上有某种限制
      【解决方案4】:

      我堆积了同样的问题。如果您的相机的 FOV ~ 180 度,我认为您将无法 100% 地消除初始图像表面的失真。更详细的解释我放here

      【讨论】:

      【解决方案5】:

      您需要使用fisheye::estimateNewCameraMatrixForUndistortRectifyR=np.eye(3)(单位矩阵)和balance=1 来获取所有像素:

      new_K = cv2.fisheye.estimateNewCameraMatrixForUndistortRectify(K, D, dim, np.eye(3), balance=balance)
      map1, map2 = cv2.fisheye.initUndistortRectifyMap(scaled_K, D, np.eye(3), new_K, dim, cv2.CV_32FC1)
      # and then remap:
      undistorted_img = cv2.remap(img, map1, map2, interpolation=cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT)
      

      【讨论】:

        猜你喜欢
        • 2018-04-15
        • 2016-05-20
        • 2018-11-24
        • 2012-10-12
        • 1970-01-01
        • 2017-04-27
        • 1970-01-01
        • 2023-03-15
        • 1970-01-01
        相关资源
        最近更新 更多