pydistort.Cv2Distortion#

class pydistort.Cv2Distortion(parameters: ndarray | None = None, Nparams: Integral | None = None)[source]#

Class to apply distortion with the OpenCV distortion model.

Distort the given normalized_points using the distortion model to obtain the distorted_points.

\[x_D = \text{distort}(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 Nparams is given during instantiation, the given parameters are truncated or extended to the given number of parameters.

Parameters:
  • parameters (numpy.ndarray, optional) – The parameters of the distortion model. If None, no distortion is applied. The default is None.

  • Nparams (int, optional) – The number of parameters of the distortion model. If None, the number of parameters is set to the number of parameters of the model. The default is None. Must be in [0, 4, 5, 8, 12, 14] if given.

Examples

Create an distortion object with a given model:

import numpy as np
from pydistort import Cv2Distortion

# Create a distortion object with 8 parameters
distortion = Cv2Distortion(np.array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8])) # Model with 8 parameters

Then you can use the distortion object to distort normalized_points:

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

result = distortion.transform(normalized_points): #alias distort is also available
distorted_points = result.distorted_points # shape (3, 2) -> distorted points in (normalized) image coordinates
print(distorted_points)

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

result = distortion.transform(distorted_points, dx=True, dp=True)
distorted_points_dx = result.jacobian_dx  # Jacobian of the image points with respect to the distorted points # Shape (..., 2, 3)
distorted_points_dp = result.jacobian_dp  # Jacobian of the image points with respect to the intrinsic parameters # Shape (..., 2, Nparams)

The parameters are ordered as given in the model description above.

property Nparams: int#

Get the number of parameters of the distortion model.

Returns:

The number of parameters of the distortion model.

Return type:

int

_abc_impl = <_abc._abc_data object>#
_compute_tilt_matrix(dp: bool = True, inv: bool = True) Tuple[ndarray, ndarray | None, ndarray | None, ndarray | None][source]#

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

The tilt matrix is computed using the following equation:

\[R_{\text{tilt}}{\tau} = R_Z[R_Y R_X] R_Y R_X\]

where \(R_X\) and \(R_Y\) are the rotation matrices along X and Y respectively, and \(R_Z\) is the rotation matrix along Z.

\[\begin{split}R_X = \begin{pmatrix} 1 & 0 & 0 \\ 0 & \cos(\tau_x) & \sin(\tau_x) \\ 0 & -\sin(\tau_x) & \cos(\tau_x) \end{pmatrix}\end{split}\]
\[\begin{split}R_Y = \begin{pmatrix} \cos(\tau_y) & 0 & -\sin(\tau_y) \\ 0 & 1 & 0 \\ \sin(\tau_y) & 0 & \cos(\tau_y) \end{pmatrix}\end{split}\]

and we note that the rotation matrix along Z is given by:

\[\begin{split}R_z[R] = \begin{pmatrix} R_{33} & 0 & -R_{13} \\ 0 & R_{33} & -R_{23} \\ 0 & 0 & 1 \end{pmatrix}\end{split}\]

The derivatives of the tilt matrix with respect to \(\tau_x\) and \(\tau_y\) are also computed. The derivatives are computed using the following equations:

\[\frac{\partial R_{\text{tilt}}}{\partial \tau_x} = R_Z [R_Y \frac{\partial R_X}{\partial \tau_x}, 0] R_Y R_X + R_Z [R_Y R_X, 1] R_Y \frac{\partial R_X}{\partial \tau_x}\]
\[\frac{\partial R_{\text{tilt}}}{\partial \tau_y} = R_Z [\frac{\partial R_Y}{\partial \tau_y} R_X, 0] R_Y R_X + R_Z [R_Y R_X, 1] \frac{\partial R_Y}{\partial \tau_y} R_X\]

Finnally, the inverse of the tilt matrix is computed using the following equation:

\[R_{\text{tilt}}^{-1} = (Ry Rx).T @ invRz[Ry Rx]\]

Where \(invRz\) is the inverse of the rotation matrix along Z given by:

\[\begin{split}(R_z[R])^{-1} = \begin{pmatrix} 1/R_{33} & 0 & R_{13}/R_{33} \\ 0 & 1/R_{33} & R_{23}/R_{33} \\ 0 & 0 & 1 \end{pmatrix}\end{split}\]

Note

If the model is not set to 14 parameters, the method returns a identity matrix and the derivatives are set to zero.

Parameters:
  • dp (bool, optional) – If True, the derivatives of the tilt matrix are computed. The default is True. If False, the derivatives are set to None.

  • inv (bool, optional) – If True, the inverse of the tilt matrix is computed. The default is True. If False, the inverse of the tilt matrix is set to None.

Returns:

  • numpy.ndarray – The tilt matrix.

  • numpy.ndarray – The derivative of the tilt matrix with respect to \(\tau_x\) if dp is True, else None.

  • numpy.ndarray – The derivative of the tilt matrix with respect to \(\tau_y\) if dp is True, else None.

  • numpy.ndarray – The inverse of the tilt matrix if inv is True, else None.

_inverse_transform(distorted_points: ndarray, *, dx: bool = False, dp: bool = False, opencv: bool = False, max_iter: int = 10, eps: float = 1e-08) tuple[ndarray, ndarray | None, ndarray | None][source]#

This method is called by the pydistort.Transform.inverse_transform() method to perform the inverse distortion transformation. This method allows to transform the distorted_points to the normalized_points using the distortion model.

Note

For _inverse_transform the input must have shape (Npoints, 2) with float64 type. The output has shape (Npoints, 2) and the jacobian are always None.

To achieve the undistortion, an iterative algorithm is used to find the normalized points that correspond to the distorted points. The algorithm is based on the following equations:

\[\begin{split}\begin{bmatrix} x_N [\text{it }k+1]\\ y_N [\text{it }k+1] \end{bmatrix} = \begin{bmatrix} (x_D - \Delta x [\text{it }k]) / \text{Rad} [\text{it }k] \\ (y_D - \Delta y [\text{it }k]) / \text{Rad}[\text{it }k] \end{bmatrix}\end{split}\]

Where \(\Delta x [\text{it }k]\) and :math:Delta y [text{it }k] are the tangential and prism distortion contributions to the distorted points computed at iteration :math:k. And \(\text{Rad} [\text{it }k]\) is the radial distortion contribution to the distorted points computed at iteration :math:k.

\[\begin{split}\begin{bmatrix} \Delta x \Delta y \end{bmatrix} = \begin{bmatrix} 2 p_1 x_N y_N + p_2 (r^2 + 2x_N^2) + s_1 r^2 + s_2 r^4 \\ 2 p_2 x_N y_N + p_1 (r^2 + 2y_N^2) + s_3 r^2 + s_4 r^4 \end{bmatrix}\end{split}\]
\[\begin{split}\begin{bmatrix} \text{Rad}_x \\ \text{Rad}_y \end{bmatrix} = \begin{bmatrix} \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} \\ \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} \end{bmatrix}\end{split}\]

Warning

This method is not designed to be used directly for the transformation of points. No checks are performed on the input points, so it is the user’s responsibility to ensure that the input points are valid.

To achieve the inverse distortion transformation using openCV, set the opencv parameter to True.

Warning

Both OpenCV and the internal method use an iterative algorithm to find the normalized points that correspond to the distorted points. In fact the jacobian with respect to the normalized points is not computed for this inverse transform (always None).

Parameters:
  • distorted_points (numpy.ndarray) – Array of distorted points to be transformed with shape (Npoints, 2).

  • dx (bool, optional) – [ALWAYS False]

  • dp (bool, optional) – [ALWAYS False]

  • opencv (bool, optional) – If True, the inverse distortion transformation is achieved using the OpenCV function undistortPoints. If False, the inverse distortion transformation is achieved using the internal method. Default is False.

  • max_iter (int, optional) – The maximum number of iterations for the optimization algorithm. Default is 10. Use only if opencv is False.

  • eps (float, optional) – The tolerance for the optimization algorithm. Default is 1e-8. Use only if opencv is False.

Returns:

  • normalized_points (numpy.ndarray) – The transformed normalized points in normalized coordinates. It will be a 2D array of shape (Npoints, 2).

  • jacobian_dx (Optional[numpy.ndarray]) – [ALWAYS None]

  • jacobian_dp (Optional[numpy.ndarray]) – [ALWAYS None]

_inverse_transform_opencv(distorted_points: ndarray, *, dx: bool = False, dp: bool = False) tuple[ndarray, ndarray | None, ndarray | None][source]#

This method is called by the pydistort.Transform.inverse_transform() method to perform the inverse distortion transformation using OpenCV undistortPoints function. To use this method, set the opencv parameter to True in the pydistort.Transform.inverse_transform() method.

Note

For _inverse_transform_opencv the input must have shape (Npoints, 2) with float64 type. The output has shape (Npoints, 2) and the jacobian are always None.

The equation used for the transformation is given in the main documentation of the class.

Warning

This method is not designed to be used directly for the transformation of points. No checks are performed on the input points, so it is the user’s responsibility to ensure that the input points are valid.

Parameters:
  • distorted_points (numpy.ndarray) – Array of distorted points to be transformed with shape (Npoints, 2).

  • dx (bool, optional) – [ALWAYS False]

  • dp (bool, optional) – [ALWAYS False]

Returns:

  • normalized_points (numpy.ndarray) – The transformed normalized points in normalized coordinates. It will be a 2D array of shape (Npoints, 2).

  • jacobian_dx (Optional[numpy.ndarray]) – [ALWAYS None]

  • jacobian_dp (Optional[numpy.ndarray]) – [ALWAYS None]

_transform(normalized_points: ndarray, *, dx: bool = False, dp: bool = False, opencv: bool = False) tuple[ndarray, ndarray | None, ndarray | None][source]#

This method is called by the pydistort.Transform.transform() method to perform the distortion transformation. This method allows to transform the normalized_points to the distorted_points using the distortion model.

Note

For _transform the input must have shape (Npoints, 2) with float64 type. The output has shape (Npoints, 2) for the image points and (Npoints, 2, 2) for the jacobian with respect to the normalized points and (Npoints, 2, 4) for the jacobian with respect to the distortion parameters.

The equation used for the transformation is given in the main documentation of the class.

Warning

This method is not designed to be used directly for the transformation of points. No checks are performed on the input points, so it is the user’s responsibility to ensure that the input points are valid.

To achieve the distortion transformation using openCV, set the opencv parameter to True. (jacobian_dx will not be computed in this case).

Parameters:
  • normalized_points (numpy.ndarray) – Array of normalized points to be transformed with shape (Npoints, 2).

  • dx (bool, optional) – If True, the Jacobian of the distorted points with respect to the normalized points is computed. Default is False. The output will be a 2D array of shape (Npoints, 2, 2).

  • dp (bool, optional) – If True, the Jacobian of the distorted points with respect to the distortion parameters is computed. Default is False. The output will be a 2D array of shape (Npoints, 2, Nparams).

  • opencv (bool, optional) – If True, the distortion transformation is achieved using the OpenCV function projectPoints. If False, the distortion transformation is achieved using the internal method. Default is False.

Returns:

  • distorted_points (numpy.ndarray) – The transformed distorted points in normalized coordinates. It will be a 2D array of shape (Npoints, 2).

  • jacobian_dx (Optional[numpy.ndarray]) – The Jacobian of the distorted points with respect to the normalized points if dx is True. Otherwise None. It will be a 2D array of shape (Npoints, 2, 2).

  • jacobian_dp (Optional[numpy.ndarray]) – The Jacobian of the distorted points with respect to the distortion parameters if dp is True. Otherwise None. It will be a 2D array of shape (Npoints, 2, Nparams).

_transform_opencv(normalized_points: ndarray, *, dx: bool = False, dp: bool = False) tuple[ndarray, ndarray | None, ndarray | None][source]#

This method is called by the pydistort.Transform.transform() method to perform the distortion transformation using OpenCV projectPoints function. To use this method, set the opencv parameter to True in the pydistort.Transform.transform() method.

Note

For _transform_opencv the input must have shape (Npoints, 2) with float64 type. The output has shape (Npoints, 2) for the image points and (Npoints, 2, Nparams) for the jacobian with respect to the distortion parameters.

The equation used for the transformation is given in the main documentation of the class.

Warning

This method is not designed to be used directly for the transformation of points. No checks are performed on the input points, so it is the user’s responsibility to ensure that the input points are valid.

The jacobian with respect to the normalized points is not computed in this case (always None).

Parameters:
  • normalized_points (numpy.ndarray) – Array of normalized points to be transformed with shape (Npoints, 2).

  • dx (bool, optional) – [ALWAYS False]

  • dp (bool, optional) – If True, the Jacobian of the distorted points with respect to the distortion parameters is computed. Default is False. The output will be a 2D array of shape (Npoints, 2, Nparams).

Returns:

  • distorted_points (numpy.ndarray) – The transformed distorted points in normalized coordinates. It will be a 2D array of shape (Npoints, 2).

  • jacobian_dx (Optional[numpy.ndarray]) – [ALWAYS None]

  • jacobian_dp (Optional[numpy.ndarray]) – The Jacobian of the distorted points with respect to the distortion parameters if dp is True. Otherwise None. It will be a 2D array of shape (Npoints, 2, Nparams).

is_set() bool[source]#

Check if the distortion model is set.

Returns:

True if the distortion model is set, False otherwise.

Return type:

bool

property k1: float#

Get the first radial distortion coefficient.

Warning

An error is raised if the number of parameters is less than 4. Set the number of parameters to 4 or more before getting the value.

Returns:

The first radial distortion coefficient.

Return type:

float

Raises:

ValueError – If the number of parameters is less than 4.

property k2: float#

Get the second radial distortion coefficient.

Warning

An error is raised if the number of parameters is less than 4. Set the number of parameters to 4 or more before getting the value.

Returns:

The second radial distortion coefficient.

Return type:

float

Raises:

ValueError – If the number of parameters is less than 4.

property k3: float | None#

Get the third radial distortion coefficient.

Warning

An error is raised if the number of parameters is less than 5. Set the number of parameters to 5 or more before getting the value.

Returns:

The third radial distortion coefficient.

Return type:

float

Raises:

ValueError – If the number of parameters is less than 5.

property k4: float | None#

Get the first fractional radial distortion coefficient.

Warning

An error is raised if the number of parameters is less than 8. Set the number of parameters to 8 or more before getting the value.

Returns:

The first fractional radial distortion coefficient.

Return type:

float

Raises:

ValueError – If the number of parameters is less than 8.

property k5: float | None#

Get the second fractional radial distortion coefficient.

Warning

An error is raised if the number of parameters is less than 8. Set the number of parameters to 8 or more before getting the value.

Returns:

The second fractional radial distortion coefficient.

Return type:

float

Raises:

ValueError – If the number of parameters is less than 8.

property k6: float | None#

Get the third fractional radial distortion coefficient.

Warning

An error is raised if the number of parameters is less than 8. Set the number of parameters to 8 or more before getting the value.

Returns:

The third fractional radial distortion coefficient.

Return type:

float

Raises:

ValueError – If the number of parameters is less than 8.

make_empty() None[source]#

Set to zero the parameters of the distortion model.

property p1: float#

Get the first tangential distortion coefficient.

Warning

An error is raised if the number of parameters is less than 4. Set the number of parameters to 4 or more before getting the value.

Returns:

The first tangential distortion coefficient.

Return type:

float

Raises:

ValueError – If the number of parameters is less than 4.

property p2: float#

Get the second tangential distortion coefficient.

Warning

An error is raised if the number of parameters is less than 4. Set the number of parameters to 4 or more before getting the value.

Returns:

The second tangential distortion coefficient.

Return type:

float

Raises:

ValueError – If the number of parameters is less than 4.

property parameters: ndarray | None#

Get the parameters of the distortion model.

Returns:

The parameters of the distortion model.

Return type:

numpy.ndarray

property s1: float | None#

Get the first thin prism distortion coefficient.

Warning

An error is raised if the number of parameters is less than 12. Set the number of parameters to 12 or more before getting the value.

Returns:

The first thin prism distortion coefficient.

Return type:

float

Raises:

ValueError – If the number of parameters is less than 12.

property s2: float | None#

Get the second thin prism distortion coefficient.

Warning

An error is raised if the number of parameters is less than 12. Set the number of parameters to 12 or more before getting the value.

Returns:

The second thin prism distortion coefficient.

Return type:

float

Raises:

ValueError – If the number of parameters is less than 12.

property s3: float | None#

Get the third thin prism distortion coefficient.

Warning

An error is raised if the number of parameters is less than 12. Set the number of parameters to 12 or more before getting the value.

Returns:

The third thin prism distortion coefficient.

Return type:

float

Raises:

ValueError – If the number of parameters is less than 12.

property s4: float | None#

Get the fourth thin prism distortion coefficient.

Warning

An error is raised if the number of parameters is less than 12. Set the number of parameters to 12 or more before getting the value.

Returns:

The fourth thin prism distortion coefficient.

Return type:

float

Raises:

ValueError – If the number of parameters is less than 12.

property tau_x: float | None#

Get the x component of the perspective transformation.

Warning

An error is raised if the number of parameters is less than 14. Set the number of parameters to 14 or more before getting the value.

Returns:

The x component of the perspective transformation.

Return type:

float

Raises:

ValueError – If the number of parameters is less than 14.

property tau_y: float | None#

Get the y component of the perspective transformation.

Warning

An error is raised if the number of parameters is less than 14. Set the number of parameters to 14 or more before getting the value.

Returns:

The y component of the perspective transformation.

Return type:

float

Raises:

ValueError – If the number of parameters is less than 14.