-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Fixes camera MDP term name and reprojection docstrings #1130
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
89cd86f
adbf9f0
8167d39
20fce89
e21d5e8
2bc9480
3e0d50d
f127e73
951726c
63fd3b0
726d2b1
47e16e4
c2eebd3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -988,12 +988,7 @@ def transform_points( | |
|
|
||
| @torch.jit.script | ||
| def unproject_depth(depth: torch.Tensor, intrinsics: torch.Tensor) -> torch.Tensor: | ||
|
||
| r"""Unproject depth image into a pointcloud. This method assumes that depth | ||
| is provided orthogonally relative to the image plane, as opposed to absolutely relative to the camera's | ||
| principal point (perspective depth). To unproject a perspective depth image, use | ||
| :meth:`convert_perspective_depth_to_orthogonal_depth` to convert | ||
| to an orthogonal depth image prior to calling this method. Otherwise, the | ||
| created point cloud will be distorted, especially around the edges. | ||
| r"""Un-project orthogonal depth image into a pointcloud. | ||
|
|
||
| This function converts depth images into points given the calibration matrix of the camera. | ||
|
|
||
|
|
@@ -1003,15 +998,19 @@ def unproject_depth(depth: torch.Tensor, intrinsics: torch.Tensor) -> torch.Tens | |
| where :math:`p_{3D}` is the 3D point, :math:`d` is the depth value, :math:`u` and :math:`v` are | ||
| the pixel coordinates and :math:`K` is the intrinsic matrix. | ||
|
|
||
| If `depth` is a batch of depth images and `intrinsics` is a single intrinsic matrix, the same | ||
| calibration matrix is applied to all depth images in the batch. | ||
|
|
||
| The function assumes that the width and height are both greater than 1. This makes the function | ||
| deal with many possible shapes of depth images and intrinsics matrices. | ||
|
|
||
| Additionally, the provided depth images need to be the orthogonal distance to the camera's image plane. | ||
| In the case of perspective depth images (i.e. the depth is computed from the camera's optical center), | ||
| please use the :meth:`orthogonalize_perspective_depth` to convert the depth image to | ||
| orthogonal depth image. Otherwise, the generated pointcloud will be distorted, especially around the edges. | ||
|
|
||
| Args: | ||
| depth: The depth measurement. Shape is (H, W) or or (H, W, 1) or (N, H, W) or (N, H, W, 1). | ||
| intrinsics: A tensor providing camera's calibration matrix. Shape is (3, 3) or (N, 3, 3). | ||
| intrinsics: The camera's calibration matrix. If a single matrix is provided, the same | ||
| calibration matrix is used across all the depth images in the batch. | ||
| Shape is (3, 3) or (N, 3, 3). | ||
|
|
||
| Returns: | ||
| The 3D coordinates of points. Shape is (P, 3) or (N, P, 3). | ||
|
|
@@ -1020,8 +1019,10 @@ def unproject_depth(depth: torch.Tensor, intrinsics: torch.Tensor) -> torch.Tens | |
| ValueError: When depth is not of shape (H, W) or (H, W, 1) or (N, H, W) or (N, H, W, 1). | ||
| ValueError: When intrinsics is not of shape (3, 3) or (N, 3, 3). | ||
| """ | ||
| # clone inputs to avoid in-place modifications | ||
| depth_batch = depth.clone() | ||
| intrinsics_batch = intrinsics.clone() | ||
|
|
||
| # check if inputs are batched | ||
| is_batched = depth_batch.dim() == 4 or (depth_batch.dim() == 3 and depth_batch.shape[-1] != 1) | ||
| # make sure inputs are batched | ||
|
|
@@ -1065,37 +1066,30 @@ def unproject_depth(depth: torch.Tensor, intrinsics: torch.Tensor) -> torch.Tens | |
|
|
||
|
|
||
| @torch.jit.script | ||
| def convert_perspective_depth_to_orthogonal_depth( | ||
| perspective_depth: torch.Tensor, intrinsics: torch.Tensor | ||
| ) -> torch.Tensor: | ||
| r"""Provided depth image(s) where depth is provided as the distance to the principal | ||
| point of the camera (perspective depth), this function converts it so that depth | ||
| is provided as the distance to the camera's image plane (orthogonal depth). | ||
|
|
||
| This is helpful because `unproject_depth` assumes that depth is expressed in | ||
| the orthogonal depth format. | ||
| def orthogonalize_perspective_depth(depth: torch.Tensor, intrinsics: torch.Tensor) -> torch.Tensor: | ||
| """Converts perspective depth image to orthogonal depth image. | ||
|
|
||
| If `perspective_depth` is a batch of depth images and `intrinsics` is a single intrinsic matrix, | ||
| the same calibration matrix is applied to all depth images in the batch. | ||
| Perspective depth images contain distances measured from the camera's optical center. | ||
| Meanwhile, orthogonal depth images provide the distance from the camera's image plane. | ||
| This method uses the camera geometry to convert perspective depth to orthogonal depth image. | ||
|
|
||
| The function assumes that the width and height are both greater than 1. | ||
|
|
||
| Args: | ||
| perspective_depth: The depth measurement obtained with the distance_to_camera replicator. | ||
| Shape is (H, W) or or (H, W, 1) or (N, H, W) or (N, H, W, 1). | ||
| intrinsics: A tensor providing camera's calibration matrix. Shape is (3, 3) or (N, 3, 3). | ||
| depth: The perspective depth images. Shape is (H, W) or or (H, W, 1) or (N, H, W) or (N, H, W, 1). | ||
| intrinsics: The camera's calibration matrix. If a single matrix is provided, the same | ||
| calibration matrix is used across all the depth images in the batch. | ||
| Shape is (3, 3) or (N, 3, 3). | ||
|
|
||
| Returns: | ||
| The depth image as if obtained by the distance_to_image_plane replicator. Shape | ||
| matches the input shape of depth | ||
| The orthogonal depth images. Shape matches the input shape of depth images. | ||
|
|
||
| Raises: | ||
| ValueError: When depth is not of shape (H, W) or (H, W, 1) or (N, H, W) or (N, H, W, 1). | ||
| ValueError: When intrinsics is not of shape (3, 3) or (N, 3, 3). | ||
| """ | ||
|
|
||
| # Clone inputs to avoid in-place modifications | ||
| perspective_depth_batch = perspective_depth.clone() | ||
| perspective_depth_batch = depth.clone() | ||
| intrinsics_batch = intrinsics.clone() | ||
|
|
||
| # Check if inputs are batched | ||
|
|
@@ -1123,7 +1117,7 @@ def convert_perspective_depth_to_orthogonal_depth( | |
|
|
||
| # Validate input shapes | ||
| if perspective_depth_batch.dim() != 3: | ||
| raise ValueError(f"Expected perspective_depth to have 2, 3, or 4 dimensions; got {perspective_depth.shape}.") | ||
| raise ValueError(f"Expected depth images to have 2, 3, or 4 dimensions; got {depth.shape}.") | ||
| if intrinsics_batch.dim() != 3: | ||
| raise ValueError(f"Expected intrinsics to have shape (3, 3) or (N, 3, 3); got {intrinsics.shape}.") | ||
|
|
||
|
|
@@ -1137,8 +1131,8 @@ def convert_perspective_depth_to_orthogonal_depth( | |
| cy = intrinsics_batch[:, 1, 2].view(-1, 1, 1) | ||
|
|
||
| # Create meshgrid of pixel coordinates | ||
| u_grid = torch.arange(im_width, device=perspective_depth.device, dtype=perspective_depth.dtype) | ||
| v_grid = torch.arange(im_height, device=perspective_depth.device, dtype=perspective_depth.dtype) | ||
| u_grid = torch.arange(im_width, device=depth.device, dtype=depth.dtype) | ||
| v_grid = torch.arange(im_height, device=depth.device, dtype=depth.dtype) | ||
| u_grid, v_grid = torch.meshgrid(u_grid, v_grid, indexing="xy") | ||
|
|
||
| # Expand the grids for batch processing | ||
|
|
@@ -1150,17 +1144,17 @@ def convert_perspective_depth_to_orthogonal_depth( | |
| y_term = ((v_grid - cy) / fy) ** 2 | ||
|
|
||
| # Calculate the orthogonal (normal) depth | ||
| normal_depth = perspective_depth_batch / torch.sqrt(1 + x_term + y_term) | ||
| orthogonal_depth = perspective_depth_batch / torch.sqrt(1 + x_term + y_term) | ||
|
|
||
| # Restore the last dimension if it was present in the input | ||
| if add_last_dim: | ||
| normal_depth = normal_depth.unsqueeze(-1) | ||
| orthogonal_depth = orthogonal_depth.unsqueeze(-1) | ||
|
|
||
| # Return to original shape if input was not batched | ||
| if not is_batched: | ||
| normal_depth = normal_depth.squeeze(0) | ||
| orthogonal_depth = orthogonal_depth.squeeze(0) | ||
|
|
||
| return normal_depth | ||
| return orthogonal_depth | ||
|
|
||
|
|
||
| @torch.jit.script | ||
|
|
@@ -1191,8 +1185,10 @@ def project_points(points: torch.Tensor, intrinsics: torch.Tensor) -> torch.Tens | |
| Returns: | ||
| Projected 3D coordinates of points. Shape is (P, 3) or (N, P, 3). | ||
| """ | ||
| # clone the inputs to avoid in-place operations modifying the original data | ||
| points_batch = points.clone() | ||
| intrinsics_batch = intrinsics.clone() | ||
|
|
||
| # check if inputs are batched | ||
| is_batched = points_batch.dim() == 2 | ||
| # make sure inputs are batched | ||
|
|
@@ -1205,12 +1201,14 @@ def project_points(points: torch.Tensor, intrinsics: torch.Tensor) -> torch.Tens | |
| raise ValueError(f"Expected points to have dim = 3: got shape {points.shape}.") | ||
| if intrinsics_batch.dim() != 3: | ||
| raise ValueError(f"Expected intrinsics to have shape (3, 3) or (N, 3, 3): got shape {intrinsics.shape}.") | ||
|
|
||
| # project points into 2D image plane | ||
| points_2d = torch.matmul(intrinsics_batch, points_batch.transpose(1, 2)) | ||
| points_2d = points_2d / points_2d[:, -1, :].unsqueeze(1) # normalize by last coordinate | ||
| points_2d = points_2d.transpose_(1, 2) # (N, 3, P) -> (N, P, 3) | ||
| # replace last coordinate with depth | ||
| points_2d[:, :, -1] = points_batch[:, :, -1] | ||
|
|
||
| # return points in same shape as input | ||
| if not is_batched: | ||
| points_2d = points_2d.squeeze(0) # (1, 3, P) -> (3, P) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.