Odd result on cv::fisheye::undistortPoints

I am trying to understand the camera calibration and facing a strange behavior of cv::fisheye::distort/undistortPoints functions. I would expect them to be one inverse of the other. The following code creates a camera matrix with distortion coefficients and undistorts and then distorts back an arbitrary point. The values for the camera intrinsics and distortion coefficients were taken from a public dataset.

cv::Mat camera_matrix = cv::Mat::zeros(3,3,CV_64F);
camera_matrix.at<double>(0,0) = 190.9784;
camera_matrix.at<double>(1,1) = 190.9733;
camera_matrix.at<double>(0,2) = 254.9317;
camera_matrix.at<double>(1,2) = 256.8974;
camera_matrix.at<double>(2,2) = 1;

std::cout << "Camera matrix: \n" << camera_matrix << "\n" <<std::endl;

cv::Mat distortion_coefficients(4,1,CV_64F);
distortion_coefficients.at<double>(0) = 0.003482;
distortion_coefficients.at<double>(1) = 0.000715;
distortion_coefficients.at<double>(2) = -0.0020532;
distortion_coefficients.at<double>(3) = 0.000203;

std::cout << "Distortion coefficients\n"<< distortion_coefficients<< "\n" << std::endl;

cv::Mat original_point(1,1,CV_64FC2);
original_point.at<cv::Point2d>(0).x= 7.7;
original_point.at<cv::Point2d>(0).y= 9.9;
cv::Mat undistorted, distorted;
cv::fisheye::undistortPoints(original_point, undistorted, camera_matrix, 
            distortion_coefficients, cv::Mat(), camera_matrix);
cv::fisheye::distortPoints(undistorted, distorted, camera_matrix, distortion_coefficients);

std:: cout << "Original point: " << original_point.at<cv::Point2d>(0).x << " " << original_point.at<cv::Point2d>(0).y << std::endl;
std:: cout << "Undistorted point: " << undistorted.at<cv::Point2d>(0).x << " " << undistorted.at<cv::Point2d>(0).y<< std::endl;
std:: cout << "Distorted point: " << distorted.at<cv::Point2d>(0).x << " " << distorted.at<cv::Point2d>(0).y;

The result of this is

Camera matrix: 
[190.9784, 0, 254.9317;
 0, 190.9733, 256.8974;
 0, 0, 1]

Distortion coefficients
[0.003482;
 0.000715;
 -0.0020532;
 0.000203]

Original point: 7.7 9.9
Undistorted point: 8905.69 8899.45
Distorted point: 464.919 466.732

I would expect that the (un)distortion should move a point along the ray connecting it to the (cx, cy) while here the point from the top left is moved far bottom right.

Is this a bug or I do not understand something?

cv::fisheye::undistortImage is working on the dataset images - the curves are turned back into lines.

1 Like

I just wasted 2 weeks of my life due to this. I had verified the undistort → distort round trip but as this only happens in certain regions of the image I didn’t catch it. In addition the rectified images looked correct but they don’t flow through fisheye::undistortPoints(). My fisheye lens is under 180 degree FOV. Wonder if scaling (reducing) the focal length of the camera matrix as many do in initUndistortRectifyMap for the new camera matrix so that more of the image is visible would do the trick here. I just need to work out how to go from normalized camera space to image space through a lens with smaller focal length and once back into image or pixel space remap according to actual focal length.