kornia.geometry.quaternion#

Module state#

Quaternion data given as a plain tensor is a persistent buffer under _data; an nn.Parameter stays a parameter under the same key. So3 saves its rotation as _q._data and Se3 as _rotation._q._data, prefixed by the enclosing module’s attribute names when nested. load_state_dict(strict=True) raises on a state dict that lacks these keys; with strict=False they are reported as missing and the target keeps its own rotation.

class kornia.geometry.quaternion.Quaternion(data)[source]#

Base class to represent a Quaternion.

A quaternion is a four dimensional vector representation of a rotation transformation in 3d. See more: https://en.wikipedia.org/wiki/Quaternion

The general definition of a quaternion is given by:

\[Q = a + b \cdot \mathbf{i} + c \cdot \mathbf{j} + d \cdot \mathbf{k}\]

Thus, we represent a rotation quaternion as a contiguous torch.Tensor structure to perform rigid bodies transformations:

\[Q = \begin{bmatrix} q_w & q_x & q_y & q_z \end{bmatrix}\]
Convention:
  • data is (w, x, y, z), real part first, with shape \((*, 4)\); only the last axis is checked. Other libraries’ orders, such as scipy’s default (x, y, z, w), are mapped on Rotations and rigid motions.

  • * between quaternions is the Hamilton product, so (q1 * q2).matrix() is q1.matrix() @ q2.matrix(), q1 / q2 is q1 * q2.inv(), and q and -q are the same rotation. A float or tensor operand of +, -, * or / is the real quaternion [s, 0, 0, 0], and a tensor of the shape of q.w holds one such scalar per quaternion of the batch.

  • Nothing normalises the stored data or the results of *, ** and inv(). matrix(), to_axis_angle(), to_euler(), polar_angle and slerp read only the direction of q: rescaling q by a positive factor changes their result by roundoff only, as long as its squared components stay within the range of the dtype and its norm stays above 1e-12.

  • At construction, plain tensor data is registered as a persistent buffer; an explicit nn.Parameter remains a parameter. Both are saved and restored by state_dict() and load_state_dict() and follow an enclosing module’s device and dtype conversions. Construction preserves the input tensor and its autograd history. Quaternion.to() returns a new quaternion; enclosing module conversions update the existing module’s state.

  • Known defects: below a norm of 1e-12, matrix() and slerp give wrong results, and the zero quaternion’s matrix() is the identity (#3952).

Example

>>> q = Quaternion.identity(batch_size=4)
>>> q.data
tensor([[1., 0., 0., 0.],
        [1., 0., 0., 0.],
        [1., 0., 0., 0.],
        [1., 0., 0., 0.]])
>>> q.real
tensor([1., 1., 1., 1.])
>>> q.vec
tensor([[0., 0., 0.],
        [0., 0., 0.],
        [0., 0., 0.],
        [0., 0., 0.]])
__add__(right)[source]#

Add a given quaternion, scalar, or torch.Tensor.

Parameters:

right (Union[Quaternion, Tensor, float]) – the quaternion, scalar, or torch.Tensor to add.

Return type:

Quaternion

Example

>>> q1 = Quaternion.identity()
>>> q2 = Quaternion(torch.tensor([2., 0., 1., 1.]))
>>> q3 = q1 + q2
>>> q3.data
tensor([3., 0., 1., 1.])
__init__(data)[source]#

Construct a quaternion from torch.Tensor or parameter data.

Parameters:

data (Union[Tensor, Parameter]) – torch.Tensor or parameter containing the quaternion data with the shape of \((*, 4)\). Stored without copying as a persistent buffer, or as a parameter if already an nn.Parameter.

Example

>>> # Create with torch.tensor(no gradients tracked by default)
>>> data = torch.tensor([1., 0., 0., 0.])
>>> q1 = Quaternion(data)
>>> # Create with parameter (gradients tracked)
>>> param_data = torch.nn.Parameter(torch.tensor([1., 0., 0., 0.]))
>>> q2 = Quaternion(param_data)
__neg__()[source]#

Inverts the sign of the quaternion data.

Return type:

Quaternion

Example

>>> q = Quaternion.identity()
>>> (-q).data
tensor([-1., -0., -0., -0.])
__pow__(t)[source]#

Return the power of a quaternion raised to exponent t.

For \(q = \|q\| (\cos\theta + n \sin\theta)\) this is \(q^t = \|q\|^t (\cos t\theta + n \sin t\theta)\), so q**2 == q * q and q**-1 == q.inv().

On the negative real axis (w < 0 and a zero vector part) \(\theta = \pi\) and the axis \(n\) is undefined: for a non-integer t every unit vector gives a valid power. This method takes \(n = e_x\) there, so q**t has norm \(\|q\|^t\) and angle \(t\pi\), (q**0.5)**2 == q, and the result is the limit from the +x side of the axis. An integer t keeps a zero vector part.

Parameters:

t (Union[float, Tensor]) – raised exponent, a float or a tensor that broadcasts against (..., 1).

Return type:

Quaternion

Example

>>> q = Quaternion(torch.tensor([1., .5, 0., 0.]))
>>> q_pow = q**2
__radd__(left)[source]#

Right addition (left + self) where left is a scalar or torch.Tensor.

Return type:

Quaternion

__rdiv__(left)[source]#

Right division (left / self) where left is a scalar or torch.Tensor.

Return type:

Quaternion

__repr__()[source]#

Return repr(self).

Return type:

str

__rmul__(left)[source]#

Right multiplication (left * self) where left is a scalar or torch.Tensor.

Return type:

Quaternion

__rsub__(left)[source]#

Right subtraction (left - self) where left is a scalar or torch.Tensor.

Return type:

Quaternion

__rtruediv__(left)[source]#

Right division (left / self) where left is a scalar or torch.Tensor.

Return type:

Quaternion

__sub__(right)[source]#

Subtract a given quaternion, scalar, or torch.Tensor.

Parameters:

right (Union[Quaternion, Tensor, float]) – the quaternion, scalar, or torch.Tensor to subtract.

Return type:

Quaternion

Example

>>> q1 = Quaternion(torch.tensor([2., 0., 1., 1.]))
>>> q2 = Quaternion.identity()
>>> q3 = q1 - q2
>>> q3.data
tensor([1., 0., 1., 1.])
property coeffs: Tuple[Tensor, Tensor, Tensor, Tensor]#

Return a tuple with the underlying coefficients in WXYZ order.

conj()[source]#

Compute the conjugate of the quaternion.

Return type:

Quaternion

Returns:

The conjugate quaternion, with the vector part negated.

Example

>>> q = Quaternion(torch.tensor([1., 2., 3., 4.]))
>>> q_conj = q.conj()
property data: Tensor#

Return the underlying data with shape \((B, 4)\).

classmethod from_axis_angle(axis_angle)[source]#

Create a quaternion from axis-angle representation.

Parameters:

axis_angle (Tensor) – rotation vector of shape \((B, 3)\).

Return type:

Quaternion

Example

>>> axis_angle = torch.tensor([[1., 0., 0.]])
>>> q = Quaternion.from_axis_angle(axis_angle)
>>> q.data
tensor([[0.8776, 0.4794, 0.0000, 0.0000]])
classmethod from_coeffs(w, x, y, z)[source]#

Create a quaternion from the data coefficients.

Parameters:
  • w (float) – a float representing the \(q_w\) component.

  • x (float) – a float representing the \(q_x\) component.

  • y (float) – a float representing the \(q_y\) component.

  • z (float) – a float representing the \(q_z\) component.

Return type:

Quaternion

Example

>>> q = Quaternion.from_coeffs(1., 0., 0., 0.)
>>> q.data
tensor([1., 0., 0., 0.])
classmethod from_euler(roll, pitch, yaw)[source]#

Create a quaternion from Euler angles.

Parameters:
  • roll (Tensor) – the roll euler angle.

  • pitch (Tensor) – the pitch euler angle.

  • yaw (Tensor) – the yaw euler angle.

Return type:

Quaternion

Example

>>> roll, pitch, yaw = torch.tensor(0), torch.tensor(1), torch.tensor(0)
>>> q = Quaternion.from_euler(roll, pitch, yaw)
>>> q.data
tensor([0.8776, 0.0000, 0.4794, 0.0000])
classmethod from_matrix(matrix, check_rotation=False)[source]#

Create a quaternion from a rotation matrix.

Parameters:
  • matrix (Tensor) – the rotation matrix to convert of shape \((B, 3, 3)\).

  • check_rotation (bool, optional) – if True, raise ValueError unless every input is a rotation matrix. The default False keeps the unchecked behaviour, under which a reflection such as diag(-1, 1, 1) returns a non-unit quaternion rather than being reported as invalid. Default: False

Return type:

Quaternion

Example

>>> m = torch.eye(3)[None]
>>> q = Quaternion.from_matrix(m)
>>> q.data
tensor([[1., 0., 0., 0.]])
classmethod identity(batch_size=None, device=None, dtype=None)[source]#

Create a quaternion representing an identity rotation.

Parameters:
  • batch_size (Optional[int], optional) – the batch size of the underlying data. Default: None

  • device (Union[str, device, None], optional) – device to place the result on. Default: None

  • dtype (Optional[dtype], optional) – dtype of the result. Default: None

Return type:

Quaternion

Example

>>> q = Quaternion.identity()
>>> q.data
tensor([1., 0., 0., 0.])
inv()[source]#

Compute the inverse of the quaternion.

Return type:

Quaternion

Returns:

The inverse quaternion.

Example

>>> q = Quaternion.identity()
>>> q_inv = q.inv()
matrix()[source]#

Convert the quaternion to a rotation matrix of shape \((B, 3, 3)\).

Return type:

Tensor

Example

>>> q = Quaternion.identity()
>>> m = q.matrix()
>>> m
tensor([[1., 0., 0.],
        [0., 1., 0.],
        [0., 0., 1.]])
norm(keepdim=False)[source]#

Compute the norm (magnitude) of the quaternion.

Parameters:

keepdim (bool, optional) – whether to retain the last dimension. Default: False

Return type:

Tensor

Returns:

The norm of the quaternion(s) as a torch.Tensor.

Example

>>> q = Quaternion.identity()
>>> q.norm()
tensor(1.)
normalize()[source]#

Return a normalized (unit) quaternion.

Return type:

Quaternion

Returns:

The normalized quaternion.

Example

>>> q = Quaternion(torch.tensor([2., 1., 0., 0.]))
>>> q_norm = q.normalize()
property polar_angle: Tensor#

Return the polar angle \(\arccos(w / |q|)\) in \([0, \pi]\), with shape \((B,)\).

q rotates by twice this angle about the axis vec.

Example

>>> q = Quaternion.identity()
>>> q.polar_angle
tensor(0.)
property q: Tensor#

Return the underlying data with shape \((B, 4)\).

Alias for data()

classmethod random(batch_size=None, device=None, dtype=None)[source]#

Create a random unit quaternion of shape \((B, 4)\).

Uniformly distributed across the rotation space as per: http://planning.cs.uiuc.edu/node198.html

Parameters:
  • batch_size (Optional[int], optional) – the batch size of the underlying data. Default: None

  • device (Union[str, device, None], optional) – device to place the result on. Default: None

  • dtype (Optional[dtype], optional) – dtype of the result. Default: None

Return type:

Quaternion

Example

>>> q = Quaternion.random()
>>> q = Quaternion.random(batch_size=2)
property real: Tensor#

Return the real part with shape \((B,)\).

Alias for w.

property scalar: Tensor#

Return a scalar with the real with shape \((B,)\).

Alias for w.

property shape: Tuple[int, ...]#

Return the shape of the underlying data with shape \((B, 4)\).

slerp(q1, t)[source]#

Return a unit quaternion spherically interpolated between quaternions self.q and q1.

The interpolation follows the shorter arc between the two rotations, whatever the signs of the stored quaternions: q1 and -q1 give the same result, and at t = 1 the output is q1 or -q1. The exception is a half turn whose relative quaternion self.inv() * q1 has a real part of exactly zero: both arcs are then equally short and the path is not unique. The arc taken follows the sign of the vector part of self.inv() * q1, so q1 and -q1 take opposite arcs, and the result is not continuous in q1 there.

See more: https://en.wikipedia.org/wiki/Slerp

Parameters:
  • q1 (Quaternion) – second quaternion to be interpolated between.

  • t (Union[float, Tensor]) – interpolation ratio, 0 at self and 1 at q1. It is not validated: values outside [0, 1] extrapolate along the same arc. A per-batch ratio has shape \((B,)\), like self.w, or \((B, 1)\).

Return type:

Quaternion

Example

>>> q0 = Quaternion.identity()
>>> q1 = Quaternion(torch.tensor([1., .5, 0., 0.]))
>>> q2 = q0.slerp(q1, .3)
squared_norm()[source]#

Compute the squared norm (magnitude) of the quaternion.

Return type:

Tensor

Returns:

The squared norm of the quaternion(s) as a torch.Tensor.

Example

>>> q = Quaternion.identity()
>>> q.squared_norm()
tensor(1.)
to(*args, **kwargs)[source]#

Move and/or cast the quaternion data.

Parameters:
  • *args (Any) – Arguments to pass to torch.Tensor.to()

  • **kwargs (Any) – Keyword arguments to pass to torch.Tensor.to()

Return type:

Quaternion

Returns:

A new Quaternion with converted data.

to_axis_angle()[source]#

Convert the quaternion to an axis-angle representation.

Return type:

Tensor

Example

>>> q = Quaternion.identity()
>>> axis_angle = q.to_axis_angle()
>>> axis_angle
tensor([0., 0., 0.])
to_euler()[source]#

Convert the quaternion to a triple of Euler angles (roll, pitch, yaw).

Return type:

Tuple[Tensor, Tensor, Tensor]

Example

>>> q = Quaternion.from_euler(torch.tensor(0.3), torch.tensor(0.2), torch.tensor(0.1))
>>> roll, pitch, yaw = q.to_euler()
>>> roll
tensor(0.3000)
>>> pitch
tensor(0.2000)
>>> yaw
tensor(0.1000)
property vec: Tensor#

Return the vector with the imaginary part with shape \((B, 3)\).

property w: Tensor#

Return the \(q_w\) with shape \((B,)\).

property x: Tensor#

Return the \(q_x\) with shape \((B,)\).

property y: Tensor#

Return the \(q_y\) with shape \((B,)\).

property z: Tensor#

Return the \(q_z\) with shape \((B,)\).

kornia.geometry.quaternion.average_quaternions(Q, w=None)[source]#

Compute (weighted) average of multiple quaternions.

Convention:
  • The chordal mean of scipy’s Rotation.mean: the eigenvector of \(\sum_i w_i q_i q_i^\top / \sum_i w_i\) with the largest eigenvalue. q_i and -q_i count the same, and the sign of the result is arbitrary.

  • w need not sum to one: scaling it by a positive factor does not change the result. A negative weight, or weights that are all zero, raise ValueError.

  • The members are normalised first, so only their directions count: a member stored as 3 * q weighs the same as q.

Parameters:
  • Q (Quaternion) – quaternion object containing data of shape (M, 4).

  • w (torch.Tensor, optional) – Weights of shape (M,). If None, uniform weights are used. Default: None

Returns:

averaged quaternion of shape (1, 4), wrapped back in the Quaternion class.

Return type:

Quaternion