Search code examples
pythonopencvcomputer-visioncameracamera-calibration

Computing camera vectors from image plane using distortions


I'm trying to use a camera model to reconstruct images one could have taken with certain cameras and their (extrinsic/intrinsic) parameters. This I don't have any problems with. Now I want to add distortions as they are described in OpenCV(seems to be the reference model).

The goal is to get a vector for every pixel in the camera grid which I can then use to determine the point it reaches on a surface (i.e. a plane with distance 1 to the camera). Sadly there only seems to be a function for the other direction, being given a point in the world I can compute the corresponding point in the image plane. This method is called projectPoints().

Is there an inverse function of this? I can't seem to find one or a different reliable method/python module. Thank you in advance.


Solution

  • Okay, I've read up a bit and it seems like there is no closed form solution at all for this direction! I do solve it now by iteratively approximating the solution. I only use 5 distortion coefficients, but it should be possible to extend that to more. The first guess is simply the undistorted vectors.

    This is the code I use and it is reasonable fast:

    def distort(D, coeff, th=10e-7, MAXITER=40):
        undistorted = D
        k1, k2, p1, p2, k3 = coeff
        
        done = True
        i    = 0
        while(done):
            undistorted_old = undistorted
            xn, yn = undistorted
            xn2  = np.square(xn)
            yn2  = np.square(yn)
            r2   = xn2 + yn2
            r4   = np.square(r2)
            r6   = r4 * r2
            xyn2 = 2 * xn * yn
        
            # radial and tangential distortions
            DR = np.tile((1 + k1*r2 + k2*r4 + k3*r6), (2,1))
            DT = np.array([p1*xyn2 + p2*(r2 + 2*xn2), p2*xyn2 + p1*(r2 + 2*yn2)])
            
            # Update
            undistorted = (D-DT) / DR
           
            # calculate error
            error = undistorted_old - undistorted
            if ((np.sum(np.square(error)) < th) or (i==MAXITER)):
                done=False
            i=i+1
        
        return undistorted
    

    Hope that helps!