mirror of
				https://github.com/facebookresearch/pytorch3d.git
				synced 2025-11-04 18:02:14 +08:00 
			
		
		
		
	more code blocks for readthedocs
Summary: More rst syntax fixes Reviewed By: davidsonic Differential Revision: D40977328 fbshipit-source-id: a3a3accbf2ba7cd9c84a0a82d0265010764a9d61
This commit is contained in:
		
							parent
							
								
									94f321fa3d
								
							
						
					
					
						commit
						a2c6af9250
					
				@ -25,19 +25,16 @@ This module has the master functions for loading and saving data.
 | 
			
		||||
The main usage is via the IO object, and its methods
 | 
			
		||||
`load_mesh`, `save_mesh`, `load_pointcloud` and `save_pointcloud`.
 | 
			
		||||
 | 
			
		||||
For example, to load a mesh you might do
 | 
			
		||||
```
 | 
			
		||||
from pytorch3d.io import IO
 | 
			
		||||
For example, to load a mesh you might do::
 | 
			
		||||
 | 
			
		||||
mesh = IO().load_mesh("mymesh.obj")
 | 
			
		||||
```
 | 
			
		||||
    from pytorch3d.io import IO
 | 
			
		||||
 | 
			
		||||
and to save a point cloud you might do
 | 
			
		||||
    mesh = IO().load_mesh("mymesh.obj")
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
pcl = Pointclouds(...)
 | 
			
		||||
IO().save_pointcloud(pcl, "output_pointcloud.obj")
 | 
			
		||||
```
 | 
			
		||||
and to save a point cloud you might do::
 | 
			
		||||
 | 
			
		||||
    pcl = Pointclouds(...)
 | 
			
		||||
    IO().save_pointcloud(pcl, "output_pointcloud.obj")
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1067,33 +1067,33 @@ def load_ply(
 | 
			
		||||
    is to use the IO.load_mesh and IO.load_pointcloud functions,
 | 
			
		||||
    which can read more of the data.
 | 
			
		||||
 | 
			
		||||
    Example .ply file format:
 | 
			
		||||
    Example .ply file format::
 | 
			
		||||
 | 
			
		||||
    ply
 | 
			
		||||
    format ascii 1.0           { ascii/binary, format version number }
 | 
			
		||||
    comment made by Greg Turk  { comments keyword specified, like all lines }
 | 
			
		||||
    comment this file is a cube
 | 
			
		||||
    element vertex 8           { define "vertex" element, 8 of them in file }
 | 
			
		||||
    property float x           { vertex contains float "x" coordinate }
 | 
			
		||||
    property float y           { y coordinate is also a vertex property }
 | 
			
		||||
    property float z           { z coordinate, too }
 | 
			
		||||
    element face 6             { there are 6 "face" elements in the file }
 | 
			
		||||
    property list uchar int vertex_index { "vertex_indices" is a list of ints }
 | 
			
		||||
    end_header                 { delimits the end of the header }
 | 
			
		||||
    0 0 0                      { start of vertex list }
 | 
			
		||||
    0 0 1
 | 
			
		||||
    0 1 1
 | 
			
		||||
    0 1 0
 | 
			
		||||
    1 0 0
 | 
			
		||||
    1 0 1
 | 
			
		||||
    1 1 1
 | 
			
		||||
    1 1 0
 | 
			
		||||
    4 0 1 2 3                  { start of face list }
 | 
			
		||||
    4 7 6 5 4
 | 
			
		||||
    4 0 4 5 1
 | 
			
		||||
    4 1 5 6 2
 | 
			
		||||
    4 2 6 7 3
 | 
			
		||||
    4 3 7 4 0
 | 
			
		||||
        ply
 | 
			
		||||
        format ascii 1.0           { ascii/binary, format version number }
 | 
			
		||||
        comment made by Greg Turk  { comments keyword specified, like all lines }
 | 
			
		||||
        comment this file is a cube
 | 
			
		||||
        element vertex 8           { define "vertex" element, 8 of them in file }
 | 
			
		||||
        property float x           { vertex contains float "x" coordinate }
 | 
			
		||||
        property float y           { y coordinate is also a vertex property }
 | 
			
		||||
        property float z           { z coordinate, too }
 | 
			
		||||
        element face 6             { there are 6 "face" elements in the file }
 | 
			
		||||
        property list uchar int vertex_index { "vertex_indices" is a list of ints }
 | 
			
		||||
        end_header                 { delimits the end of the header }
 | 
			
		||||
        0 0 0                      { start of vertex list }
 | 
			
		||||
        0 0 1
 | 
			
		||||
        0 1 1
 | 
			
		||||
        0 1 0
 | 
			
		||||
        1 0 0
 | 
			
		||||
        1 0 1
 | 
			
		||||
        1 1 1
 | 
			
		||||
        1 1 0
 | 
			
		||||
        4 0 1 2 3                  { start of face list }
 | 
			
		||||
        4 7 6 5 4
 | 
			
		||||
        4 0 4 5 1
 | 
			
		||||
        4 1 5 6 2
 | 
			
		||||
        4 2 6 7 3
 | 
			
		||||
        4 3 7 4 0
 | 
			
		||||
 | 
			
		||||
    Args:
 | 
			
		||||
        f:  A binary or text file-like object (with methods read, readline,
 | 
			
		||||
 | 
			
		||||
@ -208,8 +208,8 @@ def add_pointclouds_to_volumes(
 | 
			
		||||
    of `initial_volumes` with its `features` and `densities` updated with the
 | 
			
		||||
    result of the pointcloud addition.
 | 
			
		||||
 | 
			
		||||
    Example:
 | 
			
		||||
        ```
 | 
			
		||||
    Example::
 | 
			
		||||
 | 
			
		||||
        # init a random point cloud
 | 
			
		||||
        pointclouds = Pointclouds(
 | 
			
		||||
            points=torch.randn(4, 100, 3), features=torch.rand(4, 100, 5)
 | 
			
		||||
@ -229,7 +229,6 @@ def add_pointclouds_to_volumes(
 | 
			
		||||
            initial_volumes=initial_volumes,
 | 
			
		||||
            mode="trilinear",
 | 
			
		||||
        )
 | 
			
		||||
        ```
 | 
			
		||||
 | 
			
		||||
    Args:
 | 
			
		||||
        pointclouds: Batch of 3D pointclouds represented with a `Pointclouds`
 | 
			
		||||
 | 
			
		||||
@ -21,8 +21,8 @@ class HarmonicEmbedding(torch.nn.Module):
 | 
			
		||||
        (i.e. vector along the last dimension) in `x`
 | 
			
		||||
        into a series of harmonic features `embedding`,
 | 
			
		||||
        where for each i in range(dim) the following are present
 | 
			
		||||
        in embedding[...]:
 | 
			
		||||
            ```
 | 
			
		||||
        in embedding[...]::
 | 
			
		||||
 | 
			
		||||
            [
 | 
			
		||||
                sin(f_1*x[..., i]),
 | 
			
		||||
                sin(f_2*x[..., i]),
 | 
			
		||||
@ -34,7 +34,7 @@ class HarmonicEmbedding(torch.nn.Module):
 | 
			
		||||
                cos(f_N * x[..., i]),
 | 
			
		||||
                x[..., i],              # only present if append_input is True.
 | 
			
		||||
            ]
 | 
			
		||||
            ```
 | 
			
		||||
 | 
			
		||||
        where N corresponds to `n_harmonic_functions-1`, and f_i is a scalar
 | 
			
		||||
        denoting the i-th frequency of the harmonic embedding.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -25,20 +25,20 @@ class EmissionAbsorptionRaymarcher(torch.nn.Module):
 | 
			
		||||
    (i.e. its density -> 1.0).
 | 
			
		||||
 | 
			
		||||
    EA first utilizes `rays_densities` to compute the absorption function
 | 
			
		||||
    along each ray as follows:
 | 
			
		||||
        ```
 | 
			
		||||
    along each ray as follows::
 | 
			
		||||
 | 
			
		||||
        absorption = cumprod(1 - rays_densities, dim=-1)
 | 
			
		||||
        ```
 | 
			
		||||
 | 
			
		||||
    The value of absorption at position `absorption[..., k]` specifies
 | 
			
		||||
    how much light has reached `k`-th point along a ray since starting
 | 
			
		||||
    its trajectory at `k=0`-th point.
 | 
			
		||||
 | 
			
		||||
    Each ray is then rendered into a tensor `features` of shape `(..., feature_dim)`
 | 
			
		||||
    by taking a weighed combination of per-ray features `rays_features` as follows:
 | 
			
		||||
        ```
 | 
			
		||||
    by taking a weighed combination of per-ray features `rays_features` as follows::
 | 
			
		||||
 | 
			
		||||
        weights = absorption * rays_densities
 | 
			
		||||
        features = (rays_features * weights).sum(dim=-2)
 | 
			
		||||
        ```
 | 
			
		||||
 | 
			
		||||
    Where `weights` denote a function that has a strong peak around the location
 | 
			
		||||
    of the first surface point that a given ray passes through.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -32,23 +32,22 @@ class MultinomialRaysampler(torch.nn.Module):
 | 
			
		||||
    have uniformly-spaced z-coordinates between a predefined
 | 
			
		||||
    minimum and maximum depth.
 | 
			
		||||
 | 
			
		||||
    The raysampler first generates a 3D coordinate grid of the following form:
 | 
			
		||||
    ```
 | 
			
		||||
       / min_x, min_y, max_depth -------------- / max_x, min_y, max_depth
 | 
			
		||||
      /                                        /|
 | 
			
		||||
     /                                        / |     ^
 | 
			
		||||
    / min_depth                    min_depth /  |     |
 | 
			
		||||
    min_x ----------------------------- max_x   |     | image
 | 
			
		||||
    min_y                               min_y   |     | height
 | 
			
		||||
    |                                       |   |     |
 | 
			
		||||
    |                                       |   |     v
 | 
			
		||||
    |                                       |   |
 | 
			
		||||
    |                                       |   / max_x, max_y,     ^
 | 
			
		||||
    |                                       |  /  max_depth        /
 | 
			
		||||
    min_x                               max_y /                   / n_pts_per_ray
 | 
			
		||||
    max_y ----------------------------- max_x/ min_depth         v
 | 
			
		||||
              < --- image_width --- >
 | 
			
		||||
    ```
 | 
			
		||||
    The raysampler first generates a 3D coordinate grid of the following form::
 | 
			
		||||
 | 
			
		||||
           / min_x, min_y, max_depth -------------- / max_x, min_y, max_depth
 | 
			
		||||
          /                                        /|
 | 
			
		||||
         /                                        / |     ^
 | 
			
		||||
        / min_depth                    min_depth /  |     |
 | 
			
		||||
        min_x ----------------------------- max_x   |     | image
 | 
			
		||||
        min_y                               min_y   |     | height
 | 
			
		||||
        |                                       |   |     |
 | 
			
		||||
        |                                       |   |     v
 | 
			
		||||
        |                                       |   |
 | 
			
		||||
        |                                       |   / max_x, max_y,     ^
 | 
			
		||||
        |                                       |  /  max_depth        /
 | 
			
		||||
        min_x                               max_y /                   / n_pts_per_ray
 | 
			
		||||
        max_y ----------------------------- max_x/ min_depth         v
 | 
			
		||||
                < --- image_width --- >
 | 
			
		||||
 | 
			
		||||
    In order to generate ray points, `MultinomialRaysampler` takes each 3D point of
 | 
			
		||||
    the grid (with coordinates `[x, y, depth]`) and unprojects it
 | 
			
		||||
 | 
			
		||||
@ -41,13 +41,13 @@ class ImplicitRenderer(torch.nn.Module):
 | 
			
		||||
    as well as the `volumetric_function` `Callable`, which defines a field of opacity
 | 
			
		||||
    and feature vectors over the 3D domain of the scene.
 | 
			
		||||
 | 
			
		||||
    A standard `volumetric_function` has the following signature:
 | 
			
		||||
    ```
 | 
			
		||||
    def volumetric_function(
 | 
			
		||||
        ray_bundle: Union[RayBundle, HeterogeneousRayBundle],
 | 
			
		||||
        **kwargs,
 | 
			
		||||
    ) -> Tuple[torch.Tensor, torch.Tensor]
 | 
			
		||||
    ```
 | 
			
		||||
    A standard `volumetric_function` has the following signature::
 | 
			
		||||
 | 
			
		||||
        def volumetric_function(
 | 
			
		||||
            ray_bundle: Union[RayBundle, HeterogeneousRayBundle],
 | 
			
		||||
            **kwargs,
 | 
			
		||||
        ) -> Tuple[torch.Tensor, torch.Tensor]
 | 
			
		||||
 | 
			
		||||
    With the following arguments:
 | 
			
		||||
        `ray_bundle`: A RayBundle or HeterogeneousRayBundle object
 | 
			
		||||
            containing the following variables:
 | 
			
		||||
@ -79,32 +79,32 @@ class ImplicitRenderer(torch.nn.Module):
 | 
			
		||||
 | 
			
		||||
    Example:
 | 
			
		||||
        A simple volumetric function of a 0-centered
 | 
			
		||||
        RGB sphere with a unit diameter is defined as follows:
 | 
			
		||||
        ```
 | 
			
		||||
        def volumetric_function(
 | 
			
		||||
            ray_bundle: Union[RayBundle, HeterogeneousRayBundle],
 | 
			
		||||
            **kwargs,
 | 
			
		||||
        ) -> Tuple[torch.Tensor, torch.Tensor]:
 | 
			
		||||
        RGB sphere with a unit diameter is defined as follows::
 | 
			
		||||
 | 
			
		||||
            # first convert the ray origins, directions and lengths
 | 
			
		||||
            # to 3D ray point locations in world coords
 | 
			
		||||
            rays_points_world = ray_bundle_to_ray_points(ray_bundle)
 | 
			
		||||
            def volumetric_function(
 | 
			
		||||
                ray_bundle: Union[RayBundle, HeterogeneousRayBundle],
 | 
			
		||||
                **kwargs,
 | 
			
		||||
            ) -> Tuple[torch.Tensor, torch.Tensor]:
 | 
			
		||||
 | 
			
		||||
            # set the densities as an inverse sigmoid of the
 | 
			
		||||
            # ray point distance from the sphere centroid
 | 
			
		||||
            rays_densities = torch.sigmoid(
 | 
			
		||||
                -100.0 * rays_points_world.norm(dim=-1, keepdim=True)
 | 
			
		||||
            )
 | 
			
		||||
                # first convert the ray origins, directions and lengths
 | 
			
		||||
                # to 3D ray point locations in world coords
 | 
			
		||||
                rays_points_world = ray_bundle_to_ray_points(ray_bundle)
 | 
			
		||||
 | 
			
		||||
            # set the ray features to RGB colors proportional
 | 
			
		||||
            # to the 3D location of the projection of ray points
 | 
			
		||||
            # on the sphere surface
 | 
			
		||||
            rays_features = torch.nn.functional.normalize(
 | 
			
		||||
                rays_points_world, dim=-1
 | 
			
		||||
            ) * 0.5 + 0.5
 | 
			
		||||
                # set the densities as an inverse sigmoid of the
 | 
			
		||||
                # ray point distance from the sphere centroid
 | 
			
		||||
                rays_densities = torch.sigmoid(
 | 
			
		||||
                    -100.0 * rays_points_world.norm(dim=-1, keepdim=True)
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
                # set the ray features to RGB colors proportional
 | 
			
		||||
                # to the 3D location of the projection of ray points
 | 
			
		||||
                # on the sphere surface
 | 
			
		||||
                rays_features = torch.nn.functional.normalize(
 | 
			
		||||
                    rays_points_world, dim=-1
 | 
			
		||||
                ) * 0.5 + 0.5
 | 
			
		||||
 | 
			
		||||
                return rays_densities, rays_features
 | 
			
		||||
 | 
			
		||||
            return rays_densities, rays_features
 | 
			
		||||
        ```
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(self, raysampler: Callable, raymarcher: Callable) -> None:
 | 
			
		||||
 | 
			
		||||
@ -73,13 +73,13 @@ def ray_bundle_to_ray_points(
 | 
			
		||||
    extending each ray according to the corresponding length.
 | 
			
		||||
 | 
			
		||||
    E.g. for 2 dimensional tensors `ray_bundle.origins`, `ray_bundle.directions`
 | 
			
		||||
        and `ray_bundle.lengths`, the ray point at position `[i, j]` is:
 | 
			
		||||
        ```
 | 
			
		||||
        and `ray_bundle.lengths`, the ray point at position `[i, j]` is::
 | 
			
		||||
 | 
			
		||||
            ray_bundle.points[i, j, :] = (
 | 
			
		||||
                ray_bundle.origins[i, :]
 | 
			
		||||
                + ray_bundle.directions[i, :] * ray_bundle.lengths[i, j]
 | 
			
		||||
            )
 | 
			
		||||
        ```
 | 
			
		||||
 | 
			
		||||
    Note that both the directions and magnitudes of the vectors in
 | 
			
		||||
    `ray_bundle.directions` matter.
 | 
			
		||||
 | 
			
		||||
@ -109,13 +109,13 @@ def ray_bundle_variables_to_ray_points(
 | 
			
		||||
    ray length:
 | 
			
		||||
 | 
			
		||||
    E.g. for 2 dimensional input tensors `rays_origins`, `rays_directions`
 | 
			
		||||
    and `rays_lengths`, the ray point at position `[i, j]` is:
 | 
			
		||||
        ```
 | 
			
		||||
    and `rays_lengths`, the ray point at position `[i, j]` is::
 | 
			
		||||
 | 
			
		||||
            rays_points[i, j, :] = (
 | 
			
		||||
                rays_origins[i, :]
 | 
			
		||||
                + rays_directions[i, :] * rays_lengths[i, j]
 | 
			
		||||
            )
 | 
			
		||||
        ```
 | 
			
		||||
 | 
			
		||||
    Note that both the directions and magnitudes of the vectors in
 | 
			
		||||
    `rays_directions` matter.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -285,26 +285,26 @@ class _DeviceContextStore:
 | 
			
		||||
 | 
			
		||||
    The EGL/CUDA contexts are not meant to be created and destroyed all the time,
 | 
			
		||||
    and having multiple on a single device can be troublesome. Intended use is entirely
 | 
			
		||||
    transparent to the user:
 | 
			
		||||
    transparent to the user::
 | 
			
		||||
 | 
			
		||||
    ```
 | 
			
		||||
    rasterizer1 = MeshRasterizerOpenGL(...some args...)
 | 
			
		||||
    mesh1 = load_mesh_on_cuda_0()
 | 
			
		||||
        rasterizer1 = MeshRasterizerOpenGL(...some args...)
 | 
			
		||||
        mesh1 = load_mesh_on_cuda_0()
 | 
			
		||||
 | 
			
		||||
    # Now rasterizer1 will request EGL/CUDA contexts from global_device_context_store
 | 
			
		||||
    # on cuda:0, and since there aren't any, the store will create new ones.
 | 
			
		||||
    rasterizer1.rasterize(mesh1)
 | 
			
		||||
        # Now rasterizer1 will request EGL/CUDA contexts from
 | 
			
		||||
        # global_device_context_store on cuda:0, and since there aren't any, the
 | 
			
		||||
        # store will create new ones.
 | 
			
		||||
        rasterizer1.rasterize(mesh1)
 | 
			
		||||
 | 
			
		||||
    # rasterizer2 also needs EGL & CUDA contexts. But global_context_store already has
 | 
			
		||||
    # them for cuda:0. Instead of creating new contexts, the store will tell rasterizer2
 | 
			
		||||
    # to use them.
 | 
			
		||||
    rasterizer2 = MeshRasterizerOpenGL(dcs)
 | 
			
		||||
    rasterize2.rasterize(mesh1)
 | 
			
		||||
        # rasterizer2 also needs EGL & CUDA contexts. But global_context_store
 | 
			
		||||
        # already has them for cuda:0. Instead of creating new contexts, the store
 | 
			
		||||
        # will tell rasterizer2 to use them.
 | 
			
		||||
        rasterizer2 = MeshRasterizerOpenGL(dcs)
 | 
			
		||||
        rasterize2.rasterize(mesh1)
 | 
			
		||||
 | 
			
		||||
        # When rasterizer1 needs to render on cuda:1, the store will create new contexts.
 | 
			
		||||
        mesh2 = load_mesh_on_cuda_1()
 | 
			
		||||
        rasterizer1.rasterize(mesh2)
 | 
			
		||||
 | 
			
		||||
    # When rasterizer1 needs to render on cuda:1, the store will create new contexts.
 | 
			
		||||
    mesh2 = load_mesh_on_cuda_1()
 | 
			
		||||
    rasterizer1.rasterize(mesh2)
 | 
			
		||||
    ```
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,6 @@ Proper Python support for pytorch requires creating a torch.autograd.function
 | 
			
		||||
here and a torch.nn.Module is exposed for the use in more complex models.
 | 
			
		||||
"""
 | 
			
		||||
import logging
 | 
			
		||||
import math
 | 
			
		||||
import warnings
 | 
			
		||||
from typing import Optional, Tuple, Union
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -97,12 +97,12 @@ class Volumes:
 | 
			
		||||
              in the world coordinates.
 | 
			
		||||
            - They are specified with the following mapping that converts
 | 
			
		||||
              points `x_local` in the local coordinates to points `x_world`
 | 
			
		||||
              in the world coordinates:
 | 
			
		||||
                ```
 | 
			
		||||
                x_world = (
 | 
			
		||||
                    x_local * (volume_size - 1) * 0.5 * voxel_size
 | 
			
		||||
                ) - volume_translation,
 | 
			
		||||
                ```
 | 
			
		||||
              in the world coordinates::
 | 
			
		||||
 | 
			
		||||
                    x_world = (
 | 
			
		||||
                        x_local * (volume_size - 1) * 0.5 * voxel_size
 | 
			
		||||
                    ) - volume_translation,
 | 
			
		||||
 | 
			
		||||
              here `voxel_size` specifies the size of each voxel of the volume,
 | 
			
		||||
              and `volume_translation` is the 3D offset of the central voxel of
 | 
			
		||||
              the volume w.r.t. the origin of the world coordinate frame.
 | 
			
		||||
@ -110,12 +110,12 @@ class Volumes:
 | 
			
		||||
              the world coordinate units. `volume_size` is the spatial size of
 | 
			
		||||
              the volume in form of a 3D vector `[width, height, depth]`.
 | 
			
		||||
            - Given the above definition of `x_world`, one can derive the
 | 
			
		||||
              inverse mapping from `x_world` to `x_local` as follows:
 | 
			
		||||
                ```
 | 
			
		||||
                x_local = (
 | 
			
		||||
                    (x_world + volume_translation) / (0.5 * voxel_size)
 | 
			
		||||
                ) / (volume_size - 1)
 | 
			
		||||
                ```
 | 
			
		||||
              inverse mapping from `x_world` to `x_local` as follows::
 | 
			
		||||
 | 
			
		||||
                    x_local = (
 | 
			
		||||
                        (x_world + volume_translation) / (0.5 * voxel_size)
 | 
			
		||||
                    ) / (volume_size - 1)
 | 
			
		||||
 | 
			
		||||
            - For a trivial volume with `volume_translation==[0, 0, 0]`
 | 
			
		||||
              with `voxel_size=-1`, `x_world` would range
 | 
			
		||||
              from -(volume_size-1)/2` to `+(volume_size-1)/2`.
 | 
			
		||||
@ -139,13 +139,13 @@ class Volumes:
 | 
			
		||||
          to `x_local=(-1, 0, 1)`.
 | 
			
		||||
        - For a "trivial" volume `v` with `voxel_size = 1.`,
 | 
			
		||||
          `volume_translation=[0., 0., 0.]`, the following holds:
 | 
			
		||||
            ```
 | 
			
		||||
            torch.nn.functional.grid_sample(
 | 
			
		||||
                v.densities(),
 | 
			
		||||
                v.get_coord_grid(world_coordinates=False),
 | 
			
		||||
                align_corners=True,
 | 
			
		||||
            ) == v.densities(),
 | 
			
		||||
            ```
 | 
			
		||||
 | 
			
		||||
                torch.nn.functional.grid_sample(
 | 
			
		||||
                    v.densities(),
 | 
			
		||||
                    v.get_coord_grid(world_coordinates=False),
 | 
			
		||||
                    align_corners=True,
 | 
			
		||||
                ) == v.densities(),
 | 
			
		||||
 | 
			
		||||
            i.e. sampling the volume at trivial local coordinates
 | 
			
		||||
            (no scaling with `voxel_size`` or shift with `volume_translation`)
 | 
			
		||||
            results in the same volume.
 | 
			
		||||
@ -588,12 +588,12 @@ class VolumeLocator:
 | 
			
		||||
              in the world coordinates.
 | 
			
		||||
            - They are specified with the following mapping that converts
 | 
			
		||||
              points `x_local` in the local coordinates to points `x_world`
 | 
			
		||||
              in the world coordinates:
 | 
			
		||||
                ```
 | 
			
		||||
                x_world = (
 | 
			
		||||
                    x_local * (volume_size - 1) * 0.5 * voxel_size
 | 
			
		||||
                ) - volume_translation,
 | 
			
		||||
                ```
 | 
			
		||||
              in the world coordinates::
 | 
			
		||||
 | 
			
		||||
                    x_world = (
 | 
			
		||||
                        x_local * (volume_size - 1) * 0.5 * voxel_size
 | 
			
		||||
                    ) - volume_translation,
 | 
			
		||||
 | 
			
		||||
              here `voxel_size` specifies the size of each voxel of the volume,
 | 
			
		||||
              and `volume_translation` is the 3D offset of the central voxel of
 | 
			
		||||
              the volume w.r.t. the origin of the world coordinate frame.
 | 
			
		||||
@ -601,12 +601,12 @@ class VolumeLocator:
 | 
			
		||||
              the world coordinate units. `volume_size` is the spatial size of
 | 
			
		||||
              the volume in form of a 3D vector `[width, height, depth]`.
 | 
			
		||||
            - Given the above definition of `x_world`, one can derive the
 | 
			
		||||
              inverse mapping from `x_world` to `x_local` as follows:
 | 
			
		||||
                ```
 | 
			
		||||
                x_local = (
 | 
			
		||||
                    (x_world + volume_translation) / (0.5 * voxel_size)
 | 
			
		||||
                ) / (volume_size - 1)
 | 
			
		||||
                ```
 | 
			
		||||
              inverse mapping from `x_world` to `x_local` as follows::
 | 
			
		||||
 | 
			
		||||
                    x_local = (
 | 
			
		||||
                        (x_world + volume_translation) / (0.5 * voxel_size)
 | 
			
		||||
                    ) / (volume_size - 1)
 | 
			
		||||
 | 
			
		||||
            - For a trivial volume with `volume_translation==[0, 0, 0]`
 | 
			
		||||
              with `voxel_size=-1`, `x_world` would range
 | 
			
		||||
              from -(volume_size-1)/2` to `+(volume_size-1)/2`.
 | 
			
		||||
@ -629,14 +629,14 @@ class VolumeLocator:
 | 
			
		||||
          `DxHxW = 5x5x5`, the point `x_world = (-2, 0, 2)` gets mapped
 | 
			
		||||
          to `x_local=(-1, 0, 1)`.
 | 
			
		||||
        - For a "trivial" volume `v` with `voxel_size = 1.`,
 | 
			
		||||
          `volume_translation=[0., 0., 0.]`, the following holds:
 | 
			
		||||
            ```
 | 
			
		||||
            torch.nn.functional.grid_sample(
 | 
			
		||||
                v.densities(),
 | 
			
		||||
                v.get_coord_grid(world_coordinates=False),
 | 
			
		||||
                align_corners=True,
 | 
			
		||||
            ) == v.densities(),
 | 
			
		||||
            ```
 | 
			
		||||
          `volume_translation=[0., 0., 0.]`, the following holds::
 | 
			
		||||
 | 
			
		||||
                torch.nn.functional.grid_sample(
 | 
			
		||||
                    v.densities(),
 | 
			
		||||
                    v.get_coord_grid(world_coordinates=False),
 | 
			
		||||
                    align_corners=True,
 | 
			
		||||
                ) == v.densities(),
 | 
			
		||||
 | 
			
		||||
            i.e. sampling the volume at trivial local coordinates
 | 
			
		||||
            (no scaling with `voxel_size`` or shift with `volume_translation`)
 | 
			
		||||
            results in the same volume.
 | 
			
		||||
 | 
			
		||||
@ -22,18 +22,17 @@ def acos_linear_extrapolation(
 | 
			
		||||
    domain of `(-1, 1)`. This allows for stable backpropagation in case `x`
 | 
			
		||||
    is not guaranteed to be strictly within `(-1, 1)`.
 | 
			
		||||
 | 
			
		||||
    More specifically:
 | 
			
		||||
    ```
 | 
			
		||||
    bounds=(lower_bound, upper_bound)
 | 
			
		||||
    if lower_bound <= x <= upper_bound:
 | 
			
		||||
        acos_linear_extrapolation(x) = acos(x)
 | 
			
		||||
    elif x <= lower_bound: # 1st order Taylor approximation
 | 
			
		||||
        acos_linear_extrapolation(x)
 | 
			
		||||
            = acos(lower_bound) + dacos/dx(lower_bound) * (x - lower_bound)
 | 
			
		||||
    else:  # x >= upper_bound
 | 
			
		||||
        acos_linear_extrapolation(x)
 | 
			
		||||
            = acos(upper_bound) + dacos/dx(upper_bound) * (x - upper_bound)
 | 
			
		||||
    ```
 | 
			
		||||
    More specifically::
 | 
			
		||||
 | 
			
		||||
        bounds=(lower_bound, upper_bound)
 | 
			
		||||
        if lower_bound <= x <= upper_bound:
 | 
			
		||||
            acos_linear_extrapolation(x) = acos(x)
 | 
			
		||||
        elif x <= lower_bound: # 1st order Taylor approximation
 | 
			
		||||
            acos_linear_extrapolation(x)
 | 
			
		||||
                = acos(lower_bound) + dacos/dx(lower_bound) * (x - lower_bound)
 | 
			
		||||
        else:  # x >= upper_bound
 | 
			
		||||
            acos_linear_extrapolation(x)
 | 
			
		||||
                = acos(upper_bound) + dacos/dx(upper_bound) * (x - upper_bound)
 | 
			
		||||
 | 
			
		||||
    Args:
 | 
			
		||||
        x: Input `Tensor`.
 | 
			
		||||
 | 
			
		||||
@ -256,12 +256,12 @@ class Transform3d:
 | 
			
		||||
 | 
			
		||||
        The conversion from the 4x4 SE(3) matrix `transform` to the
 | 
			
		||||
        6D representation `log_transform = [log_translation | log_rotation]`
 | 
			
		||||
        is done as follows:
 | 
			
		||||
            ```
 | 
			
		||||
        is done as follows::
 | 
			
		||||
 | 
			
		||||
            log_transform = log(transform.get_matrix())
 | 
			
		||||
            log_translation = log_transform[3, :3]
 | 
			
		||||
            log_rotation = inv_hat(log_transform[:3, :3])
 | 
			
		||||
            ```
 | 
			
		||||
 | 
			
		||||
        where `log` is the matrix logarithm
 | 
			
		||||
        and `inv_hat` is the inverse of the Hat operator [2].
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -35,10 +35,10 @@ def cameras_from_opencv_projection(
 | 
			
		||||
    to the NDC screen convention of PyTorch3D.
 | 
			
		||||
 | 
			
		||||
    More specifically, the OpenCV convention projects points to the OpenCV screen
 | 
			
		||||
    space as follows:
 | 
			
		||||
        ```
 | 
			
		||||
    space as follows::
 | 
			
		||||
 | 
			
		||||
        x_screen_opencv = camera_matrix @ (R @ x_world + tvec)
 | 
			
		||||
        ```
 | 
			
		||||
 | 
			
		||||
    followed by the homogenization of `x_screen_opencv`.
 | 
			
		||||
 | 
			
		||||
    Note:
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user