kornia.geometry.conversions#
Angles#
- kornia.geometry.conversions.rad2deg(tensor)[source]#
Convert angles from radians to degrees.
- Convention:
the input is in radians and the output in degrees; the conversion is elementwise and preserves shape, device and float dtype
- Parameters:
tensor (
Tensor) – torch.Tensor of arbitrary shape.- Return type:
- Returns:
torch.Tensor with same shape as input.
Example
>>> input = torch.tensor(3.1415926535) >>> rad2deg(input) tensor(180.)
- kornia.geometry.conversions.deg2rad(tensor)[source]#
Convert angles from degrees to radians.
- Convention:
the input is in degrees and the output in radians; it performs the opposite conversion to
rad2deg()
- Parameters:
tensor (
Tensor) – torch.Tensor of arbitrary shape.- Return type:
- Returns:
tensor with same shape as input.
Examples
>>> input = torch.tensor(180.) >>> deg2rad(input) tensor(3.1416)
- kornia.geometry.conversions.pol2cart(rho, phi)[source]#
Convert polar coordinates to cartesian coordinates.
- Convention:
the arguments are
(rho, phi)and the return is the tuple(x, y), withx = rho * cos(phi)andy = rho * sin(phi):rho = 5,phi = atan2(4, 3)gives(3., 4.)phiis in radians (rho = 2,phi = pi / 6gives(1.7321, 1.)) and follows the angle convention documented oncart2pol()
- Parameters:
- Returns:
torch.Tensor with same shape as input. - y: torch.Tensor with same shape as input.
- Return type:
x
Example
>>> rho = torch.rand(1, 3, 3) >>> phi = torch.rand(1, 3, 3) >>> x, y = pol2cart(rho, phi)
- kornia.geometry.conversions.cart2pol(x, y, eps=1.0e-8)[source]#
Convert cartesian coordinates to polar coordinates.
- Convention:
the arguments are
(x, y)and the return is the tuple(rho, phi):(3., 4.)gives(5., 0.9273)phiisatan2(y, x)in radians, so it lies in \([-\pi, \pi]\), is0on the+xaxis and grows toward+y(x = 0,y = 1givesphi = 1.5708). Both endpoints are attained on the-xaxis, where the sign ofy’s zero decides between-piand+pikornia’s image
yaxis points down, so a growingphiturns clockwise as displayed. The relation to the other 2-D angle op is the opposite sense: applyingangle_to_rotation_matrix(theta)to a nonzero point decreases that point’sphibythetadegrees modulo \(2\pi\) — the result is re-wrapped into \([-\pi, \pi]\), so a point atphi = -170degrees rotated bytheta = 30returnsphi = +160, not-200. At the originphicarries no direction and the relation does not applyrhois the Euclidean radiussqrt(x ** 2 + y ** 2).epsonly protects the gradient near the origin and does not perturb the returned radius
Note
epsdefines the neighborhood around the origin where the gradient is stabilized. It does not change the forward value ofrho.- Parameters:
- Returns:
torch.Tensor with same shape as input. - phi: torch.Tensor with same shape as input.
- Return type:
rho
Example
>>> x = torch.rand(1, 3, 3) >>> y = torch.rand(1, 3, 3) >>> rho, phi = cart2pol(x, y)
- kornia.geometry.conversions.angle_to_rotation_matrix(angle)[source]#
Create a rotation matrix out of angles in degrees.
- Convention:
angleis in degrees, shape \((*)\) in and \((*, 2, 2)\) outthe matrix is
[[cos, sin], [-sin, cos]]withdet = +1; forangle = 30it is[[0.8660, 0.5000], [-0.5000, 0.8660]]applied on the left to a column vector
(x, y),angle = 30maps(1., 0.)to(0.8660, -0.5000)— counter-clockwise as displayed under kornia’s y-down image axes. In the raw coordinate plane this is the opposite sense tocart2pol(), whose Convention block spells out the modulo-\(2\pi\) relation between the two ops
- Parameters:
angle (
Tensor) – tensor of angles in degrees, any shape \((*)\).- Return type:
- Returns:
tensor of rotation matrices with shape \((*, 2, 2)\).
Example
>>> input = torch.rand(1, 3) # Nx3 >>> output = angle_to_rotation_matrix(input) # Nx3x2x2
Coordinates#
- kornia.geometry.conversions.convert_points_from_homogeneous(points, eps=1e-8)[source]#
Convert points from homogeneous to Euclidean space.
- Convention:
the last component of the last dimension is the homogeneous coordinate
wand is dropped from the outputrequires rank \(\geq 2\): a bare \((D,)\) point raises
ValueErrorwhen
abs(w) > epsthe remaining components are divided by exactlyw, with its sign kept ([[2., 4., -2.]]gives[[-1., -2.]])when
abs(w) <= eps(defaulteps = 1e-8; the test is a strict>) the numerator is instead returned unchanged, following OpenCV:[[2., 4., 0.]]gives[[2., 4.]]epsonly picks the branch, it never enters the division, so the result carries no bias from it. It is compared againstwin the working dtype
- Parameters:
- Return type:
- Returns:
the points in Euclidean space \((*, N, D-1)\).
Examples
>>> input = torch.tensor([[0., 0., 1.]]) >>> convert_points_from_homogeneous(input) tensor([[0., 0.]])
- kornia.geometry.conversions.convert_points_to_homogeneous(points)[source]#
Convert points from Euclidean to homogeneous space.
- Convention:
appends the constant
1as the last component of the last dimension, which is whereconvert_points_from_homogeneous()expects itrequires rank \(\geq 2\): a bare \((D,)\) point raises
ValueErrorthe input dtype is preserved, integer dtypes included
- Parameters:
points (
Tensor) – the points to be transformed with shape \((*, N, D)\).- Return type:
- Returns:
the points in homogeneous coordinates \((*, N, D+1)\).
Examples
>>> input = torch.tensor([[0., 0.]]) >>> convert_points_to_homogeneous(input) tensor([[0., 0., 1.]])
- kornia.geometry.conversions.convert_affinematrix_to_homography(A)[source]#
Convert batch of affine matrices.
- Convention:
appends the row
[0, 0, 1]at the bottom and copies the \(2 \times 3\) block verbatim; the input tensor is not modifiedthe rank is enforced to be exactly 3, so batching is mandatory: an unbatched \((2, 3)\) matrix raises
ValueError
- Parameters:
A (
Tensor) – the affine matrix with shape \((B,2,3)\).- Return type:
- Returns:
the homography matrix with shape of \((B,3,3)\).
Examples
>>> A = torch.tensor([[[1., 0., 0.], ... [0., 1., 0.]]]) >>> convert_affinematrix_to_homography(A) tensor([[[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]]])
- kornia.geometry.conversions.convert_affinematrix_to_homography3d(A)[source]#
Convert batch of 3d affine matrices.
- Convention:
same as
convert_affinematrix_to_homography(), except thatAis \((B, 3, 4)\) and the appended bottom row is[0, 0, 0, 1]
- Parameters:
A (
Tensor) – the affine matrix with shape \((B,3,4)\).- Return type:
- Returns:
the homography matrix with shape of \((B,4,4)\).
Examples
>>> A = torch.tensor([[[1., 0., 0., 0.], ... [0., 1., 0., 0.], ... [0., 0., 1., 0.]]]) >>> convert_affinematrix_to_homography3d(A) tensor([[[1., 0., 0., 0.], [0., 1., 0., 0.], [0., 0., 1., 0.], [0., 0., 0., 1.]]])
- kornia.geometry.conversions.denormalize_pixel_coordinates(pixel_coordinates, height, width, eps=1e-8)[source]#
Denormalize pixel coordinates.
The input is assumed to be -1 if on extreme left, 1 if on extreme right (x = w-1).
- Convention:
See Conventions & Pitfalls for the library-wide pixel-centre, normalized-coordinate and
align_cornersconventions.the inverse of
normalize_pixel_coordinates(),x = (width - 1) * (x_norm + 1) / 2, with the same(x, y)component order and the same(pixel_coordinates, height, width)positional ordersingleton axes, non-positive-size validation, tracing assumptions, and the deprecated
epsparameter follow the normalization function
- Parameters:
- Return type:
- Returns:
the denormalized pixel coordinates with shape \((*, 2)\).
Examples
>>> coords = torch.tensor([[-1., -1.]]) >>> denormalize_pixel_coordinates(coords, 100, 50) tensor([[0., 0.]])
- kornia.geometry.conversions.normalize_pixel_coordinates(pixel_coordinates, height, width, eps=1e-8)[source]#
Map pixel coordinates so that the first and last pixel of each axis become -1 and 1.
- Convention:
See Conventions & Pitfalls for the library-wide pixel-centre, normalized-coordinate and
align_cornersconventions.pixel_coordinatesis \((*, 2)\) in(x, y)order:xindexes columns and is scaled bywidth,yindexes rows and is scaled byheight. The positional argument order is the other way round —(pixel_coordinates, height, width)the mapping is corner-aligned,
x_norm = 2 * x / (width - 1) - 1: forwidth = 4the columns0,1,3map to-1,-1/3,+1. This is thealign_corners=Trueconvention;torch.nn.functional.grid_sample()at its defaultalign_corners=Falsewould instead place the first and last of those values at pixels-0.5and3.5— half a pixel outside the image on each side — soalign_corners=Truemust be passed explicitly when feeding this output to it. Note that kornia’s ownremap()resolvesalign_corners=NonetoFalsea singleton axis uses scale
1and offset0: its only valid pixel coordinate maps to the normalized centre, and the unit-scale extension keeps this function exactly invertible outside that lone valid coordinate. Zero and negative sizes raiseValueErrorthe output is not clamped: coordinates outside the image extrapolate linearly past
[-1, 1], as the example below shows
Note
Legacy
torch.jit.tracegraphs assume positive runtime sizes because tracing cannot retain the PythonValueErrorvalidation. Eager, TorchScript, andtorch.compilecalls validate sizes.Deprecated since version 0.9.0:
epsno longer participates in the explicitly defined singleton-axis mapping. Passing a non-default value warns in eager mode; the parameter will be removed in a future breaking release.- Parameters:
- Return type:
- Returns:
the normalized pixel coordinates with shape \((*, 2)\).
Examples
>>> coords = torch.tensor([[50., 100.]]) >>> normalize_pixel_coordinates(coords, 100, 50) tensor([[1.0408, 1.0202]])
- kornia.geometry.conversions.denormalize_pixel_coordinates3d(pixel_coordinates, depth, height, width, eps=1e-8)[source]#
Denormalize 3d pixel coordinates.
- Convention:
the inverse of
normalize_pixel_coordinates3d(), with the same(d, x, y)component order and the same(pixel_coordinates, depth, height, width)positional order: withdepth=3, height=5, width=9the input[0., 0., 0.]maps back to[1., 4., 2.]singleton axes, non-positive-size validation, tracing assumptions, and the deprecated
epsparameter follow the 2-D counterpart
- Parameters:
pixel_coordinates (
Tensor) – the normalized grid coordinates. Shape can be \((*, 3)\).depth (
int) – the maximum depth in the z-axis.height (
int) – the maximum height in the y-axis.width (
int) – the maximum width in the x-axis.eps (
float, optional) – deprecated compatibility parameter. It is ignored. Default:1e-8
- Return type:
- Returns:
the denormalized pixel coordinates.
- kornia.geometry.conversions.normalize_pixel_coordinates3d(pixel_coordinates, depth, height, width, eps=1e-8)[source]#
Map 3d pixel coordinates so that the first and last sample of each axis become -1 and 1.
- Convention:
pixel_coordinatesis \((*, 3)\) in(d, x, y)order — depth first, then x, then y, not(x, y, z). This is the ordercreate_meshgrid3d()produces. The three components are scaled bydepth - 1,width - 1andheight - 1respectively, so withdepth=3, height=5, width=9the coordinate[2., 8., 4.]maps to[1., 1., 1.]the positional argument order is
(pixel_coordinates, depth, height, width)corner-aligned and unclamped in each axis exactly as in
normalize_pixel_coordinates()singleton axes, non-positive-size validation, tracing assumptions, and the deprecated
epsparameter likewise follow that function
- Parameters:
pixel_coordinates (
Tensor) – the grid with pixel coordinates. Shape can be \((*, 3)\).depth (
int) – the maximum depth in the z-axis.height (
int) – the maximum height in the y-axis.width (
int) – the maximum width in the x-axis.eps (
float, optional) – deprecated compatibility parameter. It is ignored. Default:1e-8
- Return type:
- Returns:
the normalized pixel coordinates.
- kornia.geometry.conversions.normalize_points_with_intrinsics(point_2d, camera_matrix)[source]#
Normalize points with intrinsics. Useful for conversion of keypoints to be used with essential matrix.
- Convention:
See camera and world conventions for the camera intrinsics and pixel-centre conventions used by these coordinates.
point_2dis \((*, 2)\) in pixel(u, v)order andcamera_matrixis a row-major pinhole \((*, 3, 3)\) withfx = K[0, 0],fy = K[1, 1],cx = K[0, 2],cy = K[1, 2]the output is the calibrated camera coordinate
x = (u - cx) / fx,y = (v - cy) / fy: withK = [[100., 0., 320.], [0., 200., 240.], [0., 0., 1.]]the pixel(420., 440.)maps to(1., 1.)the skew entry
K[0, 1]is ignored; only the two diagonal entries and the[:2, 2]column are read. This is a design choice: kornia’s functional pinhole model is zero-skew, like OpenCV’s, andproject_points()readsKthe same way. For a skewedKapplyinv(K)directly
- Parameters:
- Return type:
- Returns:
tensor of normalized camera coordinates \((x, y)\) with shape \((*, 2)\).
Example
>>> _ = torch.manual_seed(0) >>> X = torch.rand(1, 2) >>> K = torch.eye(3)[None] >>> normalize_points_with_intrinsics(X, K) tensor([[0.4963, 0.7682]])
- kornia.geometry.conversions.denormalize_points_with_intrinsics(point_2d_norm, camera_matrix)[source]#
Denormalize points with intrinsics. Useful for converting normalized camera points back to pixels.
- Convention:
See camera and world conventions for the camera intrinsics and pixel-centre conventions used by these coordinates.
the inverse of
normalize_points_with_intrinsics(), which documents theKlayout:u = x * fx + cxandv = y * fy + cy, and the skew entryK[0, 1]is ignored here too
- Parameters:
- Return type:
- Returns:
tensor of \((u, v)\) pixel coordinates with shape \((*, 2)\).
Example
>>> _ = torch.manual_seed(0) >>> X = torch.rand(1, 2) >>> K = torch.eye(3)[None] >>> denormalize_points_with_intrinsics(X, K) tensor([[0.4963, 0.7682]])
Homography#
- kornia.geometry.conversions.normalize_homography(dst_pix_trans_src_pix, dsize_src, dsize_dst, align_corners=True)[source]#
Normalize a given homography in pixels to [-1, 1].
- Convention:
the input maps source pixels to destination pixels and the output maps normalized source to normalized destination: exactly
N_dst @ H @ inv(N_src)withNfromnormal_transform_pixel(), sodsize_srcdrives the right factor anddsize_dstthe left one. A+2pixel shift inxon a 5-wide image comes back as+1.0.denormalize_homography()computes the reverseinv(N_dst) @ H @ N_srcboth
dsizearguments are(height, width), while the matrix acts on(x, y, 1)column vectorsa \((3, 3)\) or \((B, 3, 3)\) matrix is accepted and batching is per sample; an unbatched input is returned as
(1, 3, 3), and any other shape raisesValueErrorin eager mode
inv(N_src)is a closed-form adjugate built fromtorch.linalg.cross, so nocusolveris needed. Afloat16orbfloat16matrix is inverted infloat32and the result cast back: thefloat16determinant of a large image’s normalization matrix is subnormal or zero, and some backends lack abfloat16crosskernel (MPS on torch 2.5.1). For any other dtype, a backend without acrosskernel for it raises here
Warning
An integer matrix is not rejected: the normalization matrices are cast to it and truncated, and the call then fails inside torch or returns
nan, depending on the backend. Tracked in #3959.Warning
The \([-1, 1]\) frames follow this function’s own
align_corners, which defaults toTrue(corner-aligned) — not theFalsethattorch.nn.functional.grid_sample()andhomography_warp()default to. The value passed here must match thegrid_samplecall that consumes the result; a mismatch applies a spurious sub-pixel scale and shift.warp_perspective(),warp_affine()andhomography_warp()forward their own flag, so they are consistent under both settings; see #3904.normalize_homography3d()still has noalign_cornersparameter and is corner-aligned unconditionally, sowarp_affine3d()keeps this mismatch atalign_corners=False. Tracked in #4503.- Parameters:
dst_pix_trans_src_pix (
Tensor) – homography/ies from source to destination to be normalized. \((B, 3, 3)\), or an unbatched \((3, 3)\), which is promoted to \((1, 3, 3)\)dsize_src (
tuple[int,int]) – size of the source image (height, width).dsize_dst (
tuple[int,int]) – size of the destination image (height, width).align_corners (
bool, optional) – whichtorch.nn.functional.grid_sample()convention the normalized \([-1, 1]\) coordinates follow, forwarded tonormal_transform_pixel(). Must match thealign_cornersof thegrid_samplecall that ultimately consumes the result, otherwise the warp picks up a spurious sub-pixel scale and shift. Default:True
- Return type:
- Returns:
the normalized homography of shape \((B, 3, 3)\).
- kornia.geometry.conversions.denormalize_homography(dst_pix_trans_src_pix, dsize_src, dsize_dst, align_corners=True)[source]#
De-normalize a given homography in pixels from [-1, 1] to actual height and width.
- Convention:
the mirror of
normalize_homography(): the composition isinv(N_dst) @ H @ N_src, so the input maps normalized source to normalized destination and the output maps source pixels to destination pixels. Thedsizeroles, the(x, y, 1)column vectors, per-sample batching, thealign_corners-selected frames and the shape guard are as documented there, including its integer-input (#3959) warninginv(N_dst)goes throughtorch.linalg.invin eager mode (socusolveroncuda), not through thecross-based adjugatethe two functions invert each other to a small multiple of the working dtype’s
epstimes the largest entry, not bitwise in general
- Parameters:
dst_pix_trans_src_pix (
Tensor) – homography/ies from source to destination to be denormalized. \((B, 3, 3)\), or an unbatched \((3, 3)\), which is promoted to \((1, 3, 3)\)dsize_src (
tuple[int,int]) – size of the source image (height, width).dsize_dst (
tuple[int,int]) – size of the destination image (height, width).align_corners (
bool, optional) – whichtorch.nn.functional.grid_sample()convention the incoming normalized coordinates follow. Must match the value used to produce them, so that this function invertsnormalize_homography(). Default:True
- Return type:
- Returns:
the denormalized homography of shape \((B, 3, 3)\).
- kornia.geometry.conversions.normalize_homography3d(dst_pix_trans_src_pix, dsize_src, dsize_dst)[source]#
Normalize a given homography in pixels to [-1, 1].
- Convention:
the 3-D counterpart of
normalize_homography(): same compositionN_dst @ H @ inv(N_src), same source-to-destination direction re-expressed in normalized frames, samedsize_srcon the right anddsize_dston the left, and corner-aligned frames — withnormal_transform_pixel3d()in place of the 2-D helper. Unlike the 2-D function it has noalign_cornersparameter, so its frames are corner-aligned unconditionally. It is not the 2-D function with wider matrices, though: the shapes and — least visibly — the inversion routine differ, as the bullets below recordit inverts
N_srcwithtorch.linalg.inv(socusolveroncuda, and afloat32upcast forfloat16/bfloat16), where the 2-D function uses a closed-form adjugate in the working dtype; the 2-D and 3-D routes therefore need not agree bitwisethe matrices are \((B, 4, 4)\) and act on
(x, y, z, 1)column vectors, while bothdsizearguments are(depth, height, width)triplesdenormalize_homography3d()computes the reverseinv(N_dst) @ H @ N_srcthe shape guard is the 2-D function’s for 4x4 matrices: \((4, 4)\) (returned as
(1, 4, 4)) or \((B, 4, 4)\), anything else raisesValueError
- Parameters:
dst_pix_trans_src_pix (
Tensor) – homography/ies from source to destination to be normalized. \((B, 4, 4)\), or an unbatched \((4, 4)\), which is promoted to \((1, 4, 4)\)dsize_src (
tuple[int,int,int]) – size of the source image (depth, height, width).dsize_dst (
tuple[int,int,int]) – size of the destination image (depth, height, width).
- Return type:
- Returns:
the normalized homography.
- Shape:
Output: \((B, 4, 4)\)
- kornia.geometry.conversions.denormalize_homography3d(dst_pix_trans_src_pix, dsize_src, dsize_dst)[source]#
De-normalize a given 3D homography from [-1, 1] to actual depth, height and width.
- Convention:
the mirror of
normalize_homography3d(): the composition isinv(N_dst) @ H @ N_src, so the input maps normalized source to normalized destination and the output maps source voxels to destination voxels. The(depth, height, width)dsizeroles, the(x, y, z, 1)column vectors, per-sample batching, the corner-aligned frames and the shape guard are as documented thereinv(N_dst)goes throughtorch.linalg.inv(socusolveroncuda, and afloat32upcast forfloat16/bfloat16), the same routinenormalize_homography3d()uses forinv(N_src)the two functions invert each other to a small multiple of the working dtype’s
epstimes the largest entry, not bitwise in generalonly real floating point homographies are accepted (
float16,bfloat16,float32,float64): an integer, bool or complexdst_pix_trans_src_pixraisesTypeCheckError(also aTypeError) instead of being promoted, so cast it first. Integers would truncate the normalization matrices (the 2-D function still does, #3959), and complex dtypes would be inverted infloat32(_torch_inverse_cast), losingcomplex128precision
- Parameters:
dst_pix_trans_src_pix (
Tensor) – homography/ies from source to destination to be denormalized. \((B, 4, 4)\), or an unbatched \((4, 4)\), which is promoted to \((1, 4, 4)\)dsize_src (
tuple[int,int,int]) – size of the source image (depth, height, width).dsize_dst (
tuple[int,int,int]) – size of the destination image (depth, height, width).
- Return type:
- Returns:
the denormalized homography.
- Shape:
Output: \((B, 4, 4)\)
- kornia.geometry.conversions.normal_transform_pixel(height, width, eps=1e-14, device=None, dtype=None, align_corners=True)[source]#
Compute the normalization matrix from image size in pixels to [-1, 1].
- Convention:
the result is a single matrix of shape \((1, 3, 3)\) — never batched — acting on homogeneous
(x, y, 1)column vectors, withxindexing columns and scaled bywidthandyindexing rows and scaled byheight. The positional argument order is the other way round,(height, width)the mapping is corner-aligned by default: scale
2 / (size - 1), offset-1, so the pixel centres0andsize - 1map to exactly-1and+1.align_corners=Falseselects the half-pixel mapping instead; see thealign_cornersbullet below.normal_transform_pixel(4, 5)has rows[0.5, 0.0, -1.0]and[0.0, 0.6667, -1.0], and sends the pixels(0, 0),(4, 3)and(2, 1.5)to(-1, -1),(1, 1)and(0, 0)for sizes
>= 2this is the same map asnormalize_pixel_coordinates(). Infloat32/float64the two routes agree to the working dtype’s rounding; infloat16/bfloat16they can differ by about oneeps, because the matrix is applied through a matmul while the helper rounds elementwisethe convention is selected by
align_corners(Trueby default).Falseis the half-pixel mapping with scale2 / sizeand offset1 / size - 1, so that \(\pm 1\) fall on the outer pixel edges.normalize_homography()anddenormalize_homography()forward their ownalign_cornershere, whilenormal_transform_pixel3d()is still corner-aligned unconditionally; see the convention warning therea singleton axis maps its only pixel to the centre of the normalized range: under
align_corners=Truewith scale1and offset0, which keeps the matrix invertible for homography composition. Zero and negative sizes raiseValueErrorwith
dtype=Nonethe matrix takestorch.get_default_dtype()(float32unless the default was changed); an integer or booldtyperaisesValueError, since the fractional scales would truncate to0, for every size and even underdisable_checks(). Every floating and complex dtype is accepted
Note
Legacy
torch.jit.tracegraphs assume positive runtime sizes because tracing cannot retain the PythonValueErrorvalidation. Eager, TorchScript, andtorch.compilecalls validate sizes.Deprecated since version 0.9.0:
epsno longer participates in the explicitly defined singleton-axis mapping. Passing a non-default value warns in eager mode; the parameter will be removed in a future breaking release.- Parameters:
height (
int) – image height.width (
int) – image width.eps (
float, optional) – deprecated compatibility parameter. It is ignored. Default:1e-14device (
Optional[device], optional) – device to place the result on. Default:Nonedtype (
Optional[dtype], optional) – dtype of the result.Nonemeanstorch.get_default_dtype(). Default:Nonealign_corners (
bool, optional) – whichtorch.nn.functional.grid_sample()convention to normalize to.Truemaps pixel centers \([0, size-1]\) to \([-1, 1]\);Falseuses the half-pixel mapping \(x_{norm} = (2x + 1) / W - 1\), where \(\pm 1\) are the outer pixel edges. Default:True
- Return type:
- Returns:
normalized transform with shape \((1, 3, 3)\).
Example
>>> normal_transform_pixel(4, 5) tensor([[[ 0.5000, 0.0000, -1.0000], [ 0.0000, 0.6667, -1.0000], [ 0.0000, 0.0000, 1.0000]]])
- kornia.geometry.conversions.normal_transform_pixel3d(depth, height, width, eps=1e-14, device=None, dtype=None)[source]#
Compute the normalization matrix from image size in pixels to [-1, 1].
- Convention:
the 3-D counterpart of
normal_transform_pixel(): same corner-aligned2 / (size - 1)scaling with offset-1, samedtype=None/torch.get_default_dtype()rule, and likewise never batched. Unlike the 2-D function it has noalign_cornersparameter, so it applies that scaling unconditionally. Singleton axes use the same invertible centre mapping, and zero or negative sizes raiseValueError. Only the lines below differthe result has shape \((1, 4, 4)\) and acts on homogeneous
(x, y, z, 1)column vectors withxscaled bywidth,ybyheightandzbydepth, while the positional argument order is(depth, height, width):normal_transform_pixel3d(9, 5, 3)has diagonal[1.0, 0.5, 0.25]and sends(0, 0, 0)to(-1, -1, -1)and the far corner(2, 4, 8)to(1, 1, 1)that
(x, y, z)slot order is a permutation ofnormalize_pixel_coordinates3d(), which reads its input as(d, x, y). The two produce the same three numbers in different slots — withdepth=9, height=5, width=3the pointd=7, x=2, y=1gives[0.75, 1.0, -0.5]through the coordinate helper and[1.0, -0.5, 0.75]through this matrix — so a grid built for one silently permutes axes when fed to the otheran integer or bool
dtyperaisesValueError, as in the 2-D function
Note
Legacy
torch.jit.tracegraphs assume positive runtime sizes for the same reason as the 2-D counterpart.Deprecated since version 0.9.0:
epsis ignored and follows the deprecation policy of the 2-D counterpart.- Parameters:
depth (
int) – image depth.height (
int) – image height.width (
int) – image width.eps (
float, optional) – deprecated compatibility parameter. It is ignored. Default:1e-14device (
Optional[device], optional) – device to place the result on. Default:Nonedtype (
Optional[dtype], optional) – dtype of the result.Nonemeanstorch.get_default_dtype(). Default:None
- Return type:
- Returns:
normalized transform with shape \((1, 4, 4)\).
Example
>>> normal_transform_pixel3d(2, 4, 5) tensor([[[ 0.5000, 0.0000, 0.0000, -1.0000], [ 0.0000, 0.6667, 0.0000, -1.0000], [ 0.0000, 0.0000, 2.0000, -1.0000], [ 0.0000, 0.0000, 0.0000, 1.0000]]])
Quaternion#
- kornia.geometry.conversions.quaternion_to_axis_angle(quaternion)[source]#
Convert quaternion vector to axis angle of rotation in radians.
The quaternion should be in (w, x, y, z) format.
Adapted from ceres C++ library: ceres-solver/include/ceres/rotation.h
- Convention:
the input is
(w, x, y, z), real part first (seequaternion_to_rotation_matrix()), and the output is the rotation axis scaled by the angle in radiansfor
w != 0the double cover is collapsed:qand-qreturn the same vector, the representative with|theta| <= piat exactly
w = 0— a half turn, and0.is exactly representable — the collapse does not happen and the two return exact negations:[0., 1., 0., 0.]gives[pi, 0., 0.]while[-0., -1., 0., 0.]gives[-pi, 0., 0.], the same rotation written the other way roundthe input need not be unit: scaling
qby a power of two returns a bit-identical vector, and other scales move it by the working dtype’s rounding, as long as the squares of the components neither overflow nor underflowquaternion_to_angle_axisis the deprecated alias of this function since 0.7.0differentiable at the identity quaternion. The
sqrtwhose derivative is unbounded there never sees its zero radicand, so the gradient is the analytic limit of the surrounding map rather thannan. The guard is elementwise, and away from the identity it moves no forward bit
- Parameters:
quaternion (
Tensor) – tensor with quaternions.- Return type:
- Returns:
tensor with axis angle of rotation.
- Shape:
Input: \((*, 4)\) where * means, any number of dimensions
Output: \((*, 3)\)
Example
>>> quaternion = torch.tensor((1., 0., 0., 0.)) >>> quaternion_to_axis_angle(quaternion) tensor([0., 0., 0.])
- kornia.geometry.conversions.quaternion_to_rotation_matrix(quaternion)[source]#
Convert a quaternion to a rotation matrix.
The quaternion should be in (w, x, y, z) format.
- Convention:
the quaternion is
(w, x, y, z), real part first, shape \((*, 4)\) in and \((*, 3, 3)\) out.[1., 0., 0., 0.]gives the identity and[0., 0., 0., 1.]gives[[-1., 0., 0.], [0., -1., 0.], [0., 0., 1.]], a half turn about+z— so a caller passing(x, y, z, w)gets a valid-looking rotation matrix and no errorqand-qare the same rotation (double cover) and return bit-identical matricesthe input is normalised internally with
normalize_quaternion(), soquaternion_to_rotation_matrix(2 * q)is bitwisequaternion_to_rotation_matrix(q); other rescalings move the matrix by the working dtype’s rounding, as long as the norm of the rescaled quaternion neither overflows nor falls below the normalisation flooreps = 1e-12(see that function’s warning)quaternion_to_axis_angle(),quaternion_exp_to_log(), andeuler_from_quaternion()are scale-safe tooapplied on the left to a column vector,
+thetaabout+zmapsx_hattoy_hat(right-hand rule)the output dtype follows the input at every shape
Warning
The zero quaternion, which is not a rotation, returns the identity matrix rather than raising. Tracked in #3952.
- Parameters:
quaternion (
Tensor) – a tensor containing a quaternion to be converted. The tensor can be of shape \((*, 4)\).- Return type:
- Returns:
the rotation matrix of shape \((*, 3, 3)\).
Example
>>> quaternion = torch.tensor((0., 0., 0., 1.)) >>> quaternion_to_rotation_matrix(quaternion) tensor([[-1., 0., 0.], [ 0., -1., 0.], [ 0., 0., 1.]])
- kornia.geometry.conversions.quaternion_log_to_exp(quaternion, eps=1.0e-8)[source]#
Apply exponential map to log quaternion.
- Convention:
the input is a 3-vector of shape \((*, 3)\), not a quaternion; the output is the quaternion of shape \((*, 4)\) in
(w, x, y, z)order (seequaternion_to_rotation_matrix())the map is
w = cos(||v||)with vector partsin(||v||) * v / ||v||, and every finitevreturns a unit quaternion up to the working dtype’s rounding:||v||is computed ass * ||v / s||withs = max |v_i|, so it cannot overflow, andfloat16/bfloat16are computed infloat32, so the zero vector returns[1., 0., 0., 0.]at every dtypepi/2 < ||v|| < 3 * pi/2lands in thew < 0half of the double cover — at||v|| = 2the real part is-0.4161468365471424.wiscos(||v||), so the sign turns over again beyond that interval rather than staying negativevis therefore half the axis-angle vector: the result agrees withaxis_angle_to_quaternion(2 * v)to the rounding of the working dtype, but not bit-for-bit:[0.15, 0.2, 0.25]already disagrees atbfloat16, and infloat64most random vectors do toofor a unit
q,quaternion_log_to_exp(quaternion_exp_to_log(q))returnsqup to rounding, except that the pure-real[-1., 0., 0., 0.]comes back as[1., 0., 0., 0.]— the other half of the same rotation
- Parameters:
- Return type:
- Returns:
the quaternion exponential map of shape \((*, 4)\).
Example
>>> quaternion = torch.tensor((0., 0., 0.)) >>> quaternion_log_to_exp(quaternion, eps=torch.finfo(quaternion.dtype).eps) tensor([1., 0., 0., 0.])
- kornia.geometry.conversions.quaternion_exp_to_log(quaternion, eps=1.0e-8)[source]#
Apply the log map to a quaternion.
The quaternion should be in (w, x, y, z) format.
- Convention:
the input is the quaternion of shape \((*, 4)\) in
(w, x, y, z)order and the output is a 3-vector of shape \((*, 3)\), the argumentquaternion_log_to_exp()takesfor a unit
qon thew >= 0half of the double cover the result isquaternion_to_axis_angle(q) / 2. On thew < 0half the two part company: this function keeps the sign ofw, with the angleatan2(||v||, w)in[0, pi], whilequaternion_to_axis_angle()collapses the double cover. For theqwhose log isv,quaternion_exp_to_log(-q)is-(pi - ||v||) * v / ||v||quaternion_exp_to_log(quaternion_log_to_exp(v))returnsvfor0 < ||v|| < piand the wrapped||v|| - 2 * piabovepi(pi + 0.5comes back as-2.6415926535897936). At exactly||v|| = piinfloat64it collapses to nearly0:cos(pi)rounds to-1and the vector part falls under theepsclamp. Both are properties of the map, not defectsfloat16/bfloat16are computed infloat32, so the identity returns[0., 0., 0.]at every dtype, and the gradient is finite atw = +-1, the identity includedthe map is scale-invariant: a non-unit quaternion produces the same log as its normalisation
- Parameters:
- Return type:
- Returns:
the quaternion log map of shape \((*, 3)\).
Example
>>> quaternion = torch.tensor((1., 0., 0., 0.)) >>> quaternion_exp_to_log(quaternion, eps=torch.finfo(quaternion.dtype).eps) tensor([0., 0., 0.])
- kornia.geometry.conversions.normalize_quaternion(quaternion, eps=1.0e-12)[source]#
Normalize a quaternion.
The quaternion should be in (x, y, z, w) or (w, x, y, z) format.
- Convention:
it is an L2 normalisation of the last axis and nothing else, which is why the
(x, y, z, w)or(w, x, y, z)phrasing above is accurate here:[4., 3., 2., 1.]normalises to the reversal of what[1., 2., 3., 4.]givesthe sign is preserved —
normalize_quaternion(-q)is exactly-normalize_quaternion(q), there is now >= 0canonicalisation
Warning
When
||q|| < epsthe output is not a unit quaternion and no error is raised: with the defaulteps = 1e-12,[1e-13, 0., 0., 0.]returns[0.1, 0., 0., 0.]andzeros(4)returnszeros(4). Tracked in #3952. Witheps=0.0the zero quaternion returnsnan. Infloat16a positiveepsis floored at the smallest subnormal.- Parameters:
- Return type:
- Returns:
the normalized quaternion of shape \((*, 4)\).
Example
>>> quaternion = torch.tensor((1., 0., 1., 0.)) >>> normalize_quaternion(quaternion) tensor([0.7071, 0.0000, 0.7071, 0.0000])
Vector#
- kornia.geometry.conversions.vector_to_skew_symmetric_matrix(vec)[source]#
Convert a vector to a skew symmetric matrix.
A vector \((v1, v2, v3)\) has a corresponding skew-symmetric matrix, which is of the form:
\[\begin{split}\begin{bmatrix} 0 & -v3 & v2 \\ v3 & 0 & -v1 \\ -v2 & v1 & 0\end{bmatrix}\end{split}\]- Convention:
the matrix acts on the left as the first cross-product factor:
vector_to_skew_symmetric_matrix(v) @ xequalscross(v, x), not its negation — forv = (1., 2., 3.)andx = (4., 5., 6.)both are(-3., 6., -3.)accepts \((3,)\) or \((B, 3)\) only; any higher rank raises
ValueError
- Parameters:
vec (
Tensor) – tensor of shape \((3,)\) or \((B, 3)\).- Return type:
- Returns:
tensor of shape \((3, 3)\) or \((B, 3, 3)\) respectively.
Example
>>> vec = torch.tensor([1.0, 2.0, 3.0]) >>> vector_to_skew_symmetric_matrix(vec) tensor([[ 0., -3., 2.], [ 3., 0., -1.], [-2., 1., 0.]])
Rotation Matrix#
- kornia.geometry.conversions.rotation_matrix_to_axis_angle(rotation_matrix, check_rotation=False)[source]#
Convert 3x3 rotation matrix to Rodrigues vector in radians.
- Convention:
any number of leading batch dimensions is accepted: \((3, 3)\) gives \((3,)\) and \((2, 5, 3, 3)\) gives \((2, 5, 3)\)
the output is the rotation axis scaled by the angle in radians, the parametrization
axis_angle_to_rotation_matrix()consumes, at every rank: the \((3,)\) and \((2, 5, 3)\) results above can be fed straight backthe round trip through
axis_angle_to_rotation_matrix()is accurate to roundoff, except that the low-angle Taylor branch (theta <= 1e-3) leaves a truncation error of up to about2e-10by default the input is not checked for being a rotation matrix:
zeros(3, 3)returns[0., 0., 3.1416]and2 * eye(3)returns[0., 0., 0.]. Passcheck_rotation=Trueto reject such an input insteadrotation_matrix_to_angle_axisis the deprecated alias of this function since 0.7.0
Warning
By default a reflection (
det = -1) is returned as a rotation:diag(-1, 1, 1)gives[0., 0., 0.], the identity. Passcheck_rotation=Trueto raise aValueErrorinstead.- Parameters:
rotation_matrix (
Tensor) – rotation matrix of shape \((*, 3, 3)\).check_rotation (
bool, optional) – ifTrue, raiseValueErrorunless every input is a rotation:max|R @ R^T - I|within 100 eps of the dtype ofrotation_matrix(16 eps for float16 and bfloat16) anddet(R) > 0. Defaults toFalse(unchecked). Default:False
- Return type:
- Returns:
Rodrigues vector transformation of shape \((*, 3)\).
Example
>>> input = torch.tensor([[1., 0., 0.], ... [0., 1., 0.], ... [0., 0., 1.]]) >>> rotation_matrix_to_axis_angle(input) tensor([0., 0., 0.])
>>> input = torch.tensor([[1., 0., 0.], ... [0., 0., -1.], ... [0., 1., 0.]]) >>> rotation_matrix_to_axis_angle(input) tensor([1.5708, 0.0000, 0.0000])
- kornia.geometry.conversions.rotation_matrix_to_quaternion(rotation_matrix, eps=1.0e-8, check_rotation=False)[source]#
Convert 3x3 rotation matrix to 4d quaternion vector.
The quaternion vector has components in (w, x, y, z) format.
- Convention:
the returned components are
(w, x, y, z), real part first — the layout, and its silent misreading, are spelled out onquaternion_to_rotation_matrix()the sign is not canonicalised to
w >= 0. Fortrace(R) > 0the returnedwis non-negative, but fortrace(R) <= 0it is the dominant ofx, y, zthat is forced non-negative andwmay be negative: 170 degrees about(1, 2, -3)/sqrt(14)(trace = -0.9696) returns[-0.0872, -0.2662, -0.5325, 0.7987]by default the input is not checked for being a rotation matrix; see the degenerate inputs listed on
rotation_matrix_to_axis_angle(). Passcheck_rotation=Trueto reject such an input instead
- Parameters:
rotation_matrix (
Tensor) – the rotation matrix to convert with shape \((*, 3, 3)\).eps (
float, optional) – floor on each square-root radicand. It is never added to the radicand: a radicand aboveepsis used as is, and one at or below it (for example the negative radicand of a discarded branch on a slightly non-orthogonal input) gives2 * sqrt(eps)with a zero gradient. For an exact rotation matrix the selected radicand is at least1, soepsdoes not change the result. The divisions are separately guarded against a zero denominator. Default:1.0e-8check_rotation (
bool, optional) – ifTrue, raiseValueErrorunless every input is a rotation:max|R @ R^T - I|within 100 eps of the dtype ofrotation_matrix(16 eps for float16 and bfloat16) anddet(R) > 0. Defaults toFalse(unchecked). Default:False
- Return type:
- Returns:
the rotation in quaternion with shape \((*, 4)\).
Example
>>> input = torch.tensor([[1., 0., 0.], ... [0., 1., 0.], ... [0., 0., 1.]]) >>> rotation_matrix_to_quaternion(input) tensor([1., 0., 0., 0.])
Axis Angle#
- kornia.geometry.conversions.axis_angle_to_quaternion(axis_angle)[source]#
Convert an axis angle to a quaternion.
The quaternion vector has components in (w, x, y, z) format.
Adapted from ceres C++ library: ceres-solver/include/ceres/rotation.h
- Convention:
the input is the rotation axis scaled by the angle in radians, shape \((*, 3)\); the output is
(w, x, y, z)withw = cos(theta / 2), shape \((*, 4)\) (seequaternion_to_rotation_matrix()for the layout)nothing is canonicalised, so
theta > pireturns thew < 0half of the double cover:[2 * pi, 0., 0.]gives[-1., 0., 0., 0.]the round trip with
quaternion_to_axis_angle()holds to roundoff for0 <= theta <= piangle_axis_to_quaternionis the deprecated alias of this function since 0.7.0an integral or boolean input is promoted, not rejected: the
sqrton the way in already produces a floating tensor, and the output is allocated from that rather than from the input, so the result comes back at the ambient default floating dtypedifferentiable at the zero rotation. The
sqrtwhose derivative is unbounded there never sees its zero radicand, so the gradient is the analytic limit of the surrounding map rather thannan. The guard is elementwise, and away from zero it moves no forward bit
- Parameters:
axis_angle (
Tensor) – tensor with axis angle in radians.- Return type:
- Returns:
tensor with quaternion.
- Shape:
Input: \((*, 3)\) where * means, any number of dimensions
Output: \((*, 4)\)
Example
>>> axis_angle = torch.tensor((0., 1., 0.)) >>> axis_angle_to_quaternion(axis_angle) tensor([0.8776, 0.0000, 0.4794, 0.0000])
- kornia.geometry.conversions.axis_angle_to_rotation_matrix(axis_angle)[source]#
Convert 3d vector of axis-angle rotation to 3x3 rotation matrix.
- Convention:
any number of leading batch dimensions is accepted: \((3,)\) gives \((3, 3)\) and \((2, 5, 3)\) gives \((2, 5, 3, 3)\)
the input is the rotation axis scaled by the angle, in radians:
[[0., 0., pi/2]]is a quarter turn about+z, while[[0., 0., 90.]]is 90 radians about+zand returns a matrix whose leading entry iscos(90) = -0.4481. The 2-D opangle_to_rotation_matrix()reads degrees insteadapplied on the left to a column vector,
+thetaabout+zmapsx_hattoy_hat(right-hand rule):[[0., 0., 0.6]]sends(1., 0., 0.)to(0.8253, 0.5646, 0.). The quaternion routequaternion_to_rotation_matrix()turns the same wayangle_axis_to_rotation_matrixis the deprecated alias of this function since 0.7.0; it emits aDeprecationWarningand forwards to this function, returning an equal resultdifferentiable at the identity rotation. The
sqrtwhose derivative is unbounded there never sees its zero radicand, so the gradient is the analytic limit of the surrounding map rather thannan. The guard is elementwise, and away from the identity it moves no forward bit
- Parameters:
axis_angle (
Tensor) – tensor of 3d vector of axis-angle rotations in radians with shape \((*, 3)\).- Return type:
- Returns:
tensor of rotation matrices of shape \((*, 3, 3)\).
Example
>>> input = torch.tensor([[0., 0., 0.]]) >>> axis_angle_to_rotation_matrix(input) tensor([[[1., ...0., 0.], [0., 1., ...0.], [...0., 0., 1.]]])
>>> input = torch.tensor([[1.5708, 0., 0.]]) >>> axis_angle_to_rotation_matrix(input) tensor([[[ 1.0000e+00, 0.0000e+00, 0.0000e+00], [ 0.0000e+00, -3.6200e-06, -1.0000e+00], [ 0.0000e+00, 1.0000e+00, -3.6200e-06]]])
Euler Angles#
- kornia.geometry.conversions.quaternion_from_euler(roll, pitch, yaw)[source]#
Convert Euler angles to quaternion coefficients.
- Convention:
roll,pitchandyaware in radians and turn aboutx,yandzrespectively; the rotation they compose to isR = Rz(yaw) @ Ry(pitch) @ Rx(roll)— extrinsic X-Y-Z about the fixed axes, equivalently intrinsic Z-Y’-X’’. The order matters: at(0.3, 0.7, 1.1)the returned quaternion’s matrix differs fromRx @ Ry @ Rzby0.64, fromRy @ Rz @ Rxby0.55and fromRx @ Rz @ Ryby0.25the three arguments must have exactly equal shapes; broadcastable shapes such as
(2,)and(1,)raiseBaseErrorthe return is a tuple of four separate tensors
(w, x, y, z), not a \((*, 4)\) tensor:(0.3, 0.7, 1.1)gives[0.8186, -0.0575, 0.3624, 0.4418]
- kornia.geometry.conversions.euler_from_quaternion(w, x, y, z)[source]#
Convert a quaternion coefficients to Euler angles.
- Convention:
the four quaternion coefficients are passed as separate tensors in
(w, x, y, z)order, not as one \((*, 4)\) tensor, and their shapes must be exactly equal: broadcastable shapes such as(2,)and(1,)raiseBaseErrorthe return is a tuple of three tensors
(roll, pitch, yaw)in radians, withrollaboutx,pitchaboutyandyawaboutz; the composition they stand for is documented onquaternion_from_euler()away from
|pitch| = pi/2it returns the triple of the input rotation folded intoroll, yawin[-pi, pi]— the interval is closed at both ends: they come fromatan2, which reaches±piwith the endpoint’s sign decided by signed zeros, sow = -0.0, x = 1.0, y = 0.0, z = -0.0returns roll exactly-piwhile the+0.0twin returns+pi— andpitchin[-pi/2, pi/2], which inside those ranges is the input itself: thefloat64round trip of(0.3, 0.7, 1.1)throughquaternion_from_euler()returns to2.2e-16, while(0.2, 2.5, 0.3)comes back as(-2.9416, 0.6416, -2.8416)— a different triple for the same rotation, to1.1e-16at
|pitch| = pi/2(gimbal lock)rollandyaware not individually determined, onlyyaw - rollat+pi/2andyaw + rollat-pi/2are, so the input triple cannot be recovered. It returnspitchexactly±pi/2,rollexactly0and that one combination inyaw, wrapped into[-pi, pi], which reproduces the rotation: the round trip throughquaternion_from_euler()is exact to rounding, andqand-qreturn the same triple. Gimbal lock is detected ascos(pitch) < 2 * sqrt(eps)for the dtype’seps(6.25e-2forfloat16,1.77e-1forbfloat16,6.9e-4forfloat32,3.0e-8forfloat64), so a pitch that close to±pi/2is also snapped to the pole and the returned rotation is off by at most its distance to itthe input is normalised with
normalize_quaternion()first, so a rescaled quaternion returns the same triple
Note
The gradient is finite everywhere, including exactly at gimbal lock. There
rollandpitchare constants, so their gradient is exactly0and all of it is inyaw: for the quaternion of(roll, pitch, yaw) = (0.1, pi/2, 0.2)the gradient ofroll + pitch + yawwith respect to(w, x, y, z)is(-0.141, -2.82, 0, 0). Within2 * sqrt(eps)of the pole it is the gradient of that constant-pitch triple, not of the plain formulas.
Pose#
- kornia.geometry.conversions.Rt_to_matrix4x4(R, t)[source]#
Combine 3x3 rotation matrix R and 3x1 translation vector t into 4x4 extrinsics.
- Convention:
tgoes in the last column and the appended bottom row is[0, 0, 0, 1], so the result acts on homogeneous column vectors asx_out = R @ x_in + t: witht = (1, 2, 3),M @ (0, 0, 0, 1)returnstitself andM @ (1, 0, 0, 1)returnsR[:, 0] + tthe function is frame-agnostic — it packs whatever
(R, t)it is handed and does not check thatRis a rotation. Under the camera-to-world reading the rest of this family uses (seecamtoworld_to_worldtocam_Rt()),tis the camera centre in world coordinates, whereas the world-to-camera form’s-R^T tis a translation and not a centre. Which of the two you are packing is your bookkeeping, not this function’sshapes are strict: exactly \((B, 3, 3)\) and \((B, 3, 1)\). An unbatched
(3, 3), a(B, 3)translation, a(B, 1, 3)translation and extra leading dimensions each raiseShapeError;Randtmust also carry the same batch size: a mismatched pair raisesShapeErrortoomatrix4x4_to_Rt()is the inverse:Rt -> 4x4 -> Rtis bitwise, while4x4 -> Rt -> 4x4is bitwise only when the bottom row is already[0, 0, 0, 1], becausematrix4x4_to_Rt()drops it
Note
Randtmust promote to a floating point or complex dtype; an integer or boolean pair raisesValueErrornaming its dtype. Mixed integer/floating inputs keep torch’s promotion. The integer-safe_4x4frame functions andcamtoworld_to_worldtocam_Rtkeep their existing behavior; the broader dtype consistency question is tracked in #3959.- Parameters:
- Return type:
- Returns:
the extrinsics \((B, 4, 4)\).
Example
>>> R, t = torch.eye(3)[None], torch.ones(3).reshape(1, 3, 1) >>> Rt_to_matrix4x4(R, t) tensor([[[1., 0., 0., 1.], [0., 1., 0., 1.], [0., 0., 1., 1.], [0., 0., 0., 1.]]])
- kornia.geometry.conversions.matrix4x4_to_Rt(extrinsics)[source]#
Convert 4x4 extrinsics into 3x3 rotation matrix R and 3x1 translation vector t.
- Convention:
the inverse of
Rt_to_matrix4x4(), with the same layout —Ris the top-left 3x3 block andtthe first three rows of the last column — and the same frame-agnosticism. Only the lines below differthe input shape is strictly \((B, 4, 4)\); an unbatched
(4, 4), a(B, 3, 3)and extra leading dimensions each raiseShapeErrorthe bottom row is ignored: a projective 4x4 is silently truncated to its rigid part, so replacing the bottom row with
[9, 9, 9, 9]leavesRandtbit-identical, and re-packing throughRt_to_matrix4x4()restores the canonical[0, 0, 0, 1]rather than what was passed inthe returned
Randtare views ofextrinsics, not copies:R.mul_(0.)zeroes the caller’s rotation block in place. Clone before mutating either output
- Parameters:
extrinsics (
Tensor) – pose matrix \((B, 4, 4)\).- Returns:
Rotation matrix, \((B, 3, 3).\) t: Translation matrix \((B, 3, 1)\).
- Return type:
R
Example
>>> ext = torch.eye(4)[None] >>> matrix4x4_to_Rt(ext) (tensor([[[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]]]), tensor([[[0.], [0.], [0.]]]))
- kornia.geometry.conversions.worldtocam_to_camtoworld_Rt(R, t, check_rotation=False)[source]#
Convert worldtocam frame used in Colmap to camtoworld.
- Convention:
See camera and world conventions for camera-to-world versus world-to-camera extrinsics and camera-centre semantics.
the same function as
camtoworld_to_worldtocam_Rt(), which carries the canonical block: for a proper rotation(R^T, -R^T @ t)is its own inverse, so one name serves both directions and the choice is documentation for the readerread the other way round here: the input
tis the world-to-camera translation and the returned-R^T tis the camera centre in world coordinatesthe shapes and the rotation warning are as documented there
- Parameters:
R (
Tensor) – Rotation matrix, \((B, 3, 3).\)t (
Tensor) – Translation matrix \((B, 3, 1)\).check_rotation (
bool, optional) – ifTrue, raiseValueErrorunless everyRis a rotation:max|R @ R^T - I|within 100 eps of the dtype ofR(16 eps for float16 and bfloat16) anddet(R) > 0. Defaults toFalse(unchecked). Default:False
- Returns:
Rotation matrix, \((B, 3, 3).\) tinv: Translation matrix \((B, 3, 1)\).
- Return type:
Rinv
Example
>>> R, t = torch.eye(3)[None], torch.ones(3).reshape(1, 3, 1) >>> worldtocam_to_camtoworld_Rt(R, t) (tensor([[[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]]]), tensor([[[-1.], [-1.], [-1.]]]))
- kornia.geometry.conversions.camtoworld_to_worldtocam_Rt(R, t, check_rotation=False)[source]#
Convert camtoworld to worldtocam frame used in Colmap.
See long-url: https://colmap.github.io/format.html#output-format
- Convention:
See camera and world conventions for camera-to-world versus world-to-camera extrinsics and camera-centre semantics.
the returned pair is exactly
(R^T, -R^T @ t)— the rigid inverse, computed by transposition and never by a matrix inverse, so for a proper rotation it inverts the pose to the working dtype’s roundingwhat
tmeans on each side: the input is a camera-to-world pose, so itstis the camera centre in world coordinates (the 4x4 sends the origin tot); the returned-R^T tis the world-to-camera translation of Colmap’simages.txt(the returned 4x4 sends the camera centre to the origin)worldtocam_to_camtoworld_Rt()is the same function under the other name: applying either one twice returnsRexactly andtto roundingthe shapes are \((B, 3, 3)\) and \((B, 3, 1)\), and
Randtmust carry the same batch size: a mismatched pair raisesShapeError
Warning
Ris assumed to be a rotation and by default this is not checked, so for a non-orthogonalRthe result is a transpose and not an inverse, silently:R = [[1, 0.5, 0], [0, 1, 0], [0, 0, 2]]givesmax|M_inv @ M - I| = 3.0. Passcheck_rotation=Trueto raise aValueErrorinstead, which also rejects reflections (det(R) < 0).- Parameters:
R (
Tensor) – Rotation matrix, \((B, 3, 3).\)t (
Tensor) – Translation matrix \((B, 3, 1)\).check_rotation (
bool, optional) – ifTrue, raiseValueErrorunless everyRis a rotation:max|R @ R^T - I|within 100 eps of the dtype ofR(16 eps for float16 and bfloat16) anddet(R) > 0. Defaults toFalse(unchecked). Default:False
- Returns:
Rotation matrix, \((B, 3, 3).\) tinv: Translation matrix \((B, 3, 1)\).
- Return type:
Rinv
Example
>>> R, t = torch.eye(3)[None], torch.ones(3).reshape(1, 3, 1) >>> camtoworld_to_worldtocam_Rt(R, t) (tensor([[[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]]]), tensor([[[-1.], [-1.], [-1.]]]))
- kornia.geometry.conversions.camtoworld_graphics_to_vision_4x4(extrinsics_graphics)[source]#
Convert a camera-to-world pose from the graphics frame (e.g. OpenGL) to the vision frame (e.g. OpenCV).
I.e. flips y and z axis. Graphics convention: [+x, +y, +z] == [right, up, backwards]. Vision convention: [+x, +y, +z] == [right, down, forwards].
- Convention:
See camera and world conventions for the graphics/vision camera frames and camera-to-world extrinsics convention.
the input is a camera-to-world pose \((B, 4, 4)\): its 3x3 block maps camera axes into the world and its last column is the camera centre in world coordinates
the operation is exactly
extrinsics @ diag(1, -1, -1, 1)— a right multiplication, i.e. a change of the camera-side basis. The translation column is untouched. Left-multiplying by the same matrix would negate two of its components instead, and feeding a world-to-camera matrix in flips the wrong side and leaves the translation in the old frame: a silent error, not an exceptiongraphics (OpenGL) camera frame:
+xright,+yup,+zbackwards — the camera looks down-z. Vision (OpenCV) camera frame:+xright,+ydown,+zforwards — the camera looks down+z. On the identity camera-to-world pose, camera+ymaps to world+ybefore the conversion and to world-yafter it, and likewise for+zthe flip preserves the determinant of the 3x3 block, and with it the handedness:
diag(1, -1, -1)has determinant+1, so a proper rotation stays proper. Nothing here checks that the input is a rotationthe flip is an involution, and all four graphics/vision frame functions compute the identical map:
camtoworld_vision_to_graphics_4x4()returns the same matrix as this one on the same input, and applying either twice returns the input. The two names document the caller’s intent, not different arithmeticthe shape is strictly \((B, 4, 4)\); the
_Rtvariants take and return \((B, 3, 3)\) and \((B, 3, 1)\) and agree with this path bitwise
Warning
Integer input is not guarded: this function returns
int64for anint64matrix (on backends with integer batched matmul), whilecamtoworld_graphics_to_vision_Rt()raisesValueErrornaming the unsupported dtype. Tracked in #3959; seeRt_to_matrix4x4().- Parameters:
extrinsics_graphics (
Tensor) – pose matrix \((B, 4, 4)\).- Returns:
pose matrix \((B, 4, 4)\).
- Return type:
Example
>>> ext = torch.eye(4)[None] >>> camtoworld_graphics_to_vision_4x4(ext) tensor([[[ 1., 0., 0., 0.], [ 0., -1., 0., 0.], [ 0., 0., -1., 0.], [ 0., 0., 0., 1.]]])
- kornia.geometry.conversions.camtoworld_vision_to_graphics_4x4(extrinsics_vision)[source]#
Convert a camera-to-world pose from the vision frame (e.g. OpenCV) to the graphics frame (e.g. OpenGL).
I.e. flips y and z axis. Graphics convention: [+x, +y, +z] == [right, up, backwards]. Vision convention: [+x, +y, +z] == [right, down, forwards].
- Convention:
See camera and world conventions for the graphics/vision camera frames and camera-to-world extrinsics convention.
the same map as
camtoworld_graphics_to_vision_4x4(), which carries the canonical block:diag(1, -1, -1, 1)is its own inverse, so vision-to-graphics and graphics-to-vision are the identical function and return bitwise equal matrices on the same input. The name records which direction the caller meanseverything else — the right multiplication, the untouched translation column, the two frame definitions, the preserved determinant, the strict \((B, 4, 4)\) shape and the integer-dtype warning — is as documented there
- Parameters:
extrinsics_vision (
Tensor) – pose matrix \((B, 4, 4)\).- Returns:
pose matrix \((B, 4, 4)\).
- Return type:
Example
>>> ext = torch.eye(4)[None] >>> camtoworld_vision_to_graphics_4x4(ext) tensor([[[ 1., 0., 0., 0.], [ 0., -1., 0., 0.], [ 0., 0., -1., 0.], [ 0., 0., 0., 1.]]])
- kornia.geometry.conversions.camtoworld_graphics_to_vision_Rt(R, t)[source]#
Convert a camera-to-world pose from the graphics frame (e.g. OpenGL) to the vision frame (e.g. OpenCV).
I.e. flips y and z axis. Graphics convention: [+x, +y, +z] == [right, up, backwards]. Vision convention: [+x, +y, +z] == [right, down, forwards].
- Convention:
See camera and world conventions for the graphics/vision camera frames and camera-to-world extrinsics convention.
the split-argument form of
camtoworld_graphics_to_vision_4x4(), which documents the flip, the two camera frames, the involution and the preserved handedness. It packs(R, t)withRt_to_matrix4x4(), applies that function and splits the result again, so the two paths agree bitwise. Only the lines below differthe shapes are strictly \((B, 3, 3)\) and \((B, 3, 1)\) in and out, with the same-batch-size rule and the integer-input
ValueErrorofRt_to_matrix4x4()tis returned unchanged; onlyRhas its second and third columns negated
- Parameters:
- Returns:
Rotation matrix, \((B, 3, 3).\) t: Translation matrix \((B, 3, 1)\).
- Return type:
R
Example
>>> R, t = torch.eye(3)[None], torch.ones(3).reshape(1, 3, 1) >>> camtoworld_graphics_to_vision_Rt(R, t) (tensor([[[ 1., 0., 0.], [ 0., -1., 0.], [ 0., 0., -1.]]]), tensor([[[1.], [1.], [1.]]]))
- kornia.geometry.conversions.camtoworld_vision_to_graphics_Rt(R, t)[source]#
Convert a camera-to-world pose from the vision frame (e.g. OpenCV) to the graphics frame (e.g. OpenGL).
I.e. flips y and z axis. Graphics convention: [+x, +y, +z] == [right, up, backwards]. Vision convention: [+x, +y, +z] == [right, down, forwards].
- Convention:
See camera and world conventions for the graphics/vision camera frames and camera-to-world extrinsics convention.
the split-argument form of
camtoworld_vision_to_graphics_4x4()and, becausediag(1, -1, -1, 1)is its own inverse, bitwise the same function ascamtoworld_graphics_to_vision_Rt(). The canonical block lives oncamtoworld_graphics_to_vision_4x4()the shapes, the unchanged
tand the warnings are as in the graphics-to-vision_Rtform
- Parameters:
- Returns:
Rotation matrix, \((B, 3, 3).\) t: Translation matrix \((B, 3, 1)\).
- Return type:
R
Example
>>> R, t = torch.eye(3)[None], torch.ones(3).reshape(1, 3, 1) >>> camtoworld_vision_to_graphics_Rt(R, t) (tensor([[[ 1., 0., 0.], [ 0., -1., 0.], [ 0., 0., -1.]]]), tensor([[[1.], [1.], [1.]]]))
- kornia.geometry.conversions.ARKitQTVecs_to_ColmapQTVecs(qvec, tvec)[source]#
Convert an Apple ARKit camera-to-world screen pose to the world-to-camera pose expected by Colmap.
Both poses in quaternion representation.
- Convention:
See camera and world conventions for the camera frames and extrinsics conventions composed by this conversion.
input:
qvec\((B, 4)\) in(w, x, y, z)order —[1., 0., 0., 0.]is the identity — andtvec\((B, 3, 1)\), read as a camera-to-world pose in the graphics frame (+yup,-zforward), sotvecis the camera centre in world coordinatesoutput:
(q, t)in the same layouts, a world-to-camera pose in the vision frame (+ydown,+zforward) — Colmap’simages.txtQW QX QY QZ TX TY TZ. The pipeline isquaternion_to_rotation_matrix(),camtoworld_graphics_to_vision_Rt(),camtoworld_to_worldtocam_Rt(), thenrotation_matrix_to_quaternion()ARKit’s
simd_quatfexposes.vectoras(ix, iy, iz, r), i.e.xyzw: reorder it towxyzfirst, since this function accepts either order silentlythe input quaternion need not be unit and
qand-qgive the same output, as long as||q||stays above theeps = 1e-12normalisation floor and its squared norm does not overflow (about1.8e19infloat32); outside that range the result is the zero-quaternion answer of the warning below or a wrong posethe sign of the output quaternion is not canonical: it is the representative
rotation_matrix_to_quaternion()’s branch produces, so[0.5, 0.5, 0.5, 0.5]witht = (1, 2, 3)returnsq = [-0.5, -0.5, -0.5, 0.5]andt = (-2, 3, 1). Compare rotations, never raw componentsworked literal:
q = [0., 1., 0., 1.],t = (1, 1, 1)givesq = [0.7071, 0., 0.7071, 0.]andt = (-1, -1, 1), the example belowColmapQTVecs_to_ARKitQTVecs()computes the reverse conversion
Warning
The zero quaternion is not rejected:
torch.zeros(1, 4)witht = (1, 1, 1)returnsq = [0., 1., 0., 0.],t = (-1, 1, 1), the same answer as the identity input. Tracked in #3952.- Parameters:
- Returns:
Colmap rotation quaternion \((B, 4)\), [w, x, y, z] format. tvec: translation vector \((B, 3, 1)\), [x, y, z]
- Return type:
qvec
Example
>>> q, t = torch.tensor([0, 1, 0, 1.])[None], torch.ones(3).reshape(1, 3, 1) >>> ARKitQTVecs_to_ColmapQTVecs(q, t) (tensor([[0.7071, 0.0000, 0.7071, 0.0000]]), tensor([[[-1.0000], [-1.0000], [ 1.0000]]]))
- kornia.geometry.conversions.ColmapQTVecs_to_ARKitQTVecs(qvec, tvec)[source]#
Convert a Colmap world-to-camera pose to an Apple ARKit camera-to-world screen pose.
Both poses in quaternion representation.
- Convention:
See camera and world conventions for the camera frames and extrinsics conventions composed by this conversion.
the reverse of
ARKitQTVecs_to_ColmapQTVecs(), with the same layouts and the frames exchangedinput:
qvec\((B, 4)\) in(w, x, y, z)order —[1., 0., 0., 0.]is the identity — andtvec\((B, 3, 1)\), read as a world-to-camera pose in the vision frame (+ydown,+zforward) — Colmap’simages.txtQW QX QY QZ TX TY TZoutput:
(q, t)in the same layouts, a camera-to-world pose in the graphics frame (+yup,-zforward), sotis the camera centre in world coordinates. The pipeline isquaternion_to_rotation_matrix(),worldtocam_to_camtoworld_Rt(),camtoworld_vision_to_graphics_Rt(), thenrotation_matrix_to_quaternion()the output is
(w, x, y, z); ARKit’ssimd_quatfstores(ix, iy, iz, r), i.e.xyzw, so reorder it before handing it to ARKitthe input quaternion need not be unit and
qand-qgive the same output, within the same normalisation range asARKitQTVecs_to_ColmapQTVecs()only real floating point
qvecandtvecare accepted: an integer, bool or complex one raisesTypeCheckError(also aTypeError) naming the argument, so cast it firstthe sign of the output quaternion is not canonical: a round trip through both functions returns the input rotation, but not necessarily the input quaternion’s sign. Compare rotations, never raw components
worked literal: the reverse of the
ARKitQTVecs_to_ColmapQTVecs()example,q = [0.7071, 0., 0.7071, 0.],t = (-1, -1, 1), givesq = [0., 0.7071, 0., 0.7071]andt = (1, 1, 1), the unit form of that example’s input; see the example below
Warning
The zero quaternion is not rejected:
torch.zeros(1, 4)witht = (1, 1, 1)returnsq = [0., 1., 0., 0.],t = (-1, -1, -1), the same answer as the identity input. Tracked in #3952.- Parameters:
- Returns:
ARKit rotation quaternion \((B, 4)\), [w, x, y, z] format. tvec: translation vector \((B, 3, 1)\), [x, y, z]
- Return type:
qvec
Example
>>> q, t = torch.tensor([0, 1, 0, 1.])[None], torch.ones(3).reshape(1, 3, 1) >>> ColmapQTVecs_to_ARKitQTVecs(*ARKitQTVecs_to_ColmapQTVecs(q, t)) (tensor([[0.0000, 0.7071, 0.0000, 0.7071]]), tensor([[[1.0000], [1.0000], [1.0000]]]))