Opencv: distort back

There are some points which I found when tried to redistort points using tips from this topic:

  1. Code in the question is almost right, but has a bug. It uses r^4 after k3 instead of r^6. I rewrote code and successfully run after this simple correction.

xCorrected = x * (1. + k1 * r2 + k2 * r2 * r2 + k3 * r2 * r2 * r2); // Multiply r2 after k3 one more time in yCorrected too

  1. Joan Charman said the right things and equations allow to distort point back (Not undistort, as mentioned in comments under his answer). However, some words are incorrect:

// To relative coordinates <- this is the step you are missing

This is wrong, as the code in this question already useы relative coordinates! It is a trick in OpenCV undistortPoints functions. It has a new intrinsic matrix as the 6th argument. If it is None, than the function returns points in relative coordinates. And this is why the original code in question has this step:

//Step 2 : ideal coordinates => actual coordinates
      xCorrected = xCorrected * fx + ux;
      yCorrected = yCorrected * fy + uy;
  1. Also, I have to say about confusion in the Internet material.

When I started to study this question, I had the same opinion that these equations undistort points, not the opposite.

Recently I have found why. The tutorial of OpenCV and its documentation has the different names. Tutorial uses variables 'xCorrected' and 'yCorrected' for the equations. While in doc the same things have different names: 'xDistorted' and 'yDistorted'

So let's me solve the confuse: Distortion operation can be represented as equations in various distortion models. But Undistortion is only possible through numerical iteration algorithm. There is no analytical solutions to represent undistortion as equations (Because of 6th order part in radial part and nonlinearity)

If you multiply all the distortion coefficients by -1 you can then pass them to undistort or undistortPoints and basically you will apply the inverse distortion which will bring the distortion back.

You can easily distort back your points using ProjectPoints.

cv::Mat rVec(3, 1, cv::DataType<double>::type); // Rotation vector<double>(0) = 0;<double>(1) = 0;<double>(2) =0;
cv::Mat tVec(3, 1, cv::DataType<double>::type); // Translation vector<double>(0) =0;<double>(1) = 0;<double>(2) = 0;

cv::projectPoints(points,rVec,tVec, cameraMatrix, distCoeffs,result);

PS: in the opencv 3 they added a function for distort.

The initUndistortRectifyMap linked in one of the answers of the question you mention does indeed what you want. Since it is used in Remap to build the full undistorted image, it gives, for each location in the destination image (undistorted), where to find the corresponding pixel in the distorted image so they can use its color. So it's really an f(undistorted) = distorted map.

However, using this map will only allow for input positions that are integer and within the image rectangle. Thankfully, the documentation gives the full equations.

It is mostly what you have, except that there is a preliminary step that you are missing. Here is my version (it is C# but should be the same):

public PointF Distort(PointF point)
    // To relative coordinates <- this is the step you are missing.
    double x = (point.X - cx) / fx;
    double y = (point.Y - cy) / fy;

    double r2 = x*x + y*y;

    // Radial distorsion
    double xDistort = x * (1 + k1 * r2 + k2 * r2 * r2 + k3 * r2 * r2 * r2);
    double yDistort = y * (1 + k1 * r2 + k2 * r2 * r2 + k3 * r2 * r2 * r2);

    // Tangential distorsion
    xDistort = xDistort + (2 * p1 * x * y + p2 * (r2 + 2 * x * x));
    yDistort = yDistort + (p1 * (r2 + 2 * y * y) + 2 * p2 * x * y);

    // Back to absolute coordinates.
    xDistort = xDistort * fx + cx;
    yDistort = yDistort * fy + cy;

    return new PointF((float)xDistort, (float)yDistort);