c++opencvfisheye

OpenCV fisheye calibration C++ output differs from Python


I’m currently working on a camera that have a fisheye (which is not much but still) and I’m trying to undistort it.

As starter : I’m not that familiar with opencv, I’m like always on the documentation while trying to do anything. (and/or here looking for answer to my problem(s)).

So I saw few example on the web, I tried the solutions and got some results on my part.

Here what I found :

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)

This is the python script I use to undistort image. The data at the top (K & D) are generated through another script. I didn’t mentioned it because I have a translation in C++ that show same result for the same base_picture

And for this function if I give a distorted image like : Python distorted image I got this result : Python undistorted image

So I can see that the tiny distortion has been resolved.

But when I try to implement this same function in C++ as follow :

    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);

The base image is still the same BUT I got this as result : C++ undistorted image

And as you can tell, it went worse…

I dumped K, D & E in my python script and c++ program (both gives the same result for the same base picture) (I mean when I compute the datas)

It goes wrong from the initUndistortRectifyMap up to the remap and finally imshow is totally not what I was expecting.

I try to dump map1 & map2 in python script & C++ program (wasn’t looking at ALL of the data) and I could notice that at the end of one of the map (didn’t look both) the results were differents.

Since I call the function using the same parameter (as far as I’m aware of) I expected for the map to be equal between both programs.

Is there something I’m doing wrong ? Like messing with the types or whatsoever ?

Does it change anything to compute the image from a cv::imread or from a frame acquisition from a camera ?

(Just to let you know, the frame (.jpg) with which computation is made, is a cv::imwrite from the frame acquisition of the camera, then I intend not to use images anymore but only work with cv::Mat filled with data from camera acquisition.)

(I know that at the end the enum aren't the same, but even using cv::BORDER_CONSTANT I still have the same issue.)


Solution

  • You've used the cv::initUndistortRectifyMap instead of cv::fisheye::initUndistortRectifyMap

    using this code instead I get the proper result:

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

    enter image description here