pycvcam.Cv2Distortion#

Cv2Distortion Class#

class Cv2Distortion(parameters=None, constants=None, n_params=None)[source]#

Subclass of the pycvcam.core.Distortion class that represents the OpenCV distortion model.

Note

This class represents the distortion transformation, which is the middle step of the process from the world_points to the image_points.

The Cv2Distortion model in the OpenCV model with radial, tangential and prism distortion.

Lets consider normalized_points in the camera normalized coordinate system \(\vec{x}_n = (x_n, y_n)\), the corresponding distorted_points in the camera normalized coordinate system are given \(\vec{x}_d\) can be obtained by :

\[\vec{x}_d = \text{distort}(\vec{x}_n, \lambda_1, \lambda_2, \lambda_3, \ldots)\]

The model of OpenCV is the following one:

\[\begin{split}\begin{bmatrix} x_d \\ y_d \end{bmatrix} = \begin{bmatrix} x_n \frac{1+k_1 r^2 + k_2 r^4 + k_3 r^6}{1 + k_4 r^2 + k_5 r^4 + k_6 r^6} + 2p_1 x_n y_n + p_2 (r^2 + 2x_n^2) + s_1 r^2 + s_2 r^4 \\ y_n \frac{1+k_1 r^2 + k_2 r^4 + k_3 r^6}{1 + k_4 r^2 + k_5 r^4 + k_6 r^6} + p_1 (r^2 + 2y_n^2) + 2p_2 x_n y_n + s_3 r^2 + s_4 r^4 \end{bmatrix}\end{split}\]

where \(r^2 = x_n^2 + y_n^2\) and \(k_i\) are the radial distortion coefficients, \(p_i\) are the tangential distortion coefficients and \(s_i\) are the thin prism distortion coefficients.

Then a perspective transformation is applied using \(\tau_x\) and \(\tau_y\) to obtain the final distorted points.

\[\begin{split}\begin{bmatrix} x_d \\ y_d \\ 1 \end{bmatrix} = \begin{bmatrix} R_{33}(\tau) & 0 & -R_{13}(\tau) \\ 0 & R_{33}(\tau) & -R_{23}(\tau) \\ 0 & 0 & 1 \end{bmatrix} R(\tau) \begin{bmatrix} x_d \\ y_d \\ 1 \end{bmatrix}\end{split}\]

where :

\[\begin{split}R(\tau) = \begin{bmatrix} cos(\tau_y) & sin(\tau_x)sin(\tau_y) & -cos(\tau_x)sin(\tau_y) \\ 0 & cos(\tau_x) & sin(\tau_x) \\ sin(\tau_y) & -sin(\tau_x)cos(\tau_y) & cos(\tau_x)cos(\tau_y) \end{bmatrix}\end{split}\]

and \(R_{ij}(\tau)\) are the elements of the rotation matrix.

See also

OpenCV can use various models for distortion,

  • N = 4 parameters : \((k_1, k_2, p_1, p_2)\) : radial and tangential distortion

  • N = 5 parameters : \((k_1, k_2, p_1, p_2, k_3)\) : radial and tangential distortion with third order radial distortion

  • N = 8 parameters : \((k_1, k_2, p_1, p_2, k_3, k_4, k_5, k_6)\) : radial and tangential distortion with fractional radial distortion

  • N = 12 parameters : \((k_1, k_2, p_1, p_2, k_3, k_4, k_5, k_6, s_1, s_2, s_3, s_4)\) : radial and tangential distortion with thin prism distortion

  • N = 14 parameters : \((k_1, k_2, p_1, p_2, k_3, k_4, k_5, k_6, s_1, s_2, s_3, s_4, \tau_x, \tau_y)\) : radial and tangential distortion with thin prism distortion and perspective transformation

If the number of input parameters is not equal to the number of parameters required by the model, the other parameters are set to 0.

Warning

If the number of parameters n_params is given during instantiation, the given parameters are truncated or extended to the given number of parameters.

Parameters:
  • parameters (Optional[ArrayLike], optional) – The parameters of the distortion transformation. It should be a numpy array of shape (n_params,) containing the distortion coefficients ordered as described above. Default is None, which means no distortion is setted.

  • n_params (Optional[Integral], optional) – The number of parameters for the distortion model. If not specified, it will be inferred from the shape of the parameters array.

  • constants (None)

Accessing the parameters of Cv2Distortion objects#

The parameters and constants properties can be accessing using pycvcam.core.Transform methods. Some additional convenience methods are provided to access commonly used parameters of the Cv2Distortion model:

Cv2Distortion.k1

Get the first radial distortion coefficient.

Cv2Distortion.k2

Get the second radial distortion coefficient.

Cv2Distortion.k3

Get the third radial distortion coefficient.

Cv2Distortion.k4

Get the first fractional radial distortion coefficient.

Cv2Distortion.k5

Get the second fractional radial distortion coefficient.

Cv2Distortion.k6

Get the third fractional radial distortion coefficient.

Cv2Distortion.p1

Get the first tangential distortion coefficient.

Cv2Distortion.p2

Get the second tangential distortion coefficient.

Cv2Distortion.s1

Get the first thin prism distortion coefficient.

Cv2Distortion.s2

Get the second thin prism distortion coefficient.

Cv2Distortion.s3

Get the third thin prism distortion coefficient.

Cv2Distortion.s4

Get the fourth thin prism distortion coefficient.

Cv2Distortion.tau_x

Get the x component of the perspective transformation.

Cv2Distortion.tau_y

Get the y component of the perspective transformation.

Performing distortion with Cv2Distortion objects#

The transform and inverse_transform methods can be used to perform distortion and undistortion using the Cv2Distortion model (as described in the pycvcam.core.Transform documentation).

The implementation of theses transformations and more details on the options available can be found in the following methods:

Cv2Distortion._compute_tilt_matrix([dp, inv])

Compute the tilt matrix for the perspective transformation for N = 14 (only).

Cv2Distortion._transform(normalized_points, *)

Compute the transformation from the normalized_points to the distorted_points.

Cv2Distortion._transform_opencv(...[, dx, dp])

Compute the transformation from the normalized_points to the distorted_points using OpenCV's projectPoints function.

Cv2Distortion._inverse_transform(...[, dx, ...])

Compute the inverse transformation from the distorted_points to the normalized_points.

Cv2Distortion._inverse_transform_opencv(...)

Compute the inverse transformation from the distorted_points to the normalized_points using OpenCV's undistortPoints function.

Examples#

Create an distortion object with a specific number of parameters:

import numpy
from pycvcam import Cv2Distortion

parameters = numpy.array([0.1, 0.01, 0.02, 0.03, 0.001])

distortion = Cv2Distortion(parameters=parameters)

Then you can use the distortion object to transform normalized_points to distorted_points:

normalized_points = numpy.array([[0.1, 0.2], [0.3, 0.4], [0.5, 0.6]]) # shape (n_points, 2)

result = distortion.transform(normalized_points)
distorted_points = result.distorted_points # Shape (n_points, 2)
print(distorted_points)

You can also access to the jacobian of the distortion transformation:

result = distortion.transform(normalized_points, dx=True, dp=True)
distorted_points_dx = result.jacobian_dx  # Shape (n_points, 2, 2)
distorted_points_dp = result.jacobian_dp  # Shape (n_points, 2, n_params = 5)
print(distorted_points_dx)
print(distorted_points_dp)

The inverse transformation can be computed using the inverse_transform method:

inverse_result = distortion.inverse_transform(distorted_points, dx=True, dp=True)
normalized_points = inverse_result.normalized_points  # Shape (n_points, 2)
print(normalized_points)

Note

The jacobian with respect to the depth is not computed.

See also

For more information about the transformation process, see: