kornia.geometry.depth#
depth_to_3d() (channels first) and
depth_to_3d_v2() (channels last, optionally reusing rays from
unproject_meshgrid()) turn a depth map into 3D points, and
depth_to_normals() into surface normals. Get depth from a stereo disparity map with
depth_from_disparity(), or for pixels on a known plane with
depth_from_plane_equation(). Render an image from another viewpoint by depth with
warp_frame_depth() (a 4x4 pose and one camera matrix), or with
DepthWarper and depth_warp() (two pinhole camera models).
- kornia.geometry.depth.depth_from_disparity(disparity, baseline, focal)[source]#
Convert a rectified stereo disparity map to depth.
depth = depth_from_disparity(disparity, baseline, focal)returnsbaseline * focal / disparityfor every pixel of a(*, H, W)disparity map, withbaselinethe distance between the two camera centres andfocalthe focal length in pixels, so the depth comes out in the unit ofbaseline. A zero disparity gives a large finite depth, notinf, except in float16 (see below). To go from disparity straight to 3D points with a calibrated stereo rig, usereproject_disparity_to_3D(), which takes a(B, H, W, 1)disparity.- Convention:
the exact formula is
baseline * focal / (disparity + 1e-8): a disparity of 2 with a baseline of 0.5 and a focal length of 100 gives a depth of 25. The1e-8lowers the depth by a relative1e-8 / disparity. Float32 rounds that away from a disparity of 0.25 up; below it the bias shows,1e-6relative (10 float32 ulps) at a disparity of 0.01.a zero disparity (no stereo match, or a point at infinity) gives a finite far depth,
baseline * focal / 1e-8(5e9for baseline 0.5 and focal 100), notinf. Such a point warps as a point at infinity, along the rotation-only homography, inwarp_frame_depth(), whereas aninfdepth would turn intoNaNindepth_to_3d()wherever a ray component is zero. The far depth is a placeholder, not a measurement: maskdisparity > 0to tell matched pixels apart.in float16 the
1e-8rounds to0and the far depth would overflow anyway, so a zero disparity givesinf. A float32 far depth turns back intoinfwherever the warp casts it to float16, as a float16 pose or float16 autocast does, so run the whole warp (depth, image, pose and camera matrix) in float32, outside float16 autocast, when zero disparities flow into it.baselineandfocalare each a scalar (Python number, 0-d or(1,)tensor) shared by the whole disparity, or a(B,)tensor paired withdisparity[b], which then needs a leading batch axis of sizeB(otherwiseShapeError). The two may mix.disparityis(*, H, W)and the result has its shape. Its sign is not checked.
- Parameters:
disparity (
Tensor) – Disparity tensor of shape(*, H, W).baseline (
float|Tensor) – Distance between the two lenses, as an int, float, or tensor of shape()or(1,), or of shape(B,)for one value per batch element.focal (
float|Tensor) – Focal length, as an int, float, or tensor of shape()or(1,), or of shape(B,)for one value per batch element.
- Return type:
- Returns:
Depth map of the shape
(*, H, W).
See also
depth_to_3d(),depth_to_3d_v2(): unproject the depth map to 3D points.reproject_disparity_to_3D(): disparity to 3D points in one step.depth_from_plane_equation(): the depth of given pixels on a known plane,(B, N), not a map.
Example
>>> disparity = torch.rand(4, 1, 4, 4) >>> baseline = torch.rand(1) >>> focal = torch.rand(1) >>> depth_from_disparity(disparity, baseline, focal).shape torch.Size([4, 1, 4, 4])
- kornia.geometry.depth.depth_to_3d(depth, camera_matrix, normalize_points=False)[source]#
Unproject a depth map to a 3D point per pixel, channels first.
points = depth_to_3d(depth, camera_matrix)takes a(B, 1, H, W)map of camera-frame depths and(B, 3, 3)pixel intrinsics, and returns the camera-frame point of every pixel as a(B, 3, H, W)tensor. For a channels-last(*, H, W, 3)result, or to reuse the pixel rays across frames, usedepth_to_3d_v2()ondepth[:, 0]. To unproject selected pixels rather than a whole map, useunproject_points().- Convention:
pixel
(u, v), withuthe column andvthe row, maps to((u - cx) z / fx, (v - cy) z / fy, z). Pixel centres are integers, as inPinholeCamera.depth_to_3d(depth, K).permute(0, 2, 3, 1)equalsdepth_to_3d_v2(depth[:, 0], K).normalize_points=Truereadsdepthas the Euclidean ray length instead ofz.an integer
depthis not rejected; the result takes the floating dtype ofcamera_matrix. The pixel grid is built inpromote_types(depth.dtype, camera_matrix.dtype)when either input is floating (the default floating dtype when both are integer), so half-precisiondepthdoes not round the pixel indices below the intrinsics’ precision.
- Parameters:
depth (
Tensor) – image tensor containing a depth value per pixel with shape(B, 1, H, W).camera_matrix (
Tensor) – tensor containing the camera intrinsics with shape(B, 3, 3).normalize_points (
bool, optional) – whether to normalize the pointcloud. This must be set toTruewhen the depth is represented as the Euclidean ray length from the camera position. Default:False
- Return type:
- Returns:
tensor with a 3d point per pixel of the same resolution as the input
(B, 3, H, W).
See also
depth_to_3d_v2(): the same points channels last, with an optional cached grid.depth_to_normals(): per-pixel surface normals from the same inputs.depth_from_disparity(): depth from a stereo disparity map, to feed this function.unproject_points(): the camera-frame point of selected pixels.
Example
>>> depth = torch.rand(1, 1, 4, 4) >>> K = torch.eye(3)[None] >>> depth_to_3d(depth, K).shape torch.Size([1, 3, 4, 4])
- kornia.geometry.depth.depth_to_3d_v2(depth, camera_matrix, normalize_points=False, xyz_grid=None)[source]#
Unproject a depth map to a 3D point per pixel, channels last.
points = depth_to_3d_v2(depth, camera_matrix)takes a(*, H, W)map of camera-frame depths and(B, 3, 3)pixel intrinsics, and returns the camera-frame point of every pixel as a(*, H, W, 3)tensor. The(B, H, W, 3)rays of theBcameras broadcast againstdepthby torch’s rules, so the camera batch lines up with the axis ofdepthjust beforeH, not with its first axis: an(H, W)depth gives one map per camera, a(B, H, W)depth pairs camerabwithdepth[b], and a(B, T, H, W)depth pairs cameratwithdepth[:, t]whenT == B. WithT == 1it pairs every camera with every map and returns(B, B, H, W, 3), so passdepth[:, 0]; any otherTraises, unless there is a single camera, which then serves every map. For one camera per(B, T, H, W)batch element, passxyz_grid=unproject_meshgrid(H, W, camera_matrix)[:, None]; the same grid also saves rebuilding the pixel rays for many frames of one camera. For a channels-first(B, 3, H, W)result, usedepth_to_3d().- Convention:
pixel
(u, v), withuthe column andvthe row, maps to((u - cx) z / fx, (v - cy) z / fy, z). Pixel centres are integers, as inPinholeCamera.depth_to_3d_v2(depth[:, 0], K)equalsdepth_to_3d(depth, K).permute(0, 2, 3, 1).without
xyz_grid,camera_matrixmust be exactly(B, 3, 3)(another shape raisesShapeError); withxyz_gridonly its shape is checked.normalize_points=Truereadsdepthas the Euclidean ray length instead ofz. Withxyz_gridit is ignored: build the grid with the samenormalize_points.without
xyz_grid, the pixel grid is built inpromote_types(depth.dtype, camera_matrix.dtype)when either input is floating (the default floating dtype when both are integer), so half-precision depth does not round the pixel indices below the intrinsics’ precision.
- Parameters:
depth (
Tensor) – image tensor containing a depth value per pixel with shape(*, H, W).camera_matrix (
Tensor) – tensor containing the camera intrinsics with shape(B, 3, 3).normalize_points (
bool, optional) – whether to normalize the pointcloud. This must be set toTruewhen the depth is represented as the Euclidean ray length from the camera position. Default:Falsexyz_grid (
Optional[Tensor], optional) – explicit xyz point values. Default:None
- Return type:
- Returns:
tensor with a 3d point per pixel of the same resolution as the input,
(*, H, W, 3), whose leading dimensions are the broadcast ofdepth’s and the grid’s: the Example broadcasts a(4, 4)depth against a(2, 3, 3)camera to(2, 4, 4, 3), and a(B, T, H, W)depth with anxyz_gridof shape(B, 1, H, W, 3)returns(B, T, H, W, 3).
See also
depth_to_3d(): the same points channels first,(B, 3, H, W).unproject_meshgrid(): the per-pixel rays to pass asxyz_grid.depth_to_normals(): per-pixel surface normals, from a(B, 1, H, W)depth.unproject_points(): the camera-frame point of selected pixels.
Example
>>> depth = torch.rand(4, 4) >>> K = torch.eye(3).repeat(2,1,1) >>> depth_to_3d_v2(depth, K).shape torch.Size([2, 4, 4, 3])
- kornia.geometry.depth.unproject_meshgrid(height, width, camera_matrix, normalize_points=False, device=None, dtype=None)[source]#
Compute the camera ray through every pixel, to reuse across frames with depth_to_3d_v2.
rays = unproject_meshgrid(H, W, camera_matrix)returns the camera-frame ray of each pixel as a(B, H, W, 3)tensor, scaled so thatzis 1 by default (unit length withnormalize_points=True). It takes no depth: multiply the rays bydepth[..., None]for a(B, H, W)depth map, or pass them todepth_to_3d_v2()asxyz_grid, to get the 3D points of many frames from one camera without rebuilding the grid each time.- Convention:
pixel centres are integers; see
PinholeCamera.camera_matrixmust be(B, 3, 3); an unbatched matrix or extra leading dimensions raiseShapeError.
- Parameters:
height (
int) – height of image.width (
int) – width of image.camera_matrix (
Tensor) – tensor containing the camera intrinsics with shape(B, 3, 3).normalize_points (
bool, optional) – whether to normalize the pointcloud. This must be set toTruewhen the depth is represented as the Euclidean ray length from the camera position. Default:Falsedevice (
Optional[device], optional) – device to place the result on. Default:Nonedtype (
Optional[dtype], optional) – dtype of the pixel grid; the output dtype follows promotion withcamera_matrix. Default:None
- Return type:
- Returns:
the ray through each pixel, with
zequal to 1 (or unit length withnormalize_points=True), with shape(B, H, W, 3).
See also
depth_to_3d_v2(): takes these rays asxyz_gridand scales them by a depth map.unproject_points(): the camera-frame point of selected pixels.
- kornia.geometry.depth.depth_to_normals(depth, camera_matrix, normalize_points=False)[source]#
Estimate a unit surface normal per pixel from a depth map.
normals = depth_to_normals(depth, camera_matrix)takes the same(B, 1, H, W)depth map and(B, 3, 3)intrinsics asdepth_to_3d(), differentiates the unprojected points with a Sobelspatial_gradient(), and returns the normalized cross product of the two tangents as a(B, 3, H, W)tensor. Normals point away from the camera: a fronto-parallel plane gets(0, 0, 1).- Convention:
both spatial dimensions must be at least 2: a surface normal requires two tangent directions.
a depth growing along the columns tilts the normal towards
-x, one growing along the rows towards-y.float16 and bfloat16 inputs are widened to float32 first. The result has the promoted dtype of
depthandcamera_matrix, or the default floating dtype when both are integer, and it does not follow an enclosing autocast region: its dtype and values are the same inside autocast as outside.
- Parameters:
depth (
Tensor) – image tensor containing a depth value per pixel with shape(B, 1, H, W), with \(H \geq 2\) and \(W \geq 2\).camera_matrix (
Tensor) – tensor containing the camera intrinsics with shape(B, 3, 3).normalize_points (
bool, optional) – whether to normalize the pointcloud. This must be set toTruewhen the depth is represented as the Euclidean ray length from the camera position. Default:False
- Return type:
- Returns:
tensor with a normal surface vector per pixel of the same resolution as the input
(B, 3, H, W).- Raises:
ShapeError – if either spatial dimension of
depthis smaller than 2.
See also
depth_to_3d(): the point map whose tangents give the normals.
Example
>>> depth = torch.rand(1, 1, 4, 4) >>> K = torch.eye(3)[None] >>> depth_to_normals(depth, K).shape torch.Size([1, 3, 4, 4])
- kornia.geometry.depth.depth_from_plane_equation(plane_normals, plane_offsets, points_uv, camera_matrix, eps=1e-8)[source]#
Compute the depth of given pixels that lie on a known plane.
depth = depth_from_plane_equation(plane_normals, plane_offsets, points_uv, camera_matrix)intersects the camera ray of each pixel inpoints_uvof shape(B, N, 2)with the camera-frame plane \(n \cdot X = d\) and returns thezof each intersection as a(B, N)tensor: a list of depths, not a depth map.- Convention:
the plane is in Hessian form, with the normal
plane_normalsof shape(B, 3)and the offsetplane_offsetsof shape(B, 1):n = (0, 0, 1)withd = 2is the planez = 2, and every pixel on it has depth 2.points_uvare pixels (integer centres; seePinholeCamera), normalized here withcamera_matrix.a ray-plane dot product inside \((-eps, eps)\) is replaced by \(\pm\)
epswith its sign (+epsfor an exact zero), so a grazing ray returns the large signed depthd / epsrather thaninf. In float16 a positiveepsis floored at the smallest subnormal,2**-24, because the default1e-8rounds to zero there;d / 2**-24is stillinfin float16 once|d|exceeds about3.9e-3, so pass a largerepsfor a finite depth (eps=1e-4keeps|d| <= 6.5finite).
- Parameters:
plane_normals (torch.Tensor) – Plane normal vectors of shape
(B, 3).plane_offsets (torch.Tensor) – Plane offsets of shape
(B, 1).points_uv (torch.Tensor) – Pixel coordinates of shape
(B, N, 2).camera_matrix (torch.Tensor) – Camera intrinsic matrix of shape
(B, 3, 3).eps (
float, optional) – epsilon for numerical stability. Default:1e-8
- Returns:
Computed depth values at the given pixels, shape
(B, N).- Return type:
See also
unproject_points(): turn these pixels and depths into 3D points.depth_from_disparity(): a whole depth map from a rectified stereo disparity map, not from a plane.Hyperplane: a plane object, \(n \cdot x + d = 0\), with the offset of the opposite sign: for a batch of planes, passplane.normal.dataand-plane.offset.data[:, None].
- kornia.geometry.depth.warp_frame_depth(image_src, depth_dst, src_trans_dst, camera_matrix, normalize_points=False)[source]#
Render an image from another viewpoint, given that viewpoint’s depth map and the relative pose.
image_dst = warp_frame_depth(image_src, depth_dst, src_trans_dst, camera_matrix)shows the source image(B, D, H, W)as the destination camera sees it. Each destination pixel is unprojected with its depth fromdepth_dstof shape(B, 1, H, W), moved into the source frame by the(B, 4, 4)posesrc_trans_dst, projected with the(B, 3, 3)intrinsicscamera_matrixthat both views share, and sampled bilinearly.DepthWarperanddepth_warp()do the same warp from twoPinholeCameramodels; for a planar scene,warp_perspective()with a homography needs no depth.- Convention:
src_trans_dstmaps destination-frame points into the source frame. Withfx = fy = 1and a unit depth, a translation of 1 alongxsamplesimage_srcone pixel to the right of each destination pixel.the unprojection is
depth_to_3d_v2()and the reprojectionproject_points(), whose conventions apply.the sampling is bilinear
grid_samplewith a fixedalign_corners=Trueandpadding_mode="zeros"; the output keepsimage_src’s channels.DepthWarperanddepth_warp()name the frames the other way round: this function’sdst(the frame holding the depth) is theirsrc, andimage_srcis theirpatch_dst.a caller’s autocast region does not change the sampling grid, outside TorchScript.
- Parameters:
image_src (
Tensor) – image tensor in the source frame with shape(B, D, H, W).depth_dst (
Tensor) – depth tensor in the destination frame with shape(B, 1, H, W).src_trans_dst (
Tensor) – transformation matrix from destination to source with shape(B, 4, 4).camera_matrix (
Tensor) – tensor containing the camera intrinsics with shape(B, 3, 3).normalize_points (
bool, optional) – whether to normalize the pointcloud. This must be set toTruewhen the depth is represented as the Euclidean ray length from the camera position. Default:False
- Return type:
- Returns:
image_srcresampled onto the destination pixel grid, with shape(B, D, H, W).
A
float16/bfloat16call with every input in that dtype runs infloat32on every device and returns the input dtype: half-precision pixel coordinates and a half-precision grid are off by a pixel or more at 256 px.See also
DepthWarper,depth_warp(): the same warp from two pinhole camera models.depth_to_3d_v2(),project_points(): the two halves of the warp.warp_perspective(): warp by a homography, without depth.
- kornia.geometry.depth.depth_warp(pinhole_dst, pinhole_src, depth_src, patch_dst, height, width, align_corners=True)[source]#
Render an image from another viewpoint by depth, given two PinholeCamera models (one call).
image = depth_warp(pinhole_dst, pinhole_src, depth_src, patch_dst, H, W)samples the destination imagepatch_dstof shape(B, C, H, W)at the pixels where the source-frame depthdepth_srcprojects, so the result showspatch_dstas the source camera sees it. It isDepthWarperin one call, with that class’s defaultmodeandpadding_modeand the same output bit for bit; see its Convention block.warp_frame_depth()takes a 4x4 pose and one intrinsics matrix instead of two cameras.- Parameters:
pinhole_dst (
PinholeCamera) – the pinhole model for the destination frame, the onepatch_dstis seen from.pinhole_src (
PinholeCamera) – the pinhole model for the source frame, the onedepth_srcbelongs to.depth_src (
Tensor) – the depth in the source frame, with shape(B, 1, H, W).patch_dst (
Tensor) – the image in the destination frame, with shape(B, C, H, W).height (
int) – the height of the images,H.width (
int) – the width of the images,W.align_corners (
bool, optional) – forwarded togrid_sampleonly; the sampling grid is always normalized foralign_corners=True, soFalsemisaligns the warp (#6317). The defaultTrueis whatDepthWarperuses. Default:True
- Return type:
- Returns:
patch_dstresampled onto the source pixel grid, with shape(B, C, H, W).
See also
DepthWarper: the module form, withmodeandpadding_mode.warp_frame_depth(): the same warp from a 4x4 pose and one camera matrix.
Example
>>> # pinholes camera models >>> pinhole_dst = PinholeCamera(torch.randn(1, 4, 4), torch.randn(1, 4, 4), ... torch.tensor([32]), torch.tensor([32])) >>> pinhole_src = PinholeCamera(torch.randn(1, 4, 4), torch.randn(1, 4, 4), ... torch.tensor([32]), torch.tensor([32])) >>> # warp the destination frame to the source frame by depth >>> depth_src = torch.ones(1, 1, 32, 32) # Nx1xHxW >>> image_dst = torch.rand(1, 3, 32, 32) # NxCxHxW >>> image_src = depth_warp(pinhole_dst, pinhole_src, depth_src, image_dst, 32, 32) # NxCxHxW
- class kornia.geometry.depth.DepthWarper(pinhole_dst, height, width, mode='bilinear', padding_mode='zeros', align_corners=True)[source]#
Render an image from another viewpoint by depth, given two PinholeCamera models (module form).
Build
warper = DepthWarper(pinhole_dst, H, W), callwarper.compute_projection_matrix(pinhole_src), thenimage = warper(depth_src, patch_dst)samples the destination imagepatch_dstof shape(B, C, H, W)at the pixels where the source-frame depthdepth_srcprojects, so the(B, C, H, W)result showspatch_dstas the source camera sees it. Calling the warper beforecompute_projection_matrix()raisesValueError.depth_warp()is the one-call form;warp_frame_depth()takes a 4x4 pose and one intrinsics matrix instead of two cameras.\[ \begin{align}\begin{aligned}P_{src}^{\{dst\}} = K_{dst} * T_{src}^{\{dst\}}\\I_{src} = \omega(I_{dst}, P_{src}^{\{dst\}}, D_{src})\end{aligned}\end{align} \]- Convention:
the depth lives in the source frame and the image in the destination frame.
until
compute_projection_matrix()has been called,warp_grid()raisesValueErrorandcompute_subpixel_step()raisesRuntimeError.Half-precision cameras of one dtype compose in
float32, and afloat16/bfloat16patch with depth of its dtype builds its grid and samples infloat32on every device and returns the input dtype.warp_grid()casts the grid back to the depth’s dtype.compute_projection_matrix()storesK_dst @ (E_dst @ inverse(E_src)), the matrix above, from the constructor’spinhole_dstand that method’spinhole_src(bothPinholeCamera, world-to-camera extrinsics). Both cameras use only the top-left 3x3 block of their intrinsics, embedded in homogeneous 4x4 form; the stored fourth row and column are ignored.compute_subpixel_step()is half a pixel divided by how far the image centre,((W - 1) / 2, (H - 1) / 2), moves in the destination image per unit of inverse depth around inverse depth 1, the smallest over the batch. Two cameras with no baseline have no parallax, so it isinf, or a very large value when rounding leaves a residual translation; such a camera passes no gradient (zero, by convention, since none exists atinf), so it cannot turn the gradients of the rest of the batch into NaN. With focal lengthfand baselineb, a rectified pair gives0.5 / (f * b). It measures the image centre only: exact for a rectified pair, where every pixel moves the same, and not a bound for the whole image otherwise. Under forward motion the centre barely moves, so the step can be far coarser than the corners need.the
gridattribute is the homogeneous integer-centre pixel grid (pixel(0, 0)is(0, 0, 1));warp_grid()returns sampling positions ingrid_sample’salign_corners=Truenormalized coordinates of the destination image.align_corners(defaultTrue),modeandpadding_modeare forwarded togrid_sample, butwarp_grid()normalizes foralign_corners=Truewhatever the flag, soFalsemisaligns the warp and an identity warp no longer returns its input (#6317).warp_frame_depth()names the frames the other way round: itsdst(the frame holding the depth) is this class’ssrc, and itsimage_srcispatch_dst.a caller’s autocast region does not change
compute_projection_matrix()for cameras of one dtype. Cameras that mix float32 and half dtypes raise outside a region and compose infloat32inside one.
Warning
The two warps agree to rounding for float32/float64 away from
z = 0, and split atz = 0, wherecam2pixelsends every pixel with a nonzero projected numerator far outside the image: #4267.- Parameters:
pinhole_dst (
PinholeCamera) – the pinhole model for the destination frame.height (
int) – the height of the image to warp.width (
int) – the width of the image to warp.mode (
str, optional) – interpolation mode to calculate output values'bilinear'|'nearest'. Default:"bilinear"padding_mode (
str, optional) – padding mode for outside grid values'zeros'|'border'|'reflection'. Default:"zeros"align_corners (
bool, optional) – interpolation flag. Default:True
See also
depth_warp(): this warp in one call.warp_frame_depth(): the same warp from a 4x4 pose and one camera matrix.
- compute_projection_matrix(pinhole_src)[source]#
Compute the projection matrix from the source to destination frame.
See the Convention block on
DepthWarper.- Return type:
- compute_subpixel_step()[source]#
Compute the smallest inverse depth step over the batch for sub-pixel sampling of the depth cost volume.
See the Convention block on
DepthWarper.Szeliski, Richard, and Daniel Scharstein. “Symmetric sub-pixel stereo matching.” European Conference on Computer Vision. Springer Berlin Heidelberg, 2002.
- Return type:
- forward(depth_src, patch_dst)[source]#
Warp a tensor from the destination frame to the source frame, given the depth in the source frame.
See the Convention block on
DepthWarper.- Parameters:
- Return type:
- Returns:
the patch warped from the destination frame to the source frame.
- Shape:
Input:
(B, 1, H, W)and(B, C, H, W).Output:
(B, C, H, W)where C = number of channels.
Example
>>> # pinholes camera models >>> pinhole_dst = PinholeCamera(torch.randn(1, 4, 4), torch.randn(1, 4, 4), ... torch.tensor([32]), torch.tensor([32])) >>> pinhole_src = PinholeCamera(torch.randn(1, 4, 4), torch.randn(1, 4, 4), ... torch.tensor([32]), torch.tensor([32])) >>> # create the depth warper, compute the projection matrix >>> warper = DepthWarper(pinhole_dst, 32, 32) >>> _ = warper.compute_projection_matrix(pinhole_src) >>> # warp the destination frame to the source frame by depth >>> depth_src = torch.ones(1, 1, 32, 32) # Nx1xHxW >>> image_dst = torch.rand(1, 3, 32, 32) # NxCxHxW >>> image_src = warper(depth_src, image_dst) # NxCxHxW
- warp_grid(depth_src)[source]#
Compute where each source pixel samples the destination image, given the depth in the source frame.
See the Convention block on
DepthWarper.The method
compute_projection_matrixhas to be called beforehand in order to have precomputed the projection matrix, which moves a source-frame point into the destination camera frame and applies the destination intrinsics.- Return type: