Summary: Collection of spelling things, mostly in docs / tutorials.

Reviewed By: gkioxari

Differential Revision: D26101323

fbshipit-source-id: 652f62bc9d71a4ff872efa21141225e43191353a
This commit is contained in:
Jeremy Reizenstein 2021-04-09 09:57:55 -07:00 committed by Facebook GitHub Bot
parent c2e62a5087
commit 124bb5e391
75 changed files with 220 additions and 217 deletions

View File

@ -5,7 +5,7 @@
### Core library ### Core library
The core library is written in PyTorch. Several components have underlying implementation in CUDA for improved performance. A subset of these components have CPU implementations in C++/Pytorch. It is advised to use PyTorch3D with GPU support in order to use all the features. The core library is written in PyTorch. Several components have underlying implementation in CUDA for improved performance. A subset of these components have CPU implementations in C++/PyTorch. It is advised to use PyTorch3D with GPU support in order to use all the features.
- Linux or macOS or Windows - Linux or macOS or Windows
- Python 3.6, 3.7 or 3.8 - Python 3.6, 3.7 or 3.8

View File

@ -5,7 +5,7 @@ sidebar_label: Batching
# Batching # Batching
In deep learning, every optimization step operates on multiple input examples for robust training. Thus, efficient batching is crucial. For image inputs, batching is straighforward; N images are resized to the same height and width and stacked as a 4 dimensional tensor of shape `N x 3 x H x W`. For meshes, batching is less straighforward. In deep learning, every optimization step operates on multiple input examples for robust training. Thus, efficient batching is crucial. For image inputs, batching is straightforward; N images are resized to the same height and width and stacked as a 4 dimensional tensor of shape `N x 3 x H x W`. For meshes, batching is less straightforward.
<img src="assets/batch_intro.png" alt="batch_intro" align="middle"/> <img src="assets/batch_intro.png" alt="batch_intro" align="middle"/>
@ -21,7 +21,7 @@ Assume you want to construct a batch containing two meshes, with `mesh1 = (v1: V
## Use cases for batch modes ## Use cases for batch modes
The need for different mesh batch modes is inherent to the way pytorch operators are implemented. To fully utilize the optimized pytorch ops, the [Meshes][meshes] data structure allows for efficient conversion between the different batch modes. This is crucial when aiming for a fast and efficient training cycle. An example of this is [Mesh R-CNN][meshrcnn]. Here, in the same forward pass different parts of the network assume different inputs, which are computed by converting between the different batch modes. In particular, [vert_align][vert_align] assumes a *padded* input tensor while immediately after [graph_conv][graphconv] assumes a *packed* input tensor. The need for different mesh batch modes is inherent to the way PyTorch operators are implemented. To fully utilize the optimized PyTorch ops, the [Meshes][meshes] data structure allows for efficient conversion between the different batch modes. This is crucial when aiming for a fast and efficient training cycle. An example of this is [Mesh R-CNN][meshrcnn]. Here, in the same forward pass different parts of the network assume different inputs, which are computed by converting between the different batch modes. In particular, [vert_align][vert_align] assumes a *padded* input tensor while immediately after [graph_conv][graphconv] assumes a *packed* input tensor.
<img src="assets/meshrcnn.png" alt="meshrcnn" width="700" align="middle" /> <img src="assets/meshrcnn.png" alt="meshrcnn" width="700" align="middle" />

View File

@ -13,7 +13,7 @@ This is the system the object/scene lives - the world.
* **Camera view coordinate system** * **Camera view coordinate system**
This is the system that has its origin on the image plane and the `Z`-axis perpendicular to the image plane. In PyTorch3D, we assume that `+X` points left, and `+Y` points up and `+Z` points out from the image plane. The transformation from world to view happens after applying a rotation (`R`) and translation (`T`). This is the system that has its origin on the image plane and the `Z`-axis perpendicular to the image plane. In PyTorch3D, we assume that `+X` points left, and `+Y` points up and `+Z` points out from the image plane. The transformation from world to view happens after applying a rotation (`R`) and translation (`T`).
* **NDC coordinate system** * **NDC coordinate system**
This is the normalized coordinate system that confines in a volume the renderered part of the object/scene. Also known as view volume. Under the PyTorch3D convention, `(+1, +1, znear)` is the top left near corner, and `(-1, -1, zfar)` is the bottom right far corner of the volume. The transformation from view to NDC happens after applying the camera projection matrix (`P`). This is the normalized coordinate system that confines in a volume the rendered part of the object/scene. Also known as view volume. Under the PyTorch3D convention, `(+1, +1, znear)` is the top left near corner, and `(-1, -1, zfar)` is the bottom right far corner of the volume. The transformation from view to NDC happens after applying the camera projection matrix (`P`).
* **Screen coordinate system** * **Screen coordinate system**
This is another representation of the view volume with the `XY` coordinates defined in pixel space instead of a normalized space. This is another representation of the view volume with the `XY` coordinates defined in pixel space instead of a normalized space.

View File

@ -20,5 +20,5 @@ mesh = IO().load_mesh("mymesh.ply", device=device)
and to save a pointcloud you might do and to save a pointcloud you might do
``` ```
pcl = Pointclouds(...) pcl = Pointclouds(...)
IO().save_point_cloud(pcl, "output_poincloud.obj") IO().save_point_cloud(pcl, "output_pointcloud.obj")
``` ```

View File

@ -6,13 +6,13 @@ hide_title: true
# Meshes and IO # Meshes and IO
The Meshes object represents a batch of triangulated meshes, and is central to The Meshes object represents a batch of triangulated meshes, and is central to
much of the functionality of pytorch3d. There is no insistence that each mesh in much of the functionality of PyTorch3D. There is no insistence that each mesh in
the batch has the same number of vertices or faces. When available, it can store the batch has the same number of vertices or faces. When available, it can store
other data which pertains to the mesh, for example face normals, face areas other data which pertains to the mesh, for example face normals, face areas
and textures. and textures.
Two common file formats for storing single meshes are ".obj" and ".ply" files, Two common file formats for storing single meshes are ".obj" and ".ply" files,
and pytorch3d has functions for reading these. and PyTorch3D has functions for reading these.
## OBJ ## OBJ
@ -60,7 +60,7 @@ The `load_objs_as_meshes` function provides this procedure.
## PLY ## PLY
Ply files are flexible in the way they store additional information, pytorch3d Ply files are flexible in the way they store additional information. PyTorch3D
provides a function just to read the vertices and faces from a ply file. provides a function just to read the vertices and faces from a ply file.
The call The call
``` ```

View File

@ -84,7 +84,7 @@ For mesh texturing we offer several options (in `pytorch3d/renderer/mesh/texturi
1. **Vertex Textures**: D dimensional textures for each vertex (for example an RGB color) which can be interpolated across the face. This can be represented as an `(N, V, D)` tensor. This is a fairly simple representation though and cannot model complex textures if the mesh faces are large. 1. **Vertex Textures**: D dimensional textures for each vertex (for example an RGB color) which can be interpolated across the face. This can be represented as an `(N, V, D)` tensor. This is a fairly simple representation though and cannot model complex textures if the mesh faces are large.
2. **UV Textures**: vertex UV coordinates and **one** texture map for the whole mesh. For a point on a face with given barycentric coordinates, the face color can be computed by interpolating the vertex uv coordinates and then sampling from the texture map. This representation requires two tensors (UVs: `(N, V, 2), Texture map: `(N, H, W, 3)`), and is limited to only support one texture map per mesh. 2. **UV Textures**: vertex UV coordinates and **one** texture map for the whole mesh. For a point on a face with given barycentric coordinates, the face color can be computed by interpolating the vertex uv coordinates and then sampling from the texture map. This representation requires two tensors (UVs: `(N, V, 2), Texture map: `(N, H, W, 3)`), and is limited to only support one texture map per mesh.
3. **Face Textures**: In more complex cases such as ShapeNet meshes, there are multiple texture maps per mesh and some faces have texture while other do not. For these cases, a more flexible representation is a texture atlas, where each face is represented as an `(RxR)` texture map where R is the texture resolution. For a given point on the face, the texture value can be sampled from the per face texture map using the barycentric coordinates of the point. This representation requires one tensor of shape `(N, F, R, R, 3)`. This texturing method is inspired by the SoftRasterizer implementation. For more details refer to the [`make_material_atlas`](https://github.com/facebookresearch/pytorch3d/blob/master/pytorch3d/io/mtl_io.py#L123) and [`sample_textures`](https://github.com/facebookresearch/pytorch3d/blob/master/pytorch3d/renderer/mesh/textures.py#L452) functions. **NOTE:**: The `TextureAtlas` texture sampling is only differentiable with respect to the texture atlas but not differentiable with respect to the barycentric coordinates. 3. **Face Textures**: In more complex cases such as ShapeNet meshes, there are multiple texture maps per mesh and some faces have texture while other do not. For these cases, a more flexible representation is a texture atlas, where each face is represented as an `(RxR)` texture map where R is the texture resolution. For a given point on the face, the texture value can be sampled from the per face texture map using the barycentric coordinates of the point. This representation requires one tensor of shape `(N, F, R, R, 3)`. This texturing method is inspired by the SoftRasterizer implementation. For more details refer to the [`make_material_atlas`](https://github.com/facebookresearch/pytorch3d/blob/master/pytorch3d/io/mtl_io.py#L123) and [`sample_textures`](https://github.com/facebookresearch/pytorch3d/blob/master/pytorch3d/renderer/mesh/textures.py#L452) functions. **NOTE:**: The `TexturesAtlas` texture sampling is only differentiable with respect to the texture atlas but not differentiable with respect to the barycentric coordinates.
<img src="assets/texturing.jpg" width="1000"> <img src="assets/texturing.jpg" width="1000">
@ -116,7 +116,7 @@ raster_settings = RasterizationSettings(
faces_per_pixel=1, faces_per_pixel=1,
) )
# Create a phong renderer by composing a rasterizer and a shader. Here we can use a predefined # Create a Phong renderer by composing a rasterizer and a shader. Here we can use a predefined
# PhongShader, passing in the device on which to initialize the default parameters # PhongShader, passing in the device on which to initialize the default parameters
renderer = MeshRenderer( renderer = MeshRenderer(
rasterizer=MeshRasterizer(cameras=cameras, raster_settings=raster_settings), rasterizer=MeshRasterizer(cameras=cameras, raster_settings=raster_settings),

View File

@ -387,7 +387,7 @@
" device = device,\n", " device = device,\n",
" )\n", " )\n",
"\n", "\n",
" # compute the relative cameras as a compositon of the absolute cameras\n", " # compute the relative cameras as a composition of the absolute cameras\n",
" cameras_relative_composed = \\\n", " cameras_relative_composed = \\\n",
" get_relative_camera(cameras_absolute, relative_edges)\n", " get_relative_camera(cameras_absolute, relative_edges)\n",
"\n", "\n",

View File

@ -223,9 +223,9 @@
"source": [ "source": [
"### Create a renderer\n", "### Create a renderer\n",
"\n", "\n",
"A **renderer** in PyTorch3D is composed of a **rasterizer** and a **shader** which each have a number of subcomponents such as a **camera** (orthgraphic/perspective). Here we initialize some of these components and use default values for the rest. \n", "A **renderer** in PyTorch3D is composed of a **rasterizer** and a **shader** which each have a number of subcomponents such as a **camera** (orthographic/perspective). Here we initialize some of these components and use default values for the rest. \n",
"\n", "\n",
"For optimizing the camera position we will use a renderer which produces a **silhouette** of the object only and does not apply any **lighting** or **shading**. We will also initialize another renderer which applies full **phong shading** and use this for visualizing the outputs. " "For optimizing the camera position we will use a renderer which produces a **silhouette** of the object only and does not apply any **lighting** or **shading**. We will also initialize another renderer which applies full **Phong shading** and use this for visualizing the outputs. "
] ]
}, },
{ {
@ -266,7 +266,7 @@
")\n", ")\n",
"\n", "\n",
"\n", "\n",
"# We will also create a phong renderer. This is simpler and only needs to render one face per pixel.\n", "# We will also create a Phong renderer. This is simpler and only needs to render one face per pixel.\n",
"raster_settings = RasterizationSettings(\n", "raster_settings = RasterizationSettings(\n",
" image_size=256, \n", " image_size=256, \n",
" blur_radius=0.0, \n", " blur_radius=0.0, \n",
@ -322,15 +322,15 @@
"R, T = look_at_view_transform(distance, elevation, azimuth, device=device)\n", "R, T = look_at_view_transform(distance, elevation, azimuth, device=device)\n",
"\n", "\n",
"# Render the teapot providing the values of R and T. \n", "# Render the teapot providing the values of R and T. \n",
"silhouete = silhouette_renderer(meshes_world=teapot_mesh, R=R, T=T)\n", "silhouette = silhouette_renderer(meshes_world=teapot_mesh, R=R, T=T)\n",
"image_ref = phong_renderer(meshes_world=teapot_mesh, R=R, T=T)\n", "image_ref = phong_renderer(meshes_world=teapot_mesh, R=R, T=T)\n",
"\n", "\n",
"silhouete = silhouete.cpu().numpy()\n", "silhouette = silhouette.cpu().numpy()\n",
"image_ref = image_ref.cpu().numpy()\n", "image_ref = image_ref.cpu().numpy()\n",
"\n", "\n",
"plt.figure(figsize=(10, 10))\n", "plt.figure(figsize=(10, 10))\n",
"plt.subplot(1, 2, 1)\n", "plt.subplot(1, 2, 1)\n",
"plt.imshow(silhouete.squeeze()[..., 3]) # only plot the alpha channel of the RGBA image\n", "plt.imshow(silhouette.squeeze()[..., 3]) # only plot the alpha channel of the RGBA image\n",
"plt.grid(False)\n", "plt.grid(False)\n",
"plt.subplot(1, 2, 2)\n", "plt.subplot(1, 2, 2)\n",
"plt.imshow(image_ref.squeeze())\n", "plt.imshow(image_ref.squeeze())\n",
@ -377,7 +377,7 @@
" def forward(self):\n", " def forward(self):\n",
" \n", " \n",
" # Render the image using the updated camera position. Based on the new position of the \n", " # Render the image using the updated camera position. Based on the new position of the \n",
" # camer we calculate the rotation and translation matrices\n", " # camera we calculate the rotation and translation matrices\n",
" R = look_at_rotation(self.camera_position[None, :], device=self.device) # (1, 3, 3)\n", " R = look_at_rotation(self.camera_position[None, :], device=self.device) # (1, 3, 3)\n",
" T = -torch.bmm(R.transpose(1, 2), self.camera_position[None, :, None])[:, :, 0] # (1, 3)\n", " T = -torch.bmm(R.transpose(1, 2), self.camera_position[None, :, None])[:, :, 0] # (1, 3)\n",
" \n", " \n",

View File

@ -190,7 +190,7 @@
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {}, "metadata": {},
"source": [ "source": [
"We can retrieve a model by indexing into the loaded dataset. For both ShapeNetCore and R2N2, we can examine the category this model belongs to (in the form of a synset id, equivalend to wnid described in ImageNet's API: http://image-net.org/download-API), its model id, and its vertices and faces." "We can retrieve a model by indexing into the loaded dataset. For both ShapeNetCore and R2N2, we can examine the category this model belongs to (in the form of a synset id, equivalent to wnid described in ImageNet's API: http://image-net.org/download-API), its model id, and its vertices and faces."
] ]
}, },
{ {
@ -254,11 +254,11 @@
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {}, "metadata": {},
"source": [ "source": [
"Training deep learning models, usually requires passing in batches of inputs. The `torch.utils.data.DataLoader` from Pytorch helps us do this. PyTorch3D provides a function `collate_batched_meshes` to group the input meshes into a single `Meshes` object which represents the batch. The `Meshes` datastructure can then be used directly by other PyTorch3D ops which might be part of the deep learning model (e.g. `graph_conv`).\n", "Training deep learning models, usually requires passing in batches of inputs. The `torch.utils.data.DataLoader` from PyTorch helps us do this. PyTorch3D provides a function `collate_batched_meshes` to group the input meshes into a single `Meshes` object which represents the batch. The `Meshes` datastructure can then be used directly by other PyTorch3D ops which might be part of the deep learning model (e.g. `graph_conv`).\n",
"\n", "\n",
"For R2N2, if all the models in the batch have the same number of views, the views, rotation matrices, translation matrices, intrinsic matrices and voxels will also be stacked into batched tensors.\n", "For R2N2, if all the models in the batch have the same number of views, the views, rotation matrices, translation matrices, intrinsic matrices and voxels will also be stacked into batched tensors.\n",
"\n", "\n",
"**NOTE**: All models in the `val` split of R2N2 have 24 views, but there are 8 models that split their 24 views between `train` and `test` splits, in which case `collate_batched_meshes` will only be able to join the matrices, views and voxels as lists. However, this can be avoided by laoding only one view of each model by setting `return_all_views = False`." "**NOTE**: All models in the `val` split of R2N2 have 24 views, but there are 8 models that split their 24 views between `train` and `test` splits, in which case `collate_batched_meshes` will only be able to join the matrices, views and voxels as lists. However, this can be avoided by loading only one view of each model by setting `return_all_views = False`."
] ]
}, },
{ {
@ -295,7 +295,7 @@
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {}, "metadata": {},
"source": [ "source": [
"## 3. Render ShapeNetCore models with PyTorch3D's differntiable renderer" "## 3. Render ShapeNetCore models with PyTorch3D's differentiable renderer"
] ]
}, },
{ {
@ -450,7 +450,7 @@
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {}, "metadata": {},
"source": [ "source": [
"Next, we will visualize PyTorch3d's renderings:" "Next, we will visualize PyTorch3D's renderings:"
] ]
}, },
{ {

View File

@ -17,7 +17,7 @@
"\n", "\n",
"This tutorial shows how to fit Neural Radiance Field given a set of views of a scene using differentiable implicit function rendering.\n", "This tutorial shows how to fit Neural Radiance Field given a set of views of a scene using differentiable implicit function rendering.\n",
"\n", "\n",
"More specificially, this tutorial will explain how to:\n", "More specifically, this tutorial will explain how to:\n",
"1. Create a differentiable implicit function renderer with either image-grid or Monte Carlo ray sampling.\n", "1. Create a differentiable implicit function renderer with either image-grid or Monte Carlo ray sampling.\n",
"2. Create an Implicit model of a scene.\n", "2. Create an Implicit model of a scene.\n",
"3. Fit the implicit function (Neural Radiance Field) based on input images using the differentiable implicit renderer. \n", "3. Fit the implicit function (Neural Radiance Field) based on input images using the differentiable implicit renderer. \n",
@ -158,9 +158,9 @@
"The following initializes an implicit renderer that emits a ray from each pixel of a target image and samples a set of uniformly-spaced points along the ray. At each ray-point, the corresponding density and color value is obtained by querying the corresponding location in the neural model of the scene (the model is described & instantiated in a later cell).\n", "The following initializes an implicit renderer that emits a ray from each pixel of a target image and samples a set of uniformly-spaced points along the ray. At each ray-point, the corresponding density and color value is obtained by querying the corresponding location in the neural model of the scene (the model is described & instantiated in a later cell).\n",
"\n", "\n",
"The renderer is composed of a *raymarcher* and a *raysampler*.\n", "The renderer is composed of a *raymarcher* and a *raysampler*.\n",
"- The *raysampler* is responsible for emiting rays from image pixels and sampling the points along them. Here, we use two different raysamplers:\n", "- The *raysampler* is responsible for emitting rays from image pixels and sampling the points along them. Here, we use two different raysamplers:\n",
" - `MonteCarloRaysampler` is used to generate rays from a random subset of pixels of the image plane. The random subsampling of pixels is carried out during **training** to decrease the memory consumption of the implicit model.\n", " - `MonteCarloRaysampler` is used to generate rays from a random subset of pixels of the image plane. The random subsampling of pixels is carried out during **training** to decrease the memory consumption of the implicit model.\n",
" - `NDCGridRaysampler` which follows the standard PyTorch3d coordinate grid convention (+X from right to left; +Y from bottom to top; +Z away from the user). In combination with the implicit model of the scene, `NDCGridRaysampler` consumes a large amount of memory and, hence, is only used for visualizing the results of the training at **test** time.\n", " - `NDCGridRaysampler` which follows the standard PyTorch3D coordinate grid convention (+X from right to left; +Y from bottom to top; +Z away from the user). In combination with the implicit model of the scene, `NDCGridRaysampler` consumes a large amount of memory and, hence, is only used for visualizing the results of the training at **test** time.\n",
"- The *raymarcher* takes the densities and colors sampled along each ray and renders each ray into a color and an opacity value of the ray's source pixel. Here we use the `EmissionAbsorptionRaymarcher` which implements the standard Emission-Absorption raymarching algorithm." "- The *raymarcher* takes the densities and colors sampled along each ray and renders each ray into a color and an opacity value of the ray's source pixel. Here we use the `EmissionAbsorptionRaymarcher` which implements the standard Emission-Absorption raymarching algorithm."
] ]
}, },
@ -186,7 +186,7 @@
"# 1) Instantiate the raysamplers.\n", "# 1) Instantiate the raysamplers.\n",
"\n", "\n",
"# Here, NDCGridRaysampler generates a rectangular image\n", "# Here, NDCGridRaysampler generates a rectangular image\n",
"# grid of rays whose coordinates follow the PyTorch3d\n", "# grid of rays whose coordinates follow the PyTorch3D\n",
"# coordinate conventions.\n", "# coordinate conventions.\n",
"raysampler_grid = NDCGridRaysampler(\n", "raysampler_grid = NDCGridRaysampler(\n",
" image_height=render_size,\n", " image_height=render_size,\n",
@ -236,7 +236,7 @@
"\n", "\n",
"The `forward` function of `NeuralRadianceField` (NeRF) receives as input a set of tensors that parametrize a bundle of rendering rays. The ray bundle is later converted to 3D ray points in the world coordinates of the scene. Each 3D point is then mapped to a harmonic representation using the `HarmonicEmbedding` layer (defined in the next cell). The harmonic embeddings then enter the _color_ and _opacity_ branches of the NeRF model in order to label each ray point with a 3D vector and a 1D scalar ranging in [0-1] which define the point's RGB color and opacity respectively.\n", "The `forward` function of `NeuralRadianceField` (NeRF) receives as input a set of tensors that parametrize a bundle of rendering rays. The ray bundle is later converted to 3D ray points in the world coordinates of the scene. Each 3D point is then mapped to a harmonic representation using the `HarmonicEmbedding` layer (defined in the next cell). The harmonic embeddings then enter the _color_ and _opacity_ branches of the NeRF model in order to label each ray point with a 3D vector and a 1D scalar ranging in [0-1] which define the point's RGB color and opacity respectively.\n",
"\n", "\n",
"Since NeRF has a large memory footprint, we also implement the `NeuralRadianceField.forward_batched` method. The method splits the input rays into batches and executes the `forward` function for each batch separately in a for loop. This allows to render a large set of rays without running out of GPU memory. Standardly, `forward_batched` would be used to render rays emitted from all pixels of an image in order to produce a full-sized render of a scene.\n" "Since NeRF has a large memory footprint, we also implement the `NeuralRadianceField.forward_batched` method. The method splits the input rays into batches and executes the `forward` function for each batch separately in a for loop. This lets us render a large set of rays without running out of GPU memory. Standardly, `forward_batched` would be used to render rays emitted from all pixels of an image in order to produce a full-sized render of a scene.\n"
] ]
}, },
{ {
@ -266,7 +266,7 @@
" ]\n", " ]\n",
" \n", " \n",
" Note that `x` is also premultiplied by `omega0` before\n", " Note that `x` is also premultiplied by `omega0` before\n",
" evaluting the harmonic functions.\n", " evaluating the harmonic functions.\n",
" \"\"\"\n", " \"\"\"\n",
" super().__init__()\n", " super().__init__()\n",
" self.register_buffer(\n", " self.register_buffer(\n",
@ -417,7 +417,7 @@
"\n", "\n",
" Returns:\n", " Returns:\n",
" rays_densities: A tensor of shape `(minibatch, ..., num_points_per_ray, 1)`\n", " rays_densities: A tensor of shape `(minibatch, ..., num_points_per_ray, 1)`\n",
" denoting the opacitiy of each ray point.\n", " denoting the opacity of each ray point.\n",
" rays_colors: A tensor of shape `(minibatch, ..., num_points_per_ray, 3)`\n", " rays_colors: A tensor of shape `(minibatch, ..., num_points_per_ray, 3)`\n",
" denoting the color of each ray point.\n", " denoting the color of each ray point.\n",
" \"\"\"\n", " \"\"\"\n",
@ -457,11 +457,11 @@
" This function is used to allow for memory efficient processing\n", " This function is used to allow for memory efficient processing\n",
" of input rays. The input rays are first split to `n_batches`\n", " of input rays. The input rays are first split to `n_batches`\n",
" chunks and passed through the `self.forward` function one at a time\n", " chunks and passed through the `self.forward` function one at a time\n",
" in a for loop. Combined with disabling Pytorch gradient caching\n", " in a for loop. Combined with disabling PyTorch gradient caching\n",
" (`torch.no_grad()`), this allows for rendering large batches\n", " (`torch.no_grad()`), this allows for rendering large batches\n",
" of rays that do not all fit into GPU memory in a single forward pass.\n", " of rays that do not all fit into GPU memory in a single forward pass.\n",
" In our case, batched_forward is used to export a fully-sized render\n", " In our case, batched_forward is used to export a fully-sized render\n",
" of the radiance field for visualisation purposes.\n", " of the radiance field for visualization purposes.\n",
" \n", " \n",
" Args:\n", " Args:\n",
" ray_bundle: A RayBundle object containing the following variables:\n", " ray_bundle: A RayBundle object containing the following variables:\n",
@ -477,7 +477,7 @@
"\n", "\n",
" Returns:\n", " Returns:\n",
" rays_densities: A tensor of shape `(minibatch, ..., num_points_per_ray, 1)`\n", " rays_densities: A tensor of shape `(minibatch, ..., num_points_per_ray, 1)`\n",
" denoting the opacitiy of each ray point.\n", " denoting the opacity of each ray point.\n",
" rays_colors: A tensor of shape `(minibatch, ..., num_points_per_ray, 3)`\n", " rays_colors: A tensor of shape `(minibatch, ..., num_points_per_ray, 3)`\n",
" denoting the color of each ray point.\n", " denoting the color of each ray point.\n",
"\n", "\n",
@ -576,12 +576,12 @@
" intermediate results of the learning. \n", " intermediate results of the learning. \n",
" \n", " \n",
" Since the `NeuralRadianceField` suffers from\n", " Since the `NeuralRadianceField` suffers from\n",
" a large memory footprint, which does not allow to\n", " a large memory footprint, which does not let us\n",
" render the full image grid in a single forward pass,\n", " render the full image grid in a single forward pass,\n",
" we utilize the `NeuralRadianceField.batched_forward`\n", " we utilize the `NeuralRadianceField.batched_forward`\n",
" function in combination with disabling the gradient caching.\n", " function in combination with disabling the gradient caching.\n",
" This chunks the set of emitted rays to batches and \n", " This chunks the set of emitted rays to batches and \n",
" evaluates the implicit function on one-batch at a time\n", " evaluates the implicit function on one batch at a time\n",
" to prevent GPU memory overflow.\n", " to prevent GPU memory overflow.\n",
" \"\"\"\n", " \"\"\"\n",
" \n", " \n",
@ -720,7 +720,7 @@
" rendered_images_silhouettes.split([3, 1], dim=-1)\n", " rendered_images_silhouettes.split([3, 1], dim=-1)\n",
" )\n", " )\n",
" \n", " \n",
" # Compute the silhoutte error as the mean huber\n", " # Compute the silhouette error as the mean huber\n",
" # loss between the predicted masks and the\n", " # loss between the predicted masks and the\n",
" # sampled target silhouettes.\n", " # sampled target silhouettes.\n",
" silhouettes_at_rays = sample_images_at_mc_locs(\n", " silhouettes_at_rays = sample_images_at_mc_locs(\n",
@ -818,7 +818,7 @@
" fov=target_cameras.fov[0],\n", " fov=target_cameras.fov[0],\n",
" device=device,\n", " device=device,\n",
" )\n", " )\n",
" # Note that we again render with `NDCGridSampler`\n", " # Note that we again render with `NDCGridRaySampler`\n",
" # and the batched_forward function of neural_radiance_field.\n", " # and the batched_forward function of neural_radiance_field.\n",
" frames.append(\n", " frames.append(\n",
" renderer_grid(\n", " renderer_grid(\n",
@ -841,7 +841,7 @@
"source": [ "source": [
"## 6. Conclusion\n", "## 6. Conclusion\n",
"\n", "\n",
"In this tutorial, we have shown how to optimize an implicit representation of a scene such that the renders of the scene from known viewpoints match the observed images for each viewpoint. The rendering was carried out using the Pytorch3D's implicit function renderer composed of either a `MonteCarloRaysampler` or `NDCGridRaysampler`, and an `EmissionAbsorptionRaymarcher`." "In this tutorial, we have shown how to optimize an implicit representation of a scene such that the renders of the scene from known viewpoints match the observed images for each viewpoint. The rendering was carried out using the PyTorch3D's implicit function renderer composed of either a `MonteCarloRaysampler` or `NDCGridRaysampler`, and an `EmissionAbsorptionRaymarcher`."
] ]
} }
], ],

View File

@ -193,11 +193,11 @@
"source": [ "source": [
"### 1. Load a mesh and texture file\n", "### 1. Load a mesh and texture file\n",
"\n", "\n",
"Load an `.obj` file and it's associated `.mtl` file and create a **Textures** and **Meshes** object. \n", "Load an `.obj` file and its associated `.mtl` file and create a **Textures** and **Meshes** object. \n",
"\n", "\n",
"**Meshes** is a unique datastructure provided in PyTorch3D for working with batches of meshes of different sizes. \n", "**Meshes** is a unique datastructure provided in PyTorch3D for working with batches of meshes of different sizes. \n",
"\n", "\n",
"**TexturesVertex** is an auxillary datastructure for storing vertex rgb texture information about meshes. \n", "**TexturesVertex** is an auxiliary datastructure for storing vertex rgb texture information about meshes. \n",
"\n", "\n",
"**Meshes** has several class methods which are used throughout the rendering pipeline." "**Meshes** has several class methods which are used throughout the rendering pipeline."
] ]
@ -315,7 +315,7 @@
"# purposes only we will set faces_per_pixel=1 and blur_radius=0.0. Refer to \n", "# purposes only we will set faces_per_pixel=1 and blur_radius=0.0. Refer to \n",
"# rasterize_meshes.py for explanations of these parameters. We also leave \n", "# rasterize_meshes.py for explanations of these parameters. We also leave \n",
"# bin_size and max_faces_per_bin to their default values of None, which sets \n", "# bin_size and max_faces_per_bin to their default values of None, which sets \n",
"# their values using huristics and ensures that the faster coarse-to-fine \n", "# their values using heuristics and ensures that the faster coarse-to-fine \n",
"# rasterization method is used. Refer to docs/notes/renderer.md for an \n", "# rasterization method is used. Refer to docs/notes/renderer.md for an \n",
"# explanation of the difference between naive and coarse-to-fine rasterization. \n", "# explanation of the difference between naive and coarse-to-fine rasterization. \n",
"raster_settings = RasterizationSettings(\n", "raster_settings = RasterizationSettings(\n",
@ -324,8 +324,8 @@
" faces_per_pixel=1, \n", " faces_per_pixel=1, \n",
")\n", ")\n",
"\n", "\n",
"# Create a phong renderer by composing a rasterizer and a shader. The textured \n", "# Create a Phong renderer by composing a rasterizer and a shader. The textured \n",
"# phong shader will interpolate the texture uv coordinates for each vertex, \n", "# Phong shader will interpolate the texture uv coordinates for each vertex, \n",
"# sample from a texture image and apply the Phong lighting model\n", "# sample from a texture image and apply the Phong lighting model\n",
"renderer = MeshRenderer(\n", "renderer = MeshRenderer(\n",
" rasterizer=MeshRasterizer(\n", " rasterizer=MeshRasterizer(\n",
@ -386,7 +386,7 @@
"id": "gOb4rYx65E8z" "id": "gOb4rYx65E8z"
}, },
"source": [ "source": [
"Later in this tutorial, we will fit a mesh to the rendered RGB images, as well as to just images of just the cow silhouette. For the latter case, we will render a dataset of silhouette images. Most shaders in PyTorch3D will output an alpha channel along with the RGB image as a 4th channel in an RGBA image. The alpha channel encodes the probability that each pixel belongs to the foreground of the object. We contruct a soft silhouette shader to render this alpha channel." "Later in this tutorial, we will fit a mesh to the rendered RGB images, as well as to just images of just the cow silhouette. For the latter case, we will render a dataset of silhouette images. Most shaders in PyTorch3D will output an alpha channel along with the RGB image as a 4th channel in an RGBA image. The alpha channel encodes the probability that each pixel belongs to the foreground of the object. We construct a soft silhouette shader to render this alpha channel."
] ]
}, },
{ {
@ -607,7 +607,7 @@
"id": "QLc9zK8lEqFS" "id": "QLc9zK8lEqFS"
}, },
"source": [ "source": [
"We write an optimization loop to iteratively refine our predicted mesh from the sphere mesh into a mesh that matches the sillhouettes of the target images:" "We write an optimization loop to iteratively refine our predicted mesh from the sphere mesh into a mesh that matches the silhouettes of the target images:"
] ]
}, },
{ {

View File

@ -17,7 +17,7 @@
"\n", "\n",
"This tutorial shows how to fit a volume given a set of views of a scene using differentiable volumetric rendering.\n", "This tutorial shows how to fit a volume given a set of views of a scene using differentiable volumetric rendering.\n",
"\n", "\n",
"More specificially, this tutorial will explain how to:\n", "More specifically, this tutorial will explain how to:\n",
"1. Create a differentiable volumetric renderer.\n", "1. Create a differentiable volumetric renderer.\n",
"2. Create a Volumetric model (including how to use the `Volumes` class).\n", "2. Create a Volumetric model (including how to use the `Volumes` class).\n",
"3. Fit the volume based on the images using the differentiable volumetric renderer. \n", "3. Fit the volume based on the images using the differentiable volumetric renderer. \n",
@ -138,7 +138,7 @@
"The following initializes a volumetric renderer that emits a ray from each pixel of a target image and samples a set of uniformly-spaced points along the ray. At each ray-point, the corresponding density and color value is obtained by querying the corresponding location in the volumetric model of the scene (the model is described & instantiated in a later cell).\n", "The following initializes a volumetric renderer that emits a ray from each pixel of a target image and samples a set of uniformly-spaced points along the ray. At each ray-point, the corresponding density and color value is obtained by querying the corresponding location in the volumetric model of the scene (the model is described & instantiated in a later cell).\n",
"\n", "\n",
"The renderer is composed of a *raymarcher* and a *raysampler*.\n", "The renderer is composed of a *raymarcher* and a *raysampler*.\n",
"- The *raysampler* is responsible for emiting rays from image pixels and sampling the points along them. Here, we use the `NDCGridRaysampler` which follows the standard PyTorch3D coordinate grid convention (+X from right to left; +Y from bottom to top; +Z away from the user).\n", "- The *raysampler* is responsible for emitting rays from image pixels and sampling the points along them. Here, we use the `NDCGridRaysampler` which follows the standard PyTorch3D coordinate grid convention (+X from right to left; +Y from bottom to top; +Z away from the user).\n",
"- The *raymarcher* takes the densities and colors sampled along each ray and renders each ray into a color and an opacity value of the ray's source pixel. Here we use the `EmissionAbsorptionRaymarcher` which implements the standard Emission-Absorption raymarching algorithm." "- The *raymarcher* takes the densities and colors sampled along each ray and renders each ray into a color and an opacity value of the ray's source pixel. Here we use the `EmissionAbsorptionRaymarcher` which implements the standard Emission-Absorption raymarching algorithm."
] ]
}, },
@ -161,11 +161,11 @@
"\n", "\n",
"# 1) Instantiate the raysampler.\n", "# 1) Instantiate the raysampler.\n",
"# Here, NDCGridRaysampler generates a rectangular image\n", "# Here, NDCGridRaysampler generates a rectangular image\n",
"# grid of rays whose coordinates follow the pytorch3d\n", "# grid of rays whose coordinates follow the PyTorch3D\n",
"# coordinate conventions.\n", "# coordinate conventions.\n",
"# Since we use a volume of size 128^3, we sample n_pts_per_ray=150,\n", "# Since we use a volume of size 128^3, we sample n_pts_per_ray=150,\n",
"# which roughly corresponds to a one ray-point per voxel.\n", "# which roughly corresponds to a one ray-point per voxel.\n",
"# We futher set the min_depth=0.1 since there is no surface within\n", "# We further set the min_depth=0.1 since there is no surface within\n",
"# 0.1 units of any camera plane.\n", "# 0.1 units of any camera plane.\n",
"raysampler = NDCGridRaysampler(\n", "raysampler = NDCGridRaysampler(\n",
" image_width=render_size,\n", " image_width=render_size,\n",
@ -334,7 +334,7 @@
" batch_cameras\n", " batch_cameras\n",
" ).split([3, 1], dim=-1)\n", " ).split([3, 1], dim=-1)\n",
" \n", " \n",
" # Compute the silhoutte error as the mean huber\n", " # Compute the silhouette error as the mean huber\n",
" # loss between the predicted masks and the\n", " # loss between the predicted masks and the\n",
" # target silhouettes.\n", " # target silhouettes.\n",
" sil_err = huber(\n", " sil_err = huber(\n",

View File

@ -157,7 +157,7 @@
"source": [ "source": [
"## Create a renderer\n", "## Create a renderer\n",
"\n", "\n",
"A renderer in PyTorch3D is composed of a **rasterizer** and a **shader** which each have a number of subcomponents such as a **camera** (orthgraphic/perspective). Here we initialize some of these components and use default values for the rest.\n", "A renderer in PyTorch3D is composed of a **rasterizer** and a **shader** which each have a number of subcomponents such as a **camera** (orthographic/perspective). Here we initialize some of these components and use default values for the rest.\n",
"\n", "\n",
"In this example we will first create a **renderer** which uses an **orthographic camera**, and applies **alpha compositing**. Then we learn how to vary different components using the modular API. \n", "In this example we will first create a **renderer** which uses an **orthographic camera**, and applies **alpha compositing**. Then we learn how to vary different components using the modular API. \n",
"\n", "\n",

View File

@ -277,7 +277,7 @@
"\n", "\n",
"**Meshes** is a unique datastructure provided in PyTorch3D for working with batches of meshes of different sizes.\n", "**Meshes** is a unique datastructure provided in PyTorch3D for working with batches of meshes of different sizes.\n",
"\n", "\n",
"**TexturesUV** is an auxillary datastructure for storing vertex uv and texture maps for meshes." "**TexturesUV** is an auxiliary datastructure for storing vertex uv and texture maps for meshes."
] ]
}, },
{ {
@ -320,7 +320,7 @@
"# Place a point light in front of the person. \n", "# Place a point light in front of the person. \n",
"lights = PointLights(device=device, location=[[0.0, 0.0, 2.0]])\n", "lights = PointLights(device=device, location=[[0.0, 0.0, 2.0]])\n",
"\n", "\n",
"# Create a phong renderer by composing a rasterizer and a shader. The textured phong shader will \n", "# Create a Phong renderer by composing a rasterizer and a shader. The textured Phong shader will \n",
"# interpolate the texture uv coordinates for each vertex, sample from a texture image and \n", "# interpolate the texture uv coordinates for each vertex, sample from a texture image and \n",
"# apply the Phong lighting model\n", "# apply the Phong lighting model\n",
"renderer = MeshRenderer(\n", "renderer = MeshRenderer(\n",

View File

@ -191,11 +191,11 @@
"source": [ "source": [
"### 1. Load a mesh and texture file\n", "### 1. Load a mesh and texture file\n",
"\n", "\n",
"Load an `.obj` file and it's associated `.mtl` file and create a **Textures** and **Meshes** object. \n", "Load an `.obj` file and its associated `.mtl` file and create a **Textures** and **Meshes** object. \n",
"\n", "\n",
"**Meshes** is a unique datastructure provided in PyTorch3D for working with batches of meshes of different sizes. \n", "**Meshes** is a unique datastructure provided in PyTorch3D for working with batches of meshes of different sizes. \n",
"\n", "\n",
"**TexturesUV** is an auxillary datastructure for storing vertex uv and texture maps for meshes. \n", "**TexturesUV** is an auxiliary datastructure for storing vertex uv and texture maps for meshes. \n",
"\n", "\n",
"**Meshes** has several class methods which are used throughout the rendering pipeline." "**Meshes** has several class methods which are used throughout the rendering pipeline."
] ]
@ -317,7 +317,7 @@
"\n", "\n",
"A renderer in PyTorch3D is composed of a **rasterizer** and a **shader** which each have a number of subcomponents such as a **camera** (orthographic/perspective). Here we initialize some of these components and use default values for the rest.\n", "A renderer in PyTorch3D is composed of a **rasterizer** and a **shader** which each have a number of subcomponents such as a **camera** (orthographic/perspective). Here we initialize some of these components and use default values for the rest.\n",
"\n", "\n",
"In this example we will first create a **renderer** which uses a **perspective camera**, a **point light** and applies **phong shading**. Then we learn how to vary different components using the modular API. " "In this example we will first create a **renderer** which uses a **perspective camera**, a **point light** and applies **Phong shading**. Then we learn how to vary different components using the modular API. "
] ]
}, },
{ {
@ -352,7 +352,7 @@
"# -z direction. \n", "# -z direction. \n",
"lights = PointLights(device=device, location=[[0.0, 0.0, -3.0]])\n", "lights = PointLights(device=device, location=[[0.0, 0.0, -3.0]])\n",
"\n", "\n",
"# Create a phong renderer by composing a rasterizer and a shader. The textured phong shader will \n", "# Create a Phong renderer by composing a rasterizer and a shader. The textured Phong shader will \n",
"# interpolate the texture uv coordinates for each vertex, sample from a texture image and \n", "# interpolate the texture uv coordinates for each vertex, sample from a texture image and \n",
"# apply the Phong lighting model\n", "# apply the Phong lighting model\n",
"renderer = MeshRenderer(\n", "renderer = MeshRenderer(\n",
@ -418,7 +418,7 @@
"source": [ "source": [
"## 4. Move the light behind the object and re-render\n", "## 4. Move the light behind the object and re-render\n",
"\n", "\n",
"We can pass arbirary keyword arguments to the `rasterizer`/`shader` via the call to the `renderer` so the renderer does not need to be reinitialized if any of the settings change/\n", "We can pass arbitrary keyword arguments to the `rasterizer`/`shader` via the call to the `renderer` so the renderer does not need to be reinitialized if any of the settings change/\n",
"\n", "\n",
"In this case, we can simply update the location of the lights and pass them into the call to the renderer. \n", "In this case, we can simply update the location of the lights and pass them into the call to the renderer. \n",
"\n", "\n",
@ -579,7 +579,7 @@
}, },
"outputs": [], "outputs": [],
"source": [ "source": [
"# We can pass arbirary keyword arguments to the rasterizer/shader via the renderer\n", "# We can pass arbitrary keyword arguments to the rasterizer/shader via the renderer\n",
"# so the renderer does not need to be reinitialized if any of the settings change.\n", "# so the renderer does not need to be reinitialized if any of the settings change.\n",
"images = renderer(meshes, cameras=cameras, lights=lights)" "images = renderer(meshes, cameras=cameras, lights=lights)"
] ]

View File

@ -113,15 +113,15 @@ def generate_cow_renders(
# purposes only we will set faces_per_pixel=1 and blur_radius=0.0. Refer to # purposes only we will set faces_per_pixel=1 and blur_radius=0.0. Refer to
# rasterize_meshes.py for explanations of these parameters. We also leave # rasterize_meshes.py for explanations of these parameters. We also leave
# bin_size and max_faces_per_bin to their default values of None, which sets # bin_size and max_faces_per_bin to their default values of None, which sets
# their values using huristics and ensures that the faster coarse-to-fine # their values using heuristics and ensures that the faster coarse-to-fine
# rasterization method is used. Refer to docs/notes/renderer.md for an # rasterization method is used. Refer to docs/notes/renderer.md for an
# explanation of the difference between naive and coarse-to-fine rasterization. # explanation of the difference between naive and coarse-to-fine rasterization.
raster_settings = RasterizationSettings( raster_settings = RasterizationSettings(
image_size=128, blur_radius=0.0, faces_per_pixel=1 image_size=128, blur_radius=0.0, faces_per_pixel=1
) )
# Create a phong renderer by composing a rasterizer and a shader. The textured # Create a Phong renderer by composing a rasterizer and a shader. The textured
# phong shader will interpolate the texture uv coordinates for each vertex, # Phong shader will interpolate the texture uv coordinates for each vertex,
# sample from a texture image and apply the Phong lighting model # sample from a texture image and apply the Phong lighting model
blend_params = BlendParams(sigma=1e-4, gamma=1e-4, background_color=(0.0, 0.0, 0.0)) blend_params = BlendParams(sigma=1e-4, gamma=1e-4, background_color=(0.0, 0.0, 0.0))
renderer = MeshRenderer( renderer = MeshRenderer(

View File

@ -50,7 +50,7 @@ python ./test_nerf.py --config-name lego
``` ```
Will load a trained model from the `./checkpoints` directory and evaluate it on the test split of the corresponding dataset (Lego in the case above). Will load a trained model from the `./checkpoints` directory and evaluate it on the test split of the corresponding dataset (Lego in the case above).
### Exporting multi-view video of the radience field ### Exporting multi-view video of the radiance field
Furthermore, the codebase supports generating videos of the neural radiance field. Furthermore, the codebase supports generating videos of the neural radiance field.
The following generates a turntable video of the Lego scene: The following generates a turntable video of the Lego scene:
``` ```

View File

@ -77,7 +77,7 @@ def generate_eval_video_cameras(
cam_centers_c = cam_centers - plane_mean[None] cam_centers_c = cam_centers - plane_mean[None]
if up is not None: if up is not None:
# us the up vector instad of the plane through the camera centers # us the up vector instead of the plane through the camera centers
plane_normal = torch.FloatTensor(up) plane_normal = torch.FloatTensor(up)
else: else:
cov = (cam_centers_c.t() @ cam_centers_c) / cam_centers_c.shape[0] cov = (cam_centers_c.t() @ cam_centers_c) / cam_centers_c.shape[0]
@ -99,7 +99,7 @@ def generate_eval_video_cameras(
traj = traj @ e_vec.t() + plane_mean[None] traj = traj @ e_vec.t() + plane_mean[None]
else: else:
raise ValueError(f"Uknown trajectory_type {trajectory_type}.") raise ValueError(f"Unknown trajectory_type {trajectory_type}.")
# point all cameras towards the center of the scene # point all cameras towards the center of the scene
R, T = look_at_view_transform( R, T = look_at_view_transform(

View File

@ -42,7 +42,7 @@ class HarmonicEmbedding(torch.nn.Module):
)` )`
Note that `x` is also premultiplied by the base frequency `omega0` Note that `x` is also premultiplied by the base frequency `omega0`
before evaluting the harmonic functions. before evaluating the harmonic functions.
""" """
super().__init__() super().__init__()

View File

@ -169,7 +169,7 @@ class NeuralRadianceField(torch.nn.Module):
Returns: Returns:
rays_densities: A tensor of shape `(minibatch, ..., num_points_per_ray, 1)` rays_densities: A tensor of shape `(minibatch, ..., num_points_per_ray, 1)`
denoting the opacitiy of each ray point. denoting the opacity of each ray point.
rays_colors: A tensor of shape `(minibatch, ..., num_points_per_ray, 3)` rays_colors: A tensor of shape `(minibatch, ..., num_points_per_ray, 3)`
denoting the color of each ray point. denoting the color of each ray point.
""" """

View File

@ -266,7 +266,7 @@ class RadianceFieldRenderer(torch.nn.Module):
image: torch.Tensor, image: torch.Tensor,
) -> Tuple[dict, dict]: ) -> Tuple[dict, dict]:
""" """
Performs the coarse and fine rendering passees of the radiance field Performs the coarse and fine rendering passes of the radiance field
from the viewpoint of the input `camera`. from the viewpoint of the input `camera`.
Afterwards, both renders are compared to the input ground truth `image` Afterwards, both renders are compared to the input ground truth `image`
by evaluating the peak signal-to-noise ratio and the mean-squared error. by evaluating the peak signal-to-noise ratio and the mean-squared error.

View File

@ -36,7 +36,7 @@ class EmissionAbsorptionNeRFRaymarcher(EmissionAbsorptionRaymarcher):
rays_features: Per-ray feature values represented with a tensor rays_features: Per-ray feature values represented with a tensor
of shape `(..., n_points_per_ray, feature_dim)`. of shape `(..., n_points_per_ray, feature_dim)`.
eps: A lower bound added to `rays_densities` before computing eps: A lower bound added to `rays_densities` before computing
the absorbtion function (cumprod of `1-rays_densities` along the absorption function (cumprod of `1-rays_densities` along
each ray). This prevents the cumprod to yield exact 0 each ray). This prevents the cumprod to yield exact 0
which would inhibit any gradient-based learning. which would inhibit any gradient-based learning.
@ -44,7 +44,7 @@ class EmissionAbsorptionNeRFRaymarcher(EmissionAbsorptionRaymarcher):
features: A tensor of shape `(..., feature_dim)` containing features: A tensor of shape `(..., feature_dim)` containing
the rendered features for each ray. the rendered features for each ray.
weights: A tensor of shape `(..., n_points_per_ray)` containing weights: A tensor of shape `(..., n_points_per_ray)` containing
the ray-specific emission-absorbtion distribution. the ray-specific emission-absorption distribution.
Each ray distribution `(..., :)` is a valid probability Each ray distribution `(..., :)` is a valid probability
distribution, i.e. it contains non-negative values that integrate distribution, i.e. it contains non-negative values that integrate
to 1, such that `weights.sum(dim=-1)==1).all()` yields `True`. to 1, such that `weights.sum(dim=-1)==1).all()` yields `True`.

View File

@ -60,7 +60,7 @@ def main(cfg: DictConfig):
print(f"Loading checkpoint {checkpoint_path}.") print(f"Loading checkpoint {checkpoint_path}.")
loaded_data = torch.load(checkpoint_path) loaded_data = torch.load(checkpoint_path)
# Do not load the cached xy grid. # Do not load the cached xy grid.
# - this allows to set an arbitrary evaluation image size. # - this allows setting an arbitrary evaluation image size.
state_dict = { state_dict = {
k: v k: v
for k, v in loaded_data["model"].items() for k, v in loaded_data["model"].items()
@ -121,7 +121,7 @@ def main(cfg: DictConfig):
test_image = test_image.to(device) test_image = test_image.to(device)
test_camera = test_camera.to(device) test_camera = test_camera.to(device)
# Activate eval mode of the model (allows to do a full rendering pass). # Activate eval mode of the model (lets us do a full rendering pass).
model.eval() model.eval()
with torch.no_grad(): with torch.no_grad():
test_nerf_out, test_metrics = model( test_nerf_out, test_metrics = model(

View File

@ -70,7 +70,7 @@ class TestRaysampler(unittest.TestCase):
def test_probabilistic_raysampler(self, batch_size=1, n_pts_per_ray=60): def test_probabilistic_raysampler(self, batch_size=1, n_pts_per_ray=60):
""" """
Check that the probabilisitc ray sampler does not crash for various Check that the probabilistic ray sampler does not crash for various
settings. settings.
""" """

View File

@ -31,7 +31,7 @@ def main(cfg: DictConfig):
else: else:
warnings.warn( warnings.warn(
"Please note that although executing on CPU is supported," "Please note that although executing on CPU is supported,"
+ "the training is unlikely to finish in resonable time." + "the training is unlikely to finish in reasonable time."
) )
device = "cpu" device = "cpu"
@ -109,7 +109,7 @@ def main(cfg: DictConfig):
optimizer, lr_lambda, last_epoch=start_epoch - 1, verbose=False optimizer, lr_lambda, last_epoch=start_epoch - 1, verbose=False
) )
# Initialize the cache for storing variables needed for visulization. # Initialize the cache for storing variables needed for visualization.
visuals_cache = collections.deque(maxlen=cfg.visualization.history_size) visuals_cache = collections.deque(maxlen=cfg.visualization.history_size)
# Init the visualization visdom env. # Init the visualization visdom env.
@ -194,7 +194,7 @@ def main(cfg: DictConfig):
if iteration % cfg.stats_print_interval == 0: if iteration % cfg.stats_print_interval == 0:
stats.print(stat_set="train") stats.print(stat_set="train")
# Update the visualisatioon cache. # Update the visualization cache.
visuals_cache.append( visuals_cache.append(
{ {
"camera": camera.cpu(), "camera": camera.cpu(),
@ -219,7 +219,7 @@ def main(cfg: DictConfig):
val_image = val_image.to(device) val_image = val_image.to(device)
val_camera = val_camera.to(device) val_camera = val_camera.to(device)
# Activate eval mode of the model (allows to do a full rendering pass). # Activate eval mode of the model (lets us do a full rendering pass).
model.eval() model.eval()
with torch.no_grad(): with torch.no_grad():
val_nerf_out, val_metrics = model( val_nerf_out, val_metrics = model(

View File

@ -105,7 +105,7 @@ __device__ bool CheckPointOutsideBoundingBox(
// which contains Pixel structs with the indices of the faces which intersect // which contains Pixel structs with the indices of the faces which intersect
// with this pixel sorted by closest z distance. If the point pxy lies in the // with this pixel sorted by closest z distance. If the point pxy lies in the
// face, the list (q) is updated and re-orderered in place. In addition // face, the list (q) is updated and re-orderered in place. In addition
// the auxillary variables q_size, q_max_z and q_max_idx are also modified. // the auxiliary variables q_size, q_max_z and q_max_idx are also modified.
// This code is shared between RasterizeMeshesNaiveCudaKernel and // This code is shared between RasterizeMeshesNaiveCudaKernel and
// RasterizeMeshesFineCudaKernel. // RasterizeMeshesFineCudaKernel.
template <typename FaceQ> template <typename FaceQ>
@ -275,7 +275,7 @@ __global__ void RasterizeMeshesNaiveCudaKernel(
const int yi = H - 1 - pix_idx / W; const int yi = H - 1 - pix_idx / W;
const int xi = W - 1 - pix_idx % W; const int xi = W - 1 - pix_idx % W;
// screen coordinates to ndc coordiantes of pixel. // screen coordinates to ndc coordinates of pixel.
const float xf = PixToNonSquareNdc(xi, W, H); const float xf = PixToNonSquareNdc(xi, W, H);
const float yf = PixToNonSquareNdc(yi, H, W); const float yf = PixToNonSquareNdc(yi, H, W);
const float2 pxy = make_float2(xf, yf); const float2 pxy = make_float2(xf, yf);

View File

@ -27,7 +27,7 @@ __device__ inline bool operator<(const Pix& a, const Pix& b) {
// which contains Pixel structs with the indices of the points which intersect // which contains Pixel structs with the indices of the points which intersect
// with this pixel sorted by closest z distance. If the pixel pxy lies in the // with this pixel sorted by closest z distance. If the pixel pxy lies in the
// point, the list (q) is updated and re-orderered in place. In addition // point, the list (q) is updated and re-orderered in place. In addition
// the auxillary variables q_size, q_max_z and q_max_idx are also modified. // the auxiliary variables q_size, q_max_z and q_max_idx are also modified.
// This code is shared between RasterizePointsNaiveCudaKernel and // This code is shared between RasterizePointsNaiveCudaKernel and
// RasterizePointsFineCudaKernel. // RasterizePointsFineCudaKernel.
template <typename PointQ> template <typename PointQ>
@ -104,7 +104,7 @@ __global__ void RasterizePointsNaiveCudaKernel(
const int yi = H - 1 - pix_idx / W; const int yi = H - 1 - pix_idx / W;
const int xi = W - 1 - pix_idx % W; const int xi = W - 1 - pix_idx % W;
// screen coordinates to ndc coordiantes of pixel. // screen coordinates to ndc coordinates of pixel.
const float xf = PixToNonSquareNdc(xi, W, H); const float xf = PixToNonSquareNdc(xi, W, H);
const float yf = PixToNonSquareNdc(yi, H, W); const float yf = PixToNonSquareNdc(yi, H, W);

View File

@ -224,7 +224,7 @@ BarycentricPerspectiveCorrectionBackward(
// Clip negative barycentric coordinates to 0.0 and renormalize so // Clip negative barycentric coordinates to 0.0 and renormalize so
// the barycentric coordinates for a point sum to 1. When the blur_radius // the barycentric coordinates for a point sum to 1. When the blur_radius
// is greater than 0, a face will still be recorded as overlapping a pixel // is greater than 0, a face will still be recorded as overlapping a pixel
// if the pixel is outisde the face. In this case at least one of the // if the pixel is outside the face. In this case at least one of the
// barycentric coordinates for the pixel relative to the face will be negative. // barycentric coordinates for the pixel relative to the face will be negative.
// Clipping will ensure that the texture and z buffer are interpolated // Clipping will ensure that the texture and z buffer are interpolated
// correctly. // correctly.

View File

@ -245,7 +245,7 @@ inline std::tuple<vec3<T>, T, T, T> BarycentricPerspectiveCorrectionBackward(
// Clip negative barycentric coordinates to 0.0 and renormalize so // Clip negative barycentric coordinates to 0.0 and renormalize so
// the barycentric coordinates for a point sum to 1. When the blur_radius // the barycentric coordinates for a point sum to 1. When the blur_radius
// is greater than 0, a face will still be recorded as overlapping a pixel // is greater than 0, a face will still be recorded as overlapping a pixel
// if the pixel is outisde the face. In this case at least one of the // if the pixel is outside the face. In this case at least one of the
// barycentric coordinates for the pixel relative to the face will be negative. // barycentric coordinates for the pixel relative to the face will be negative.
// Clipping will ensure that the texture and z buffer are interpolated // Clipping will ensure that the texture and z buffer are interpolated
// correctly. // correctly.

View File

@ -99,7 +99,7 @@ class R2N2(ShapeNetBase):
path.join(SYNSET_DICT_DIR, "r2n2_synset_dict.json"), "r" path.join(SYNSET_DICT_DIR, "r2n2_synset_dict.json"), "r"
) as read_dict: ) as read_dict:
self.synset_dict = json.load(read_dict) self.synset_dict = json.load(read_dict)
# Inverse dicitonary mapping synset labels to corresponding offsets. # Inverse dictionary mapping synset labels to corresponding offsets.
self.synset_inv = {label: offset for offset, label in self.synset_dict.items()} self.synset_inv = {label: offset for offset, label in self.synset_dict.items()}
# Store synset and model ids of objects mentioned in the splits_file. # Store synset and model ids of objects mentioned in the splits_file.
@ -383,7 +383,7 @@ class R2N2(ShapeNetBase):
view_idxs: each model will be rendered with the orientation(s) of the specified view_idxs: each model will be rendered with the orientation(s) of the specified
views. Only render by view_idxs if no camera or args for BlenderCamera is views. Only render by view_idxs if no camera or args for BlenderCamera is
supplied. supplied.
Accepts any of the args of the render function in ShapnetBase: Accepts any of the args of the render function in ShapeNetBase:
model_ids: List[str] of model_ids of models intended to be rendered. model_ids: List[str] of model_ids of models intended to be rendered.
categories: List[str] of categories intended to be rendered. categories categories: List[str] of categories intended to be rendered. categories
and sample_nums must be specified at the same time. categories can be given and sample_nums must be specified at the same time. categories can be given

View File

@ -97,8 +97,8 @@ def compute_extrinsic_matrix(azimuth, elevation, distance):
Copied from meshrcnn codebase: Copied from meshrcnn codebase:
https://github.com/facebookresearch/meshrcnn/blob/master/shapenet/utils/coords.py#L96 https://github.com/facebookresearch/meshrcnn/blob/master/shapenet/utils/coords.py#L96
Compute 4x4 extrinsic matrix that converts from homogenous world coordinates Compute 4x4 extrinsic matrix that converts from homogeneous world coordinates
to homogenous camera coordinates. We assume that the camera is looking at the to homogeneous camera coordinates. We assume that the camera is looking at the
origin. origin.
Used in R2N2 Dataset when computing calibration matrices. Used in R2N2 Dataset when computing calibration matrices.
@ -189,7 +189,7 @@ def _compute_idxs(vals, counts):
Args: Args:
vals: tensor of binary values indicating voxel presence in a dense format. vals: tensor of binary values indicating voxel presence in a dense format.
counts: tensor of number of occurence of each value in vals. counts: tensor of number of occurrence of each value in vals.
Returns: Returns:
idxs: A tensor of shape (N), where N is the number of nonzero voxels. idxs: A tensor of shape (N), where N is the number of nonzero voxels.
@ -379,7 +379,7 @@ def project_verts(verts, P, eps=1e-1):
Copied from meshrcnn codebase: Copied from meshrcnn codebase:
https://github.com/facebookresearch/meshrcnn/blob/master/shapenet/utils/coords.py#L159 https://github.com/facebookresearch/meshrcnn/blob/master/shapenet/utils/coords.py#L159
Project verticies using a 4x4 transformation matrix. Project vertices using a 4x4 transformation matrix.
Args: Args:
verts: FloatTensor of shape (N, V, 3) giving a batch of vertex positions or of verts: FloatTensor of shape (N, V, 3) giving a batch of vertex positions or of
@ -403,7 +403,7 @@ def project_verts(verts, P, eps=1e-1):
# Add an extra row of ones to the world-space coordinates of verts before # Add an extra row of ones to the world-space coordinates of verts before
# multiplying by the projection matrix. We could avoid this allocation by # multiplying by the projection matrix. We could avoid this allocation by
# instead multiplying by a 4x3 submatrix of the projectio matrix, then # instead multiplying by a 4x3 submatrix of the projection matrix, then
# adding the remaining 4x1 vector. Not sure whether there will be much # adding the remaining 4x1 vector. Not sure whether there will be much
# performance difference between the two. # performance difference between the two.
ones = torch.ones(N, V, 1, dtype=dtype, device=device) ones = torch.ones(N, V, 1, dtype=dtype, device=device)

View File

@ -37,7 +37,7 @@ class ShapeNetCore(ShapeNetBase):
synset offsets or labels. A combination of both is also accepted. synset offsets or labels. A combination of both is also accepted.
When no category is specified, all categories in data_dir are loaded. When no category is specified, all categories in data_dir are loaded.
version: (int) version of ShapeNetCore data in data_dir, 1 or 2. version: (int) version of ShapeNetCore data in data_dir, 1 or 2.
Default is set to be 1. Version 1 has 57 categories and verions 2 has 55 Default is set to be 1. Version 1 has 57 categories and version 2 has 55
categories. categories.
Note: version 1 has two categories 02858304(boat) and 02992529(cellphone) Note: version 1 has two categories 02858304(boat) and 02992529(cellphone)
that are hyponyms of categories 04530566(watercraft) and 04401088(telephone) that are hyponyms of categories 04530566(watercraft) and 04401088(telephone)
@ -63,7 +63,7 @@ class ShapeNetCore(ShapeNetBase):
dict_file = "shapenet_synset_dict_v%d.json" % version dict_file = "shapenet_synset_dict_v%d.json" % version
with open(path.join(SYNSET_DICT_DIR, dict_file), "r") as read_dict: with open(path.join(SYNSET_DICT_DIR, dict_file), "r") as read_dict:
self.synset_dict = json.load(read_dict) self.synset_dict = json.load(read_dict)
# Inverse dicitonary mapping synset labels to corresponding offsets. # Inverse dictionary mapping synset labels to corresponding offsets.
self.synset_inv = {label: offset for offset, label in self.synset_dict.items()} self.synset_inv = {label: offset for offset, label in self.synset_dict.items()}
# If categories are specified, check if each category is in the form of either # If categories are specified, check if each category is in the form of either

View File

@ -250,7 +250,7 @@ class ShapeNetBase(torch.utils.data.Dataset):
Helper function for sampling a number of indices from the given category. Helper function for sampling a number of indices from the given category.
Args: Args:
sample_num: number of indicies to be sampled from the given category. sample_num: number of indices to be sampled from the given category.
category: category synset of the category to be sampled from. If not category: category synset of the category to be sampled from. If not
specified, sample from all models in the loaded dataset. specified, sample from all models in the loaded dataset.
""" """

View File

@ -28,7 +28,7 @@ def make_mesh_texture_atlas(
Args: Args:
material_properties: dict of properties for each material. If a material material_properties: dict of properties for each material. If a material
does not have any properties it will have an emtpy dict. does not have any properties it will have an empty dict.
texture_images: dict of material names and texture images texture_images: dict of material names and texture images
face_material_names: numpy array of the material name corresponding to each face_material_names: numpy array of the material name corresponding to each
face. Faces which don't have an associated material will be an empty string. face. Faces which don't have an associated material will be an empty string.
@ -220,13 +220,13 @@ def make_material_atlas(
For each grid cell we can now calculate the centroid `(c_y, c_x)` For each grid cell we can now calculate the centroid `(c_y, c_x)`
of the corresponding texture triangle: of the corresponding texture triangle:
- if `(x + y) < R`, then offsett the centroid of - if `(x + y) < R`, then offset the centroid of
triangle 0 by `(y, x) * (1/R)` triangle 0 by `(y, x) * (1/R)`
- if `(x + y) > R`, then offset the centroid of - if `(x + y) > R`, then offset the centroid of
triangle 8 by `((R-1-y), (R-1-x)) * (1/R)`. triangle 8 by `((R-1-y), (R-1-x)) * (1/R)`.
This is equivalent to updating the portion of Grid 1 This is equivalent to updating the portion of Grid 1
above the diagnonal, replacing `(y, x)` with `((R-1-y), (R-1-x))`: above the diagonal, replacing `(y, x)` with `((R-1-y), (R-1-x))`:
..code-block::python ..code-block::python

View File

@ -109,13 +109,13 @@ def load_obj(
Faces are interpreted as follows: Faces are interpreted as follows:
:: ::
5/2/1 describes the first vertex of the first triange 5/2/1 describes the first vertex of the first triangle
- 5: index of vertex [1.000000 1.000000 -1.000000] - 5: index of vertex [1.000000 1.000000 -1.000000]
- 2: index of texture coordinate [0.749279 0.501284] - 2: index of texture coordinate [0.749279 0.501284]
- 1: index of normal [0.000000 0.000000 -1.000000] - 1: index of normal [0.000000 0.000000 -1.000000]
If there are faces with more than 3 vertices If there are faces with more than 3 vertices
they are subdivided into triangles. Polygonal faces are assummed to have they are subdivided into triangles. Polygonal faces are assumed to have
vertices ordered counter-clockwise so the (right-handed) normal points vertices ordered counter-clockwise so the (right-handed) normal points
out of the screen e.g. a proper rectangular face would be specified like this: out of the screen e.g. a proper rectangular face would be specified like this:
:: ::
@ -368,7 +368,7 @@ def _parse_face(
face_normals.append(int(vert_props[2])) face_normals.append(int(vert_props[2]))
if len(vert_props) > 3: if len(vert_props) > 3:
raise ValueError( raise ValueError(
"Face vertices can ony have 3 properties. \ "Face vertices can only have 3 properties. \
Face vert %s, Line: %s" Face vert %s, Line: %s"
% (str(vert_props), str(line)) % (str(vert_props), str(line))
) )

View File

@ -33,7 +33,7 @@ and to save a point cloud you might do
``` ```
pcl = Pointclouds(...) pcl = Pointclouds(...)
IO().save_pointcloud(pcl, "output_poincloud.obj") IO().save_pointcloud(pcl, "output_pointcloud.obj")
``` ```
""" """
@ -43,7 +43,7 @@ class IO:
""" """
This class is the interface to flexible loading and saving of meshes and point clouds. This class is the interface to flexible loading and saving of meshes and point clouds.
In simple cases the user will just initialise an instance of this class as `IO()` In simple cases the user will just initialize an instance of this class as `IO()`
and then use its load and save functions. The arguments of the initializer are not and then use its load and save functions. The arguments of the initializer are not
usually needed. usually needed.
@ -53,7 +53,7 @@ class IO:
Args: Args:
include_default_formats: If False, the built-in file formats will not be available. include_default_formats: If False, the built-in file formats will not be available.
Then only user-registered formats can be used. Then only user-registered formats can be used.
path_manager: Used to customise how paths given as strings are interpreted. path_manager: Used to customize how paths given as strings are interpreted.
""" """
def __init__( def __init__(

View File

@ -380,7 +380,7 @@ def _try_read_ply_constant_list_ascii(f, definition: _PlyElementType):
return data[:, 1:] return data[:, 1:]
def _parse_heterogenous_property_ascii(datum, line_iter, property: _Property): def _parse_heterogeneous_property_ascii(datum, line_iter, property: _Property):
""" """
Read a general data property from an ascii .ply file. Read a general data property from an ascii .ply file.
@ -431,7 +431,7 @@ def _read_ply_element_ascii(f, definition: _PlyElementType):
In simple cases where every element has the same size, 2D numpy array In simple cases where every element has the same size, 2D numpy array
corresponding to the data. The rows are the different values. corresponding to the data. The rows are the different values.
Otherwise a list of lists of values, where the outer list is Otherwise a list of lists of values, where the outer list is
each occurence of the element, and the inner lists have one value per each occurrence of the element, and the inner lists have one value per
property. property.
""" """
if not definition.count: if not definition.count:
@ -454,7 +454,7 @@ def _read_ply_element_ascii(f, definition: _PlyElementType):
datum = [] datum = []
line_iter = iter(line_string.strip().split()) line_iter = iter(line_string.strip().split())
for property in definition.properties: for property in definition.properties:
_parse_heterogenous_property_ascii(datum, line_iter, property) _parse_heterogeneous_property_ascii(datum, line_iter, property)
data.append(datum) data.append(datum)
if next(line_iter, None) is not None: if next(line_iter, None) is not None:
raise ValueError("Too much data for an element.") raise ValueError("Too much data for an element.")
@ -669,7 +669,7 @@ def _read_ply_element_binary(f, definition: _PlyElementType, big_endian: bool) -
In simple cases where every element has the same size, 2D numpy array In simple cases where every element has the same size, 2D numpy array
corresponding to the data. The rows are the different values. corresponding to the data. The rows are the different values.
Otherwise a list of lists/tuples of values, where the outer list is Otherwise a list of lists/tuples of values, where the outer list is
each occurence of the element, and the inner lists have one value per each occurrence of the element, and the inner lists have one value per
property. property.
""" """
if not definition.count: if not definition.count:
@ -1027,7 +1027,7 @@ def _save_ply(
Args: Args:
f: File object to which the 3D data should be written. f: File object to which the 3D data should be written.
verts: FloatTensor of shape (V, 3) giving vertex coordinates. verts: FloatTensor of shape (V, 3) giving vertex coordinates.
faces: LongTensor of shsape (F, 3) giving faces. faces: LongTensor of shape (F, 3) giving faces.
verts_normals: FloatTensor of shape (V, 3) giving vertex normals. verts_normals: FloatTensor of shape (V, 3) giving vertex normals.
ascii: (bool) whether to use the ascii ply format. ascii: (bool) whether to use the ascii ply format.
decimal_places: Number of decimal places for saving if ascii=True. decimal_places: Number of decimal places for saving if ascii=True.

View File

@ -9,7 +9,7 @@ def mesh_laplacian_smoothing(meshes, method: str = "uniform"):
Computes the laplacian smoothing objective for a batch of meshes. Computes the laplacian smoothing objective for a batch of meshes.
This function supports three variants of Laplacian smoothing, This function supports three variants of Laplacian smoothing,
namely with uniform weights("uniform"), with cotangent weights ("cot"), namely with uniform weights("uniform"), with cotangent weights ("cot"),
and cotangent cuvature ("cotcurv").For more details read [1, 2]. and cotangent curvature ("cotcurv").For more details read [1, 2].
Args: Args:
meshes: Meshes object with a batch of meshes. meshes: Meshes object with a batch of meshes.

View File

@ -91,7 +91,7 @@ class _FacePointDistance(Function):
max_tris: Scalar equal to maximum number of faces in the batch max_tris: Scalar equal to maximum number of faces in the batch
Returns: Returns:
dists: FloatTensor of shape `(T,)`, where `dists[t]` is the squared dists: FloatTensor of shape `(T,)`, where `dists[t]` is the squared
euclidean distance of `t`-th trianguar face to the closest point in the euclidean distance of `t`-th triangular face to the closest point in the
corresponding example in the batch corresponding example in the batch
idxs: LongTensor of shape `(T,)` indicating the closest point in the idxs: LongTensor of shape `(T,)` indicating the closest point in the
corresponding example in the batch. corresponding example in the batch.

View File

@ -21,7 +21,7 @@ def interpolate_face_attributes(
pixel in the image. A value < 0 indicates that the pixel does not pixel in the image. A value < 0 indicates that the pixel does not
overlap any face and should be skipped. overlap any face and should be skipped.
barycentric_coords: FloatTensor of shape (N, H, W, K, 3) specifying barycentric_coords: FloatTensor of shape (N, H, W, K, 3) specifying
the barycentric coordianates of each pixel the barycentric coordinates of each pixel
relative to the faces (in the packed relative to the faces (in the packed
representation) which overlap the pixel. representation) which overlap the pixel.
face_attributes: packed attributes of shape (total_faces, 3, D), face_attributes: packed attributes of shape (total_faces, 3, D),

View File

@ -147,7 +147,7 @@ def knn_points(
p2_nn = knn_gather(p2, p1_idx, lengths2) p2_nn = knn_gather(p2, p1_idx, lengths2)
which is a helper function that allows indexing any tensor of shape (N, P2, U) with which is a helper function that allows indexing any tensor of shape (N, P2, U) with
the indices `p1_idx` returned by `knn_points`. The outout is a tensor the indices `p1_idx` returned by `knn_points`. The output is a tensor
of shape (N, P1, K, U). of shape (N, P1, K, U).
""" """

View File

@ -184,7 +184,7 @@ def _gen_pairs(input, dim=-2, reducer=lambda a, b: ((a - b) ** 2).sum(dim=-1)):
def _kernel_vec_distances(v): def _kernel_vec_distances(v):
"""Computes the coefficients for linearisation of the quadratic system """Computes the coefficients for linearization of the quadratic system
to match all pairwise distances between 4 control points (dim=1). to match all pairwise distances between 4 control points (dim=1).
The last dimension corresponds to the coefficients for quadratic terms The last dimension corresponds to the coefficients for quadratic terms
Bij = Bi * Bj, where Bi and Bj correspond to kernel vectors. Bij = Bi * Bj, where Bi and Bj correspond to kernel vectors.

View File

@ -28,7 +28,7 @@ def estimate_pointcloud_normals(
**neighborhood_size**: The size of the neighborhood used to estimate the **neighborhood_size**: The size of the neighborhood used to estimate the
geometry around each point. geometry around each point.
**disambiguate_directions**: If `True`, uses the algorithm from [1] to **disambiguate_directions**: If `True`, uses the algorithm from [1] to
ensure sign consistency of the normals of neigboring points. ensure sign consistency of the normals of neighboring points.
Returns: Returns:
**normals**: A tensor of normals for each input point **normals**: A tensor of normals for each input point
@ -83,7 +83,7 @@ def estimate_pointcloud_local_coord_frames(
**neighborhood_size**: The size of the neighborhood used to estimate the **neighborhood_size**: The size of the neighborhood used to estimate the
geometry around each point. geometry around each point.
**disambiguate_directions**: If `True`, uses the algorithm from [1] to **disambiguate_directions**: If `True`, uses the algorithm from [1] to
ensure sign consistency of the normals of neigboring points. ensure sign consistency of the normals of neighboring points.
Returns: Returns:
**curvatures**: The three principal curvatures of each point **curvatures**: The three principal curvatures of each point

View File

@ -140,7 +140,7 @@ def add_points_features_to_volume_densities_features(
volume_features: Batch of input feature volumes of shape volume_features: Batch of input feature volumes of shape
`(minibatch, feature_dim, D, H, W)` `(minibatch, feature_dim, D, H, W)`
If set to `None`, the `volume_features` will be automatically If set to `None`, the `volume_features` will be automatically
instantiatied with a correct size and filled with 0s. instantiated with a correct size and filled with 0s.
mode: The mode of the conversion of individual points into the volume. mode: The mode of the conversion of individual points into the volume.
Set either to `nearest` or `trilinear`: Set either to `nearest` or `trilinear`:
`nearest`: Each 3D point is first rounded to the volumetric `nearest`: Each 3D point is first rounded to the volumetric
@ -310,7 +310,7 @@ def splat_points_to_volumes(
# minibatch x n_points x feature_dim -> minibatch x feature_dim x n_points # minibatch x n_points x feature_dim -> minibatch x feature_dim x n_points
points_features = points_features.permute(0, 2, 1).contiguous() points_features = points_features.permute(0, 2, 1).contiguous()
# XYZ = the upper-left volume index of the 8-neigborhood of every point # XYZ = the upper-left volume index of the 8-neighborhood of every point
# grid_sizes is of the form (minibatch, depth-height-width) # grid_sizes is of the form (minibatch, depth-height-width)
grid_sizes_xyz = grid_sizes[:, [2, 1, 0]] grid_sizes_xyz = grid_sizes[:, [2, 1, 0]]

View File

@ -25,8 +25,9 @@ def sample_points_from_meshes(
Tuple[torch.Tensor, torch.Tensor, torch.Tensor], Tuple[torch.Tensor, torch.Tensor, torch.Tensor],
]: ]:
""" """
Convert a batch of meshes to a pointcloud by uniformly sampling points on Convert a batch of meshes to a batch of pointclouds by uniformly sampling
the surface of the mesh with probability proportional to the face area. points on the surface of the mesh with probability proportional to the
face area.
Args: Args:
meshes: A Meshes object with a batch of N meshes. meshes: A Meshes object with a batch of N meshes.
@ -54,7 +55,7 @@ def sample_points_from_meshes(
.. code-block:: python .. code-block:: python
Poinclouds(samples, normals=normals, features=textures) Pointclouds(samples, normals=normals, features=textures)
""" """
if meshes.isempty(): if meshes.isempty():
raise ValueError("Meshes are empty.") raise ValueError("Meshes are empty.")
@ -71,7 +72,7 @@ def sample_points_from_meshes(
num_meshes = len(meshes) num_meshes = len(meshes)
num_valid_meshes = torch.sum(meshes.valid) # Non empty meshes. num_valid_meshes = torch.sum(meshes.valid) # Non empty meshes.
# Intialize samples tensor with fill value 0 for empty meshes. # Initialize samples tensor with fill value 0 for empty meshes.
samples = torch.zeros((num_meshes, num_samples, 3), device=meshes.device) samples = torch.zeros((num_meshes, num_samples, 3), device=meshes.device)
# Only compute samples for non empty meshes # Only compute samples for non empty meshes
@ -104,7 +105,7 @@ def sample_points_from_meshes(
samples[meshes.valid] = w0[:, :, None] * a + w1[:, :, None] * b + w2[:, :, None] * c samples[meshes.valid] = w0[:, :, None] * a + w1[:, :, None] * b + w2[:, :, None] * c
if return_normals: if return_normals:
# Intialize normals tensor with fill value 0 for empty meshes. # Initialize normals tensor with fill value 0 for empty meshes.
# Normals for the sampled points are face normals computed from # Normals for the sampled points are face normals computed from
# the vertices of the face in which the sampled point lies. # the vertices of the face in which the sampled point lies.
normals = torch.zeros((num_meshes, num_samples, 3), device=meshes.device) normals = torch.zeros((num_meshes, num_samples, 3), device=meshes.device)

View File

@ -27,7 +27,7 @@ def wmean(
the last (spatial) dimension are assumed same; the last (spatial) dimension are assumed same;
dim: dimension(s) in `x` to average over; dim: dimension(s) in `x` to average over;
keepdim: tells whether to keep the resulting singleton dimension. keepdim: tells whether to keep the resulting singleton dimension.
eps: minumum clamping value in the denominator. eps: minimum clamping value in the denominator.
Returns: Returns:
the mean tensor: the mean tensor:
* if `weights` is None => `mean(x, dim)`, * if `weights` is None => `mean(x, dim)`,

View File

@ -15,7 +15,7 @@ def vert_align(
) -> torch.Tensor: ) -> torch.Tensor:
""" """
Sample vertex features from a feature map. This operation is called Sample vertex features from a feature map. This operation is called
"perceptual feaure pooling" in [1] or "vert align" in [2]. "perceptual feature pooling" in [1] or "vert align" in [2].
[1] Wang et al, "Pixel2Mesh: Generating 3D Mesh Models from Single [1] Wang et al, "Pixel2Mesh: Generating 3D Mesh Models from Single
RGB Images", ECCV 2018. RGB Images", ECCV 2018.
@ -45,7 +45,7 @@ def vert_align(
Returns: Returns:
feats_sampled: FloatTensor of shape (N, V, C) giving sampled features for each feats_sampled: FloatTensor of shape (N, V, C) giving sampled features for each
vertex. If feats is a list, we return concatentated features in axis=2 of vertex. If feats is a list, we return concatenated features in axis=2 of
shape (N, V, sum(C_n)) where C_n = feats[n].shape[1]. shape (N, V, sum(C_n)) where C_n = feats[n].shape[1].
If return_packed = True, the features are transformed to a packed If return_packed = True, the features are transformed to a packed
representation of shape (sum(V), C) representation of shape (sum(V), C)

View File

@ -30,7 +30,7 @@ class CamerasBase(TensorProperties):
The transformation from world -> view happens after applying a rotation (R) The transformation from world -> view happens after applying a rotation (R)
and translation (T) and translation (T)
- NDC coordinate system: This is the normalized coordinate system that confines - NDC coordinate system: This is the normalized coordinate system that confines
in a volume the renderered part of the object or scene. Also known as view volume. in a volume the rendered part of the object or scene. Also known as view volume.
Given the PyTorch3D convention, (+1, +1, znear) is the top left near corner, Given the PyTorch3D convention, (+1, +1, znear) is the top left near corner,
and (-1, -1, zfar) is the bottom right far corner of the volume. and (-1, -1, zfar) is the bottom right far corner of the volume.
The transformation from view -> NDC happens after applying the camera The transformation from view -> NDC happens after applying the camera
@ -78,7 +78,7 @@ class CamerasBase(TensorProperties):
def unproject_points(self): def unproject_points(self):
""" """
Transform input points from NDC coodinates Transform input points from NDC coordinates
to the world / camera coordinates. to the world / camera coordinates.
Each of the input points `xy_depth` of shape (..., 3) is Each of the input points `xy_depth` of shape (..., 3) is
@ -210,7 +210,7 @@ class CamerasBase(TensorProperties):
For `CamerasBase.transform_points`, setting `eps > 0` For `CamerasBase.transform_points`, setting `eps > 0`
stabilizes gradients since it leads to avoiding division stabilizes gradients since it leads to avoiding division
by excessivelly low numbers for points close to the by excessively low numbers for points close to the
camera plane. camera plane.
Returns Returns
@ -235,7 +235,7 @@ class CamerasBase(TensorProperties):
For `CamerasBase.transform_points`, setting `eps > 0` For `CamerasBase.transform_points`, setting `eps > 0`
stabilizes gradients since it leads to avoiding division stabilizes gradients since it leads to avoiding division
by excessivelly low numbers for points close to the by excessively low numbers for points close to the
camera plane. camera plane.
Returns Returns
@ -318,7 +318,7 @@ def OpenGLPerspectiveCameras(
class FoVPerspectiveCameras(CamerasBase): class FoVPerspectiveCameras(CamerasBase):
""" """
A class which stores a batch of parameters to generate a batch of A class which stores a batch of parameters to generate a batch of
projection matrices by specifiying the field of view. projection matrices by specifying the field of view.
The definition of the parameters follow the OpenGL perspective camera. The definition of the parameters follow the OpenGL perspective camera.
The extrinsics of the camera (R and T matrices) can also be set in the The extrinsics of the camera (R and T matrices) can also be set in the
@ -405,7 +405,7 @@ class FoVPerspectiveCameras(CamerasBase):
degrees: bool, set to True if fov is specified in degrees. degrees: bool, set to True if fov is specified in degrees.
Returns: Returns:
torch.floatTensor of the calibration matrix with shape (N, 4, 4) torch.FloatTensor of the calibration matrix with shape (N, 4, 4)
""" """
K = torch.zeros((self._N, 4, 4), device=self.device, dtype=torch.float32) K = torch.zeros((self._N, 4, 4), device=self.device, dtype=torch.float32)
ones = torch.ones((self._N), dtype=torch.float32, device=self.device) ones = torch.ones((self._N), dtype=torch.float32, device=self.device)
@ -421,7 +421,7 @@ class FoVPerspectiveCameras(CamerasBase):
min_x = -max_x min_x = -max_x
# NOTE: In OpenGL the projection matrix changes the handedness of the # NOTE: In OpenGL the projection matrix changes the handedness of the
# coordinate frame. i.e the NDC space postive z direction is the # coordinate frame. i.e the NDC space positive z direction is the
# camera space negative z direction. This is because the sign of the z # camera space negative z direction. This is because the sign of the z
# in the projection matrix is set to -1.0. # in the projection matrix is set to -1.0.
# In pytorch3d we maintain a right handed coordinate system throughout # In pytorch3d we maintain a right handed coordinate system throughout
@ -444,7 +444,7 @@ class FoVPerspectiveCameras(CamerasBase):
def get_projection_transform(self, **kwargs) -> Transform3d: def get_projection_transform(self, **kwargs) -> Transform3d:
""" """
Calculate the perpective projection matrix with a symmetric Calculate the perspective projection matrix with a symmetric
viewing frustrum. Use column major order. viewing frustrum. Use column major order.
The viewing frustrum will be projected into ndc, s.t. The viewing frustrum will be projected into ndc, s.t.
(max_x, max_y) -> (+1, +1) (max_x, max_y) -> (+1, +1)
@ -586,7 +586,7 @@ def OpenGLOrthographicCameras(
class FoVOrthographicCameras(CamerasBase): class FoVOrthographicCameras(CamerasBase):
""" """
A class which stores a batch of parameters to generate a batch of A class which stores a batch of parameters to generate a batch of
projection matrices by specifiying the field of view. projection matrices by specifying the field of view.
The definition of the parameters follow the OpenGL orthographic camera. The definition of the parameters follow the OpenGL orthographic camera.
""" """
@ -612,7 +612,7 @@ class FoVOrthographicCameras(CamerasBase):
max_y: maximum y coordinate of the frustrum. max_y: maximum y coordinate of the frustrum.
min_y: minimum y coordinate of the frustrum. min_y: minimum y coordinate of the frustrum.
max_x: maximum x coordinate of the frustrum. max_x: maximum x coordinate of the frustrum.
min_x: minumum x coordinage of the frustrum min_x: minimum x coordinate of the frustrum
scale_xyz: scale factors for each axis of shape (N, 3). scale_xyz: scale factors for each axis of shape (N, 3).
R: Rotation matrix of shape (N, 3, 3). R: Rotation matrix of shape (N, 3, 3).
T: Translation of shape (N, 3). T: Translation of shape (N, 3).
@ -649,7 +649,7 @@ class FoVOrthographicCameras(CamerasBase):
znear: near clipping plane of the view frustrum. znear: near clipping plane of the view frustrum.
zfar: far clipping plane of the view frustrum. zfar: far clipping plane of the view frustrum.
max_x: maximum x coordinate of the frustrum. max_x: maximum x coordinate of the frustrum.
min_x: minumum x coordinage of the frustrum min_x: minimum x coordinate of the frustrum
max_y: maximum y coordinate of the frustrum. max_y: maximum y coordinate of the frustrum.
min_y: minimum y coordinate of the frustrum. min_y: minimum y coordinate of the frustrum.
scale_xyz: scale factors for each axis of shape (N, 3). scale_xyz: scale factors for each axis of shape (N, 3).
@ -693,7 +693,7 @@ class FoVOrthographicCameras(CamerasBase):
scale_z = 2 / (far-near) scale_z = 2 / (far-near)
mid_x = (max_x + min_x) / (max_x - min_x) mid_x = (max_x + min_x) / (max_x - min_x)
mix_y = (max_y + min_y) / (max_y - min_y) mix_y = (max_y + min_y) / (max_y - min_y)
mid_z = (far + near) / (farnear) mid_z = (far + near) / (far - near)
K = [ K = [
[scale_x, 0, 0, -mid_x], [scale_x, 0, 0, -mid_x],
@ -811,7 +811,7 @@ class PerspectiveCameras(CamerasBase):
If you wish to provide parameters in screen space, you NEED to provide If you wish to provide parameters in screen space, you NEED to provide
the image_size = (imwidth, imheight). the image_size = (imwidth, imheight).
If you wish to provide parameters in NDC space, you should NOT provide If you wish to provide parameters in NDC space, you should NOT provide
image_size. Providing valid image_size will triger a screen space to image_size. Providing valid image_size will trigger a screen space to
NDC space transformation in the camera. NDC space transformation in the camera.
For example, here is how to define cameras on the two spaces. For example, here is how to define cameras on the two spaces.
@ -978,7 +978,7 @@ class OrthographicCameras(CamerasBase):
If you wish to provide parameters in screen space, you NEED to provide If you wish to provide parameters in screen space, you NEED to provide
the image_size = (imwidth, imheight). the image_size = (imwidth, imheight).
If you wish to provide parameters in NDC space, you should NOT provide If you wish to provide parameters in NDC space, you should NOT provide
image_size. Providing valid image_size will triger a screen space to image_size. Providing valid image_size will trigger a screen space to
NDC space transformation in the camera. NDC space transformation in the camera.
For example, here is how to define cameras on the two spaces. For example, here is how to define cameras on the two spaces.
@ -1120,7 +1120,7 @@ def _get_sfm_calibration_matrix(
image_size=None, image_size=None,
) -> torch.Tensor: ) -> torch.Tensor:
""" """
Returns a calibration matrix of a perspective/orthograpic camera. Returns a calibration matrix of a perspective/orthographic camera.
Args: Args:
N: Number of cameras. N: Number of cameras.
@ -1355,7 +1355,7 @@ def look_at_view_transform(
Args: Args:
dist: distance of the camera from the object dist: distance of the camera from the object
elev: angle in degres or radians. This is the angle between the elev: angle in degrees or radians. This is the angle between the
vector from the object to the camera, and the horizontal plane y = 0 (xz-plane). vector from the object to the camera, and the horizontal plane y = 0 (xz-plane).
azim: angle in degrees or radians. The vector from the object to azim: angle in degrees or radians. The vector from the object to
the camera is projected onto a horizontal plane y = 0. the camera is projected onto a horizontal plane y = 0.
@ -1365,7 +1365,7 @@ def look_at_view_transform(
degrees: boolean flag to indicate if the elevation and azimuth degrees: boolean flag to indicate if the elevation and azimuth
angles are specified in degrees or radians. angles are specified in degrees or radians.
eye: the position of the camera(s) in world coordinates. If eye is not eye: the position of the camera(s) in world coordinates. If eye is not
None, it will overide the camera position derived from dist, elev, azim. None, it will override the camera position derived from dist, elev, azim.
up: the direction of the x axis in the world coordinate system. up: the direction of the x axis in the world coordinate system.
at: the position of the object(s) in world coordinates. at: the position of the object(s) in world coordinates.
eye, up and at can be of shape (1, 3) or (N, 3). eye, up and at can be of shape (1, 3) or (N, 3).

View File

@ -67,13 +67,13 @@ class EmissionAbsorptionRaymarcher(torch.nn.Module):
rays_features: Per-ray feature values represented with a tensor rays_features: Per-ray feature values represented with a tensor
of shape `(..., n_points_per_ray, feature_dim)`. of shape `(..., n_points_per_ray, feature_dim)`.
eps: A lower bound added to `rays_densities` before computing eps: A lower bound added to `rays_densities` before computing
the absorbtion function (cumprod of `1-rays_densities` along the absorption function (cumprod of `1-rays_densities` along
each ray). This prevents the cumprod to yield exact 0 each ray). This prevents the cumprod to yield exact 0
which would inhibit any gradient-based learning. which would inhibit any gradient-based learning.
Returns: Returns:
features_opacities: A tensor of shape `(..., feature_dim+1)` features_opacities: A tensor of shape `(..., feature_dim+1)`
that concatenates two tensors alonng the last dimension: that concatenates two tensors along the last dimension:
1) features: A tensor of per-ray renders 1) features: A tensor of per-ray renders
of shape `(..., feature_dim)`. of shape `(..., feature_dim)`.
2) opacities: A tensor of per-ray opacity values 2) opacities: A tensor of per-ray opacity values

View File

@ -16,7 +16,7 @@ This file defines three raysampling techniques:
class GridRaysampler(torch.nn.Module): class GridRaysampler(torch.nn.Module):
""" """
Samples a fixed number of points along rays which are regulary distributed Samples a fixed number of points along rays which are regularly distributed
in a batch of rectangular image grids. Points along each ray in a batch of rectangular image grids. Points along each ray
have uniformly-spaced z-coordinates between a predefined have uniformly-spaced z-coordinates between a predefined
minimum and maximum depth. minimum and maximum depth.
@ -129,7 +129,7 @@ class GridRaysampler(torch.nn.Module):
class NDCGridRaysampler(GridRaysampler): class NDCGridRaysampler(GridRaysampler):
""" """
Samples a fixed number of points along rays which are regulary distributed Samples a fixed number of points along rays which are regularly distributed
in a batch of rectangular image grids. Points along each ray in a batch of rectangular image grids. Points along each ray
have uniformly-spaced z-coordinates between a predefined minimum and maximum depth. have uniformly-spaced z-coordinates between a predefined minimum and maximum depth.

View File

@ -18,7 +18,7 @@ from .utils import _validate_ray_bundle_variables, ray_bundle_variables_to_ray_p
# 1) The raysampler: # 1) The raysampler:
# - samples rays from input cameras # - samples rays from input cameras
# - transforms the rays to world coordinates # - transforms the rays to world coordinates
# 2) The volumetric_function (which is a callable argument of the forwad pass) # 2) The volumetric_function (which is a callable argument of the forward pass)
# evaluates ray_densities and ray_features at the sampled ray-points. # evaluates ray_densities and ray_features at the sampled ray-points.
# 3) The raymarcher takes ray_densities and ray_features and uses a raymarching # 3) The raymarcher takes ray_densities and ray_features and uses a raymarching
# algorithm to render each ray. # algorithm to render each ray.
@ -64,7 +64,7 @@ class ImplicitRenderer(torch.nn.Module):
the an feature vector for each ray point. the an feature vector for each ray point.
Note that, in order to increase flexibility of the API, we allow multiple Note that, in order to increase flexibility of the API, we allow multiple
other arguments to enter the volumentric function via additional other arguments to enter the volumetric function via additional
(optional) keyword arguments `**kwargs`. (optional) keyword arguments `**kwargs`.
A typical use-case is passing a `CamerasBase` object as an additional A typical use-case is passing a `CamerasBase` object as an additional
keyword argument, which can allow the volumetric function to adjust its keyword argument, which can allow the volumetric function to adjust its
@ -131,7 +131,7 @@ class ImplicitRenderer(torch.nn.Module):
Args: Args:
cameras: A batch of cameras that render the scene. A `self.raysampler` cameras: A batch of cameras that render the scene. A `self.raysampler`
takes the cameras as input and samples rays that pass through the takes the cameras as input and samples rays that pass through the
domain of the volumentric function. domain of the volumetric function.
volumetric_function: A `Callable` that accepts the parametrizations volumetric_function: A `Callable` that accepts the parametrizations
of the rendering rays and returns the densities and features of the rendering rays and returns the densities and features
at the respective 3D of the rendering rays. Please refer to at the respective 3D of the rendering rays. Please refer to
@ -229,7 +229,7 @@ class VolumeRenderer(torch.nn.Module):
Args: Args:
cameras: A batch of cameras that render the scene. A `self.raysampler` cameras: A batch of cameras that render the scene. A `self.raysampler`
takes the cameras as input and samples rays that pass through the takes the cameras as input and samples rays that pass through the
domain of the volumentric function. domain of the volumetric function.
volumes: An instance of the `Volumes` class representing a volumes: An instance of the `Volumes` class representing a
batch of volumes that are being rendered. batch of volumes that are being rendered.
@ -247,7 +247,7 @@ class VolumeRenderer(torch.nn.Module):
class VolumeSampler(torch.nn.Module): class VolumeSampler(torch.nn.Module):
""" """
A class that allows to sample a batch of volumes `Volumes` A module to sample a batch of volumes `Volumes`
at 3D points sampled along projection rays. at 3D points sampled along projection rays.
""" """
@ -255,7 +255,7 @@ class VolumeSampler(torch.nn.Module):
""" """
Args: Args:
volumes: An instance of the `Volumes` class representing a volumes: An instance of the `Volumes` class representing a
batch if volumes that are being rendered. batch of volumes that are being rendered.
sample_mode: Defines the algorithm used to sample the volumetric sample_mode: Defines the algorithm used to sample the volumetric
voxel grid. Can be either "bilinear" or "nearest". voxel grid. Can be either "bilinear" or "nearest".
""" """
@ -300,7 +300,7 @@ class VolumeSampler(torch.nn.Module):
Returns: Returns:
rays_densities: A tensor of shape rays_densities: A tensor of shape
`(minibatch, ..., num_points_per_ray, opacity_dim)` containing the `(minibatch, ..., num_points_per_ray, opacity_dim)` containing the
densitity vectors sampled from the volume at the locations of density vectors sampled from the volume at the locations of
the ray points. the ray points.
rays_features: A tensor of shape rays_features: A tensor of shape
`(minibatch, ..., num_points_per_ray, feature_dim)` containing the `(minibatch, ..., num_points_per_ray, feature_dim)` containing the

View File

@ -44,7 +44,7 @@ def diffuse(normals, color, direction) -> torch.Tensor:
average/interpolated face coordinates. average/interpolated face coordinates.
""" """
# TODO: handle multiple directional lights per batch element. # TODO: handle multiple directional lights per batch element.
# TODO: handle attentuation. # TODO: handle attenuation.
# Ensure color and location have same batch dimension as normals # Ensure color and location have same batch dimension as normals
normals, color, direction = convert_to_tensors_and_broadcast( normals, color, direction = convert_to_tensors_and_broadcast(
@ -107,7 +107,7 @@ def specular(
meshes.verts_packed_to_mesh_idx() or meshes.faces_packed_to_mesh_idx(). meshes.verts_packed_to_mesh_idx() or meshes.faces_packed_to_mesh_idx().
""" """
# TODO: handle multiple directional lights # TODO: handle multiple directional lights
# TODO: attentuate based on inverse squared distance to the light source # TODO: attenuate based on inverse squared distance to the light source
if points.shape != normals.shape: if points.shape != normals.shape:
msg = "Expected points and normals to have the same shape: got %r, %r" msg = "Expected points and normals to have the same shape: got %r, %r"

View File

@ -17,7 +17,7 @@ from .clip import (
# TODO make the epsilon user configurable # TODO make the epsilon user configurable
kEpsilon = 1e-8 kEpsilon = 1e-8
# Maxinum number of faces per bins for # Maximum number of faces per bins for
# coarse-to-fine rasterization # coarse-to-fine rasterization
kMaxFacesPerBin = 22 kMaxFacesPerBin = 22
@ -68,7 +68,7 @@ def rasterize_meshes(
set it heuristically based on the shape of the input. This should not set it heuristically based on the shape of the input. This should not
affect the output, but can affect the speed of the forward pass. affect the output, but can affect the speed of the forward pass.
faces_per_bin: Only applicable when using coarse-to-fine rasterization faces_per_bin: Only applicable when using coarse-to-fine rasterization
(bin_size > 0); this is the maxiumum number of faces allowed within each (bin_size > 0); this is the maximum number of faces allowed within each
bin. If more than this many faces actually fall into a bin, an error bin. If more than this many faces actually fall into a bin, an error
will be raised. This should not affect the output values, but can affect will be raised. This should not affect the output values, but can affect
the memory usage in the forward pass. the memory usage in the forward pass.
@ -138,7 +138,7 @@ def rasterize_meshes(
num_faces_per_mesh = meshes.num_faces_per_mesh() num_faces_per_mesh = meshes.num_faces_per_mesh()
# In the case that H != W use the max image size to set the bin_size # In the case that H != W use the max image size to set the bin_size
# to accommodate the num bins constraint in the coarse rasteizer. # to accommodate the num bins constraint in the coarse rasterizer.
# If the ratio of H:W is large this might cause issues as the smaller # If the ratio of H:W is large this might cause issues as the smaller
# dimension will have fewer bins. # dimension will have fewer bins.
# TODO: consider a better way of setting the bin size. # TODO: consider a better way of setting the bin size.
@ -453,7 +453,7 @@ def rasterize_meshes_python(
mesh_to_face_first_idx = clipped_faces.mesh_to_face_first_idx mesh_to_face_first_idx = clipped_faces.mesh_to_face_first_idx
num_faces_per_mesh = clipped_faces.num_faces_per_mesh num_faces_per_mesh = clipped_faces.num_faces_per_mesh
# Intialize output tensors. # Initialize output tensors.
face_idxs = torch.full( face_idxs = torch.full(
(N, H, W, K), fill_value=-1, dtype=torch.int64, device=device (N, H, W, K), fill_value=-1, dtype=torch.int64, device=device
) )
@ -662,7 +662,7 @@ def barycentric_coordinates_clip(bary):
Clip negative barycentric coordinates to 0.0 and renormalize so Clip negative barycentric coordinates to 0.0 and renormalize so
the barycentric coordinates for a point sum to 1. When the blur_radius the barycentric coordinates for a point sum to 1. When the blur_radius
is greater than 0, a face will still be recorded as overlapping a pixel is greater than 0, a face will still be recorded as overlapping a pixel
if the pixel is outisde the face. In this case at least one of the if the pixel is outside the face. In this case at least one of the
barycentric coordinates for the pixel relative to the face will be negative. barycentric coordinates for the pixel relative to the face will be negative.
Clipping will ensure that the texture and z buffer are interpolated correctly. Clipping will ensure that the texture and z buffer are interpolated correctly.

View File

@ -60,7 +60,7 @@ class RasterizationSettings:
class MeshRasterizer(nn.Module): class MeshRasterizer(nn.Module):
""" """
This class implements methods for rasterizing a batch of heterogenous This class implements methods for rasterizing a batch of heterogeneous
Meshes. Meshes.
""" """

View File

@ -240,7 +240,7 @@ class TexturesBase:
number of faces in the i-th mesh and C is the dimensional of number of faces in the i-th mesh and C is the dimensional of
the feature (C = 3 for RGB textures). the feature (C = 3 for RGB textures).
You can use the utils function in structures.utils to convert the You can use the utils function in structures.utils to convert the
packed respresentation to a list or padded. packed representation to a list or padded.
""" """
raise NotImplementedError() raise NotImplementedError()
@ -261,10 +261,10 @@ class TexturesBase:
def __getitem__(self, index): def __getitem__(self, index):
""" """
Each texture class should implement a method Each texture class should implement a method
to get the texture properites for the to get the texture properties for the
specified elements in the batch. specified elements in the batch.
The TexturesBase._getitem(i) method The TexturesBase._getitem(i) method
can be used as a helper funtion to retrieve the can be used as a helper function to retrieve the
class attributes for item i. Then, a new class attributes for item i. Then, a new
instance of the child class can be created with instance of the child class can be created with
the attributes. the attributes.
@ -496,7 +496,7 @@ class TexturesAtlas(TexturesBase):
of the faces (in the packed representation) which of the faces (in the packed representation) which
overlap each pixel in the image. overlap each pixel in the image.
- barycentric_coords: FloatTensor of shape (N, H, W, K, 3) specifying - barycentric_coords: FloatTensor of shape (N, H, W, K, 3) specifying
the barycentric coordianates of each pixel the barycentric coordinates of each pixel
relative to the faces (in the packed relative to the faces (in the packed
representation) which overlap the pixel. representation) which overlap the pixel.
@ -536,7 +536,7 @@ class TexturesAtlas(TexturesBase):
For N meshes with {Fi} number of faces, it returns a For N meshes with {Fi} number of faces, it returns a
tensor of shape sum(Fi)x3xD (D = 3 for RGB). tensor of shape sum(Fi)x3xD (D = 3 for RGB).
You can use the utils function in structures.utils to convert the You can use the utils function in structures.utils to convert the
packed respresentation to a list or padded. packed representation to a list or padded.
""" """
atlas_packed = self.atlas_packed() atlas_packed = self.atlas_packed()
# assume each face consists of (v0, v1, v2). # assume each face consists of (v0, v1, v2).
@ -892,7 +892,7 @@ class TexturesUV(TexturesBase):
of the faces (in the packed representation) which of the faces (in the packed representation) which
overlap each pixel in the image. overlap each pixel in the image.
- barycentric_coords: FloatTensor of shape (N, H, W, K, 3) specifying - barycentric_coords: FloatTensor of shape (N, H, W, K, 3) specifying
the barycentric coordianates of each pixel the barycentric coordinates of each pixel
relative to the faces (in the packed relative to the faces (in the packed
representation) which overlap the pixel. representation) which overlap the pixel.
@ -1233,7 +1233,7 @@ class TexturesVertex(TexturesBase):
Args: Args:
verts_features: list of (Vi, D) or (N, V, D) tensor giving a feature verts_features: list of (Vi, D) or (N, V, D) tensor giving a feature
vector with artbitrary dimensions for each vertex. vector with arbitrary dimensions for each vertex.
""" """
if isinstance(verts_features, (tuple, list)): if isinstance(verts_features, (tuple, list)):
correct_shape = all( correct_shape = all(
@ -1356,7 +1356,7 @@ class TexturesVertex(TexturesBase):
def sample_textures(self, fragments, faces_packed=None) -> torch.Tensor: def sample_textures(self, fragments, faces_packed=None) -> torch.Tensor:
""" """
Detemine the color for each rasterized face. Interpolate the colors for Determine the color for each rasterized face. Interpolate the colors for
vertices which form the face using the barycentric coordinates. vertices which form the face using the barycentric coordinates.
Args: Args:
fragments: fragments:
@ -1366,7 +1366,7 @@ class TexturesVertex(TexturesBase):
of the faces (in the packed representation) which of the faces (in the packed representation) which
overlap each pixel in the image. overlap each pixel in the image.
- barycentric_coords: FloatTensor of shape (N, H, W, K, 3) specifying - barycentric_coords: FloatTensor of shape (N, H, W, K, 3) specifying
the barycentric coordianates of each pixel the barycentric coordinates of each pixel
relative to the faces (in the packed relative to the faces (in the packed
representation) which overlap the pixel. representation) which overlap the pixel.
@ -1389,7 +1389,7 @@ class TexturesVertex(TexturesBase):
For N meshes with {Fi} number of faces, it returns a For N meshes with {Fi} number of faces, it returns a
tensor of shape sum(Fi)x3xC (C = 3 for RGB). tensor of shape sum(Fi)x3xC (C = 3 for RGB).
You can use the utils function in structures.utils to convert the You can use the utils function in structures.utils to convert the
packed respresentation to a list or padded. packed representation to a list or padded.
""" """
verts_features_packed = self.verts_features_packed() verts_features_packed = self.verts_features_packed()
faces_verts_features = verts_features_packed[faces_packed] faces_verts_features = verts_features_packed[faces_packed]

View File

@ -44,7 +44,7 @@ def _interpolate_zbuf(
of the faces (in the packed representation) which of the faces (in the packed representation) which
overlap each pixel in the image. overlap each pixel in the image.
barycentric_coords: FloatTensor of shape (N, H, W, K, 3) specifying barycentric_coords: FloatTensor of shape (N, H, W, K, 3) specifying
the barycentric coordianates of each pixel the barycentric coordinates of each pixel
relative to the faces (in the packed relative to the faces (in the packed
representation) which overlap the pixel. representation) which overlap the pixel.
meshes: Meshes object representing a batch of meshes. meshes: Meshes object representing a batch of meshes.
@ -98,7 +98,7 @@ def _try_place_rectangle(
Example: Example:
(We always have placed the first rectangle horizontally and other (We always have placed the first rectangle horizontally and other
rectangles above it.) rectangles above it.)
Let's say the placed boxes 1-4 are layed out like this. Let's say the placed boxes 1-4 are laid out like this.
The coordinates of the points marked X are stored in occupied. The coordinates of the points marked X are stored in occupied.
It is to the right of the X's that we seek to place rect. It is to the right of the X's that we seek to place rect.

View File

@ -8,7 +8,7 @@ from pytorch3d import _C # pyre-fixme[21]: Could not find name `_C` in `pytorch
from pytorch3d.renderer.mesh.rasterize_meshes import pix_to_non_square_ndc from pytorch3d.renderer.mesh.rasterize_meshes import pix_to_non_square_ndc
# Maxinum number of faces per bins for # Maximum number of faces per bins for
# coarse-to-fine rasterization # coarse-to-fine rasterization
kMaxPointsPerBin = 22 kMaxPointsPerBin = 22
@ -59,7 +59,7 @@ def rasterize_points(
set it heuristically based on the shape of the input. This should not set it heuristically based on the shape of the input. This should not
affect the output, but can affect the speed of the forward pass. affect the output, but can affect the speed of the forward pass.
points_per_bin: Only applicable when using coarse-to-fine rasterization points_per_bin: Only applicable when using coarse-to-fine rasterization
(bin_size > 0); this is the maxiumum number of points allowed within each (bin_size > 0); this is the maximum number of points allowed within each
bin. If more than this many points actually fall into a bin, an error bin. If more than this many points actually fall into a bin, an error
will be raised. This should not affect the output values, but can affect will be raised. This should not affect the output values, but can affect
the memory usage in the forward pass. the memory usage in the forward pass.
@ -95,7 +95,7 @@ def rasterize_points(
radius = _format_radius(radius, pointclouds) radius = _format_radius(radius, pointclouds)
# In the case that H != W use the max image size to set the bin_size # In the case that H != W use the max image size to set the bin_size
# to accommodate the num bins constraint in the coarse rasteizer. # to accommodate the num bins constraint in the coarse rasterizer.
# If the ratio of H:W is large this might cause issues as the smaller # If the ratio of H:W is large this might cause issues as the smaller
# dimension will have fewer bins. # dimension will have fewer bins.
# TODO: consider a better way of setting the bin size. # TODO: consider a better way of setting the bin size.
@ -276,7 +276,7 @@ def rasterize_points_python(
# Support variable size radius for each point in the batch # Support variable size radius for each point in the batch
radius = _format_radius(radius, pointclouds) radius = _format_radius(radius, pointclouds)
# Intialize output tensors. # Initialize output tensors.
point_idxs = torch.full( point_idxs = torch.full(
(N, H, W, K), fill_value=-1, dtype=torch.int32, device=device (N, H, W, K), fill_value=-1, dtype=torch.int32, device=device
) )

View File

@ -76,7 +76,7 @@ class TensorAccessor(nn.Module):
if hasattr(self.class_object, name): if hasattr(self.class_object, name):
return self.class_object.__dict__[name][self.index] return self.class_object.__dict__[name][self.index]
else: else:
msg = "Attribue %s not found on %r" msg = "Attribute %s not found on %r"
return AttributeError(msg % (name, self.class_object.__name__)) return AttributeError(msg % (name, self.class_object.__name__))

View File

@ -22,13 +22,13 @@ class Meshes(object):
- has specific batch dimension. - has specific batch dimension.
Packed Packed
- no batch dimension. - no batch dimension.
- has auxillary variables used to index into the padded representation. - has auxiliary variables used to index into the padded representation.
Example: Example:
Input list of verts V_n = [[V_1], [V_2], ... , [V_N]] Input list of verts V_n = [[V_1], [V_2], ... , [V_N]]
where V_1, ... , V_N are the number of verts in each mesh and N is the where V_1, ... , V_N are the number of verts in each mesh and N is the
numer of meshes. number of meshes.
Input list of faces F_n = [[F_1], [F_2], ... , [F_N]] Input list of faces F_n = [[F_1], [F_2], ... , [F_N]]
where F_1, ... , F_N are the number of faces in each mesh. where F_1, ... , F_N are the number of faces in each mesh.
@ -100,7 +100,7 @@ class Meshes(object):
| ]) | | ]) |
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
Auxillary variables for packed representation Auxiliary variables for packed representation
Name | Size | Example from above Name | Size | Example from above
-------------------------------|---------------------|----------------------- -------------------------------|---------------------|-----------------------
@ -139,7 +139,7 @@ class Meshes(object):
# SPHINX IGNORE # SPHINX IGNORE
From the faces, edges are computed and have packed and padded From the faces, edges are computed and have packed and padded
representations with auxillary variables. representations with auxiliary variables.
E_n = [[E_1], ... , [E_N]] E_n = [[E_1], ... , [E_N]]
where E_1, ... , E_N are the number of unique edges in each mesh. where E_1, ... , E_N are the number of unique edges in each mesh.
@ -894,7 +894,7 @@ class Meshes(object):
def _compute_packed(self, refresh: bool = False): def _compute_packed(self, refresh: bool = False):
""" """
Computes the packed version of the meshes from verts_list and faces_list Computes the packed version of the meshes from verts_list and faces_list
and sets the values of auxillary tensors. and sets the values of auxiliary tensors.
Args: Args:
refresh: Set to True to force recomputation of packed representations. refresh: Set to True to force recomputation of packed representations.
@ -1022,7 +1022,7 @@ class Meshes(object):
# Remove duplicate edges: convert each edge (v0, v1) into an # Remove duplicate edges: convert each edge (v0, v1) into an
# integer hash = V * v0 + v1; this allows us to use the scalar version of # integer hash = V * v0 + v1; this allows us to use the scalar version of
# unique which is much faster than edges.unique(dim=1) which is very slow. # unique which is much faster than edges.unique(dim=1) which is very slow.
# After finding the unique elements reconstruct the vertex indicies as: # After finding the unique elements reconstruct the vertex indices as:
# (v0, v1) = (hash / V, hash % V) # (v0, v1) = (hash / V, hash % V)
# The inverse maps from unique_edges back to edges: # The inverse maps from unique_edges back to edges:
# unique_edges[inverse_idxs] == edges # unique_edges[inverse_idxs] == edges

View File

@ -18,7 +18,7 @@ class Pointclouds(object):
- has specific batch dimension. - has specific batch dimension.
Packed Packed
- no batch dimension. - no batch dimension.
- has auxillary variables used to index into the padded representation. - has auxiliary variables used to index into the padded representation.
Example Example
@ -61,7 +61,7 @@ class Pointclouds(object):
| ]) | | ]) |
----------------------------------------------------------------------------- -----------------------------------------------------------------------------
Auxillary variables for packed representation Auxiliary variables for packed representation
Name | Size | Example from above Name | Size | Example from above
-------------------------------|---------------------|----------------------- -------------------------------|---------------------|-----------------------
@ -265,7 +265,7 @@ class Pointclouds(object):
) )
if d.device != self.device: if d.device != self.device:
raise ValueError( raise ValueError(
"All auxillary inputs must be on the same device as the points." "All auxiliary inputs must be on the same device as the points."
) )
if p > 0: if p > 0:
if d.dim() != 2: if d.dim() != 2:
@ -291,7 +291,7 @@ class Pointclouds(object):
) )
if aux_input.device != self.device: if aux_input.device != self.device:
raise ValueError( raise ValueError(
"All auxillary inputs must be on the same device as the points." "All auxiliary inputs must be on the same device as the points."
) )
aux_input_C = aux_input.shape[2] aux_input_C = aux_input.shape[2]
return None, aux_input, aux_input_C return None, aux_input, aux_input_C
@ -508,7 +508,7 @@ class Pointclouds(object):
def padded_to_packed_idx(self): def padded_to_packed_idx(self):
""" """
Return a 1D tensor x with length equal to the total number of points Return a 1D tensor x with length equal to the total number of points
such that points_packed()[i] is element x[i] of the flattened padded such that points_packed()[i] is element x[i] of the flattened padded
representation. representation.
The packed representation can be calculated as follows. The packed representation can be calculated as follows.
@ -573,7 +573,7 @@ class Pointclouds(object):
def _compute_packed(self, refresh: bool = False): def _compute_packed(self, refresh: bool = False):
""" """
Computes the packed version from points_list, normals_list and Computes the packed version from points_list, normals_list and
features_list and sets the values of auxillary tensors. features_list and sets the values of auxiliary tensors.
Args: Args:
refresh: Set to True to force recomputation of packed refresh: Set to True to force recomputation of packed
@ -910,7 +910,7 @@ class Pointclouds(object):
**neighborhood_size**: The size of the neighborhood used to estimate the **neighborhood_size**: The size of the neighborhood used to estimate the
geometry around each point. geometry around each point.
**disambiguate_directions**: If `True`, uses the algorithm from [1] to **disambiguate_directions**: If `True`, uses the algorithm from [1] to
ensure sign consistency of the normals of neigboring points. ensure sign consistency of the normals of neighboring points.
**normals**: A tensor of normals for each input point **normals**: A tensor of normals for each input point
of shape `(minibatch, num_point, 3)`. of shape `(minibatch, num_point, 3)`.
If `pointclouds` are of `Pointclouds` class, returns a padded tensor. If `pointclouds` are of `Pointclouds` class, returns a padded tensor.
@ -985,7 +985,7 @@ class Pointclouds(object):
Args: Args:
new_points_padded: FloatTensor of shape (N, P, 3) new_points_padded: FloatTensor of shape (N, P, 3)
new_normals_padded: (optional) FloatTensor of shape (N, P, 3) new_normals_padded: (optional) FloatTensor of shape (N, P, 3)
new_features_padded: (optional) FloatTensors of shape (N, P, C) new_features_padded: (optional) FloatTensor of shape (N, P, C)
Returns: Returns:
Pointcloud with updated padded representations Pointcloud with updated padded representations

View File

@ -77,7 +77,7 @@ class Volumes(object):
World coordinates: World coordinates:
- These define the locations of the centers of the volume cells - These define the locations of the centers of the volume cells
in the world coordinates. in the world coordinates.
- They are specifiied with the following mapping that converts - They are specified with the following mapping that converts
points `x_local` in the local coordinates to points `x_world` points `x_local` in the local coordinates to points `x_world`
in the world coordinates: in the world coordinates:
``` ```

View File

@ -511,7 +511,7 @@ def quaternion_to_axis_angle(quaternions):
def rotation_6d_to_matrix(d6: torch.Tensor) -> torch.Tensor: def rotation_6d_to_matrix(d6: torch.Tensor) -> torch.Tensor:
""" """
Converts 6D rotation representation by Zhou et al. [1] to rotation matrix Converts 6D rotation representation by Zhou et al. [1] to rotation matrix
using Gram--Schmidt orthogonalisation per Section B of [1]. using Gram--Schmidt orthogonalization per Section B of [1].
Args: Args:
d6: 6D rotation representation, of size (*, 6) d6: 6D rotation representation, of size (*, 6)

View File

@ -190,7 +190,7 @@ class Transform3d:
def compose(self, *others): def compose(self, *others):
""" """
Return a new Transform3d with the tranforms to compose stored as Return a new Transform3d with the transforms to compose stored as
an internal list. an internal list.
Args: Args:
@ -254,7 +254,7 @@ class Transform3d:
independently without composing them. independently without composing them.
Returns: Returns:
A new Transform3D object contaning the inverse of the original A new Transform3D object containing the inverse of the original
transformation. transformation.
""" """
@ -302,7 +302,7 @@ class Transform3d:
Args: Args:
points: Tensor of shape (P, 3) or (N, P, 3) points: Tensor of shape (P, 3) or (N, P, 3)
eps: If eps!=None, the argument is used to clamp the eps: If eps!=None, the argument is used to clamp the
last coordinate before peforming the final division. last coordinate before performing the final division.
The clamping corresponds to: The clamping corresponds to:
last_coord := (last_coord.sign() + (last_coord==0)) * last_coord := (last_coord.sign() + (last_coord==0)) *
torch.clamp(last_coord.abs(), eps), torch.clamp(last_coord.abs(), eps),
@ -681,7 +681,7 @@ def _broadcast_bmm(a, b):
b: torch tensor of shape (N, K, K) b: torch tensor of shape (N, K, K)
Returns: Returns:
a and b broadcast multipled. The output batch dimension is max(N, M). a and b broadcast multiplied. The output batch dimension is max(N, M).
To broadcast transforms across a batch dimension if M != N then To broadcast transforms across a batch dimension if M != N then
expect that either M = 1 or N = 1. The tensor with batch dimension 1 is expect that either M = 1 or N = 1. The tensor with batch dimension 1 is

View File

@ -567,7 +567,7 @@ def _add_pointcloud_trace(
pointclouds: Pointclouds object to render. It can be batched. pointclouds: Pointclouds object to render. It can be batched.
trace_name: name to label the trace with. trace_name: name to label the trace with.
subplot_idx: identifies the subplot, with 0 being the top left. subplot_idx: identifies the subplot, with 0 being the top left.
ncols: the number of sublpots per row. ncols: the number of subplots per row.
max_points_per_pointcloud: the number of points to render, which are randomly sampled. max_points_per_pointcloud: the number of points to render, which are randomly sampled.
marker_size: the size of the rendered points marker_size: the size of the rendered points
""" """
@ -648,7 +648,7 @@ def _add_camera_trace(
cameras: the Cameras object to render. It can be batched. cameras: the Cameras object to render. It can be batched.
trace_name: name to label the trace with. trace_name: name to label the trace with.
subplot_idx: identifies the subplot, with 0 being the top left. subplot_idx: identifies the subplot, with 0 being the top left.
ncols: the number of sublpots per row. ncols: the number of subplots per row.
camera_scale: the size of the wireframe used to render the Cameras object. camera_scale: the size of the wireframe used to render the Cameras object.
""" """
cam_wires = get_camera_wireframe(camera_scale).to(cameras.device) cam_wires = get_camera_wireframe(camera_scale).to(cameras.device)

View File

@ -328,7 +328,9 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase):
with self.assertRaises(ValueError) as err: with self.assertRaises(ValueError) as err:
load_obj(obj_file) load_obj(obj_file)
self.assertTrue("Face vertices can ony have 3 properties" in str(err.exception)) self.assertTrue(
"Face vertices can only have 3 properties" in str(err.exception)
)
def test_load_obj_error_invalid_vertex_indices(self): def test_load_obj_error_invalid_vertex_indices(self):
obj_file = "\n".join( obj_file = "\n".join(
@ -631,7 +633,7 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase):
self.assertTrue(aux.normals is None) self.assertTrue(aux.normals is None)
self.assertTrue(aux.verts_uvs is None) self.assertTrue(aux.verts_uvs is None)
def test_load_obj_mlt_no_image(self): def test_load_obj_mtl_no_image(self):
obj_filename = "obj_mtl_no_image/model.obj" obj_filename = "obj_mtl_no_image/model.obj"
filename = os.path.join(DATA_DIR, obj_filename) filename = os.path.join(DATA_DIR, obj_filename)
R = 8 R = 8

View File

@ -317,7 +317,7 @@ class TestMeshPlyIO(TestCaseMixin, unittest.TestCase):
file.close() file.close()
self.assertLess(lengths[False], lengths[True], "ascii should be longer") self.assertLess(lengths[False], lengths[True], "ascii should be longer")
def test_heterogenous_property(self): def test_heterogeneous_property(self):
ply_file_ascii = "\n".join( ply_file_ascii = "\n".join(
[ [
"ply", "ply",
@ -670,7 +670,7 @@ class TestMeshPlyIO(TestCaseMixin, unittest.TestCase):
with self.assertRaisesRegex(ValueError, msg): with self.assertRaisesRegex(ValueError, msg):
_load_ply_raw(StringIO("\n".join(lines2))) _load_ply_raw(StringIO("\n".join(lines2)))
# Heterogenous cases # Heterogeneous cases
lines2 = lines.copy() lines2 = lines.copy()
lines2.insert(4, "property double y") lines2.insert(4, "property double y")

View File

@ -155,7 +155,7 @@ class TestICP(TestCaseMixin, unittest.TestCase):
self.assertClose(s_init, s, atol=atol) self.assertClose(s_init, s, atol=atol)
self.assertClose(Xt_init, Xt, atol=atol) self.assertClose(Xt_init, Xt, atol=atol)
def test_heterogenous_inputs(self, batch_size=10): def test_heterogeneous_inputs(self, batch_size=10):
""" """
Tests whether we get the same result when running ICP on Tests whether we get the same result when running ICP on
a set of randomly-sized Pointclouds and on their padded versions. a set of randomly-sized Pointclouds and on their padded versions.

View File

@ -230,9 +230,9 @@ class TestPointsToVolumes(TestCaseMixin, unittest.TestCase):
def test_from_point_cloud(self, interp_mode="trilinear"): def test_from_point_cloud(self, interp_mode="trilinear"):
""" """
Generates a volume from a random point cloud sampled from faces Generates a volume from a random point cloud sampled from faces
of a 3D cube. Since each side of the cube is homogenously colored with of a 3D cube. Since each side of the cube is homogeneously colored with
a different color, this should result in a volume with a a different color, this should result in a volume with a
predefined homogenous color of the cells along its borders predefined homogeneous color of the cells along its borders
and black interior. The test is run for both cube and non-cube shaped and black interior. The test is run for both cube and non-cube shaped
volumes. volumes.
""" """

View File

@ -511,7 +511,7 @@ class TestRasterizePoints(TestCaseMixin, unittest.TestCase):
) )
# Note that the order is only deterministic here for CUDA if all points # Note that the order is only deterministic here for CUDA if all points
# fit in one chunk. This will the the case for this small example, but # fit in one chunk. This will the the case for this small example, but
# to properly exercise coordianted writes among multiple chunks we need # to properly exercise coordinated writes among multiple chunks we need
# to use a bigger test case. # to use a bigger test case.
bin_points_expected[0, 0, 1, :2] = torch.tensor([0, 3]) bin_points_expected[0, 0, 1, :2] = torch.tensor([0, 3])
bin_points_expected[0, 1, 0, 0] = torch.tensor([2]) bin_points_expected[0, 1, 0, 0] = torch.tensor([2])

View File

@ -62,7 +62,7 @@ verts0 = torch.tensor(
) )
faces0 = torch.tensor([[1, 0, 2], [4, 3, 5]], dtype=torch.int64) faces0 = torch.tensor([[1, 0, 2], [4, 3, 5]], dtype=torch.int64)
# Points for a simple pointcloud. Get the vertices from a # Points for a simple point cloud. Get the vertices from a
# torus and apply rotations such that the points are no longer # torus and apply rotations such that the points are no longer
# symmerical in X/Y. # symmerical in X/Y.
torus_mesh = torus(r=0.25, R=1.0, sides=5, rings=2 * 5) torus_mesh = torus(r=0.25, R=1.0, sides=5, rings=2 * 5)
@ -771,7 +771,7 @@ class TestRasterizeRectangleImagesPointclouds(TestCaseMixin, unittest.TestCase):
def test_render_pointcloud(self): def test_render_pointcloud(self):
""" """
Test a textured poincloud is rendered correctly in a non square image. Test a textured point cloud is rendered correctly in a non square image.
""" """
device = torch.device("cuda:0") device = torch.device("cuda:0")
pointclouds = Pointclouds( pointclouds = Pointclouds(

View File

@ -16,7 +16,7 @@ class TestRaymarching(TestCaseMixin, unittest.TestCase):
n_rays=10, n_pts_per_ray=9, device="cuda", dtype=torch.float32 n_rays=10, n_pts_per_ray=9, device="cuda", dtype=torch.float32
): ):
""" """
Generate a batch of ray points with features, densities, and z-coodinates Generate a batch of ray points with features, densities, and z-coordinates
such that their EmissionAbsorption renderring results in such that their EmissionAbsorption renderring results in
feature renders `features_gt`, depth renders `depths_gt`, feature renders `features_gt`, depth renders `depths_gt`,
and opacity renders `opacities_gt`. and opacity renders `opacities_gt`.

View File

@ -1052,7 +1052,7 @@ class TestRenderMeshes(TestCaseMixin, unittest.TestCase):
images[0, ...].sum().backward() images[0, ...].sum().backward()
fragments = rasterizer(mesh, raster_settings=raster_settings) fragments = rasterizer(mesh, raster_settings=raster_settings)
# Some of the bary coordinates are outisde the # Some of the bary coordinates are outside the
# [0, 1] range as expected because the blur is > 0 # [0, 1] range as expected because the blur is > 0
self.assertTrue(fragments.bary_coords.ge(1.0).any()) self.assertTrue(fragments.bary_coords.ge(1.0).any())
self.assertIsNotNone(atlas.grad) self.assertIsNotNone(atlas.grad)

View File

@ -531,7 +531,7 @@ class TestRenderVolumes(TestCaseMixin, unittest.TestCase):
# get the EA raymarcher # get the EA raymarcher
raymarcher = EmissionAbsorptionRaymarcher() raymarcher = EmissionAbsorptionRaymarcher()
# intialize the renderer # initialize the renderer
renderer = VolumeRenderer( renderer = VolumeRenderer(
raysampler=raysampler, raysampler=raysampler,
raymarcher=raymarcher, raymarcher=raymarcher,
@ -574,8 +574,8 @@ class TestRenderVolumes(TestCaseMixin, unittest.TestCase):
def test_rotating_cube_volume_render(self): def test_rotating_cube_volume_render(self):
""" """
Generates 4 renders of 4 sides of a volume representing a 3D cube. Generates 4 renders of 4 sides of a volume representing a 3D cube.
Since each side of the cube is homogenously colored with Since each side of the cube is homogeneously colored with
a different color, this should result in 4 images of homogenous color a different color, this should result in 4 images of homogeneous color
with the depth of each pixel equal to a constant. with the depth of each pixel equal to a constant.
""" """

View File

@ -148,8 +148,8 @@ class TestSO3(TestCaseMixin, unittest.TestCase):
`so3_exponential_map(so3_log_map(so3_exponential_map(log_rot))) `so3_exponential_map(so3_log_map(so3_exponential_map(log_rot)))
== so3_exponential_map(log_rot)` == so3_exponential_map(log_rot)`
for a randomly generated batch of rotation matrix logarithms `log_rot`. for a randomly generated batch of rotation matrix logarithms `log_rot`.
Unlike `test_so3_log_to_exp_to_log`, this test allows to check the Unlike `test_so3_log_to_exp_to_log`, this test checks the
correctness of converting `log_rot` which contains values > math.pi. correctness of converting a `log_rot` which contains values > math.pi.
""" """
log_rot = 2.0 * TestSO3.init_log_rot(batch_size=batch_size) log_rot = 2.0 * TestSO3.init_log_rot(batch_size=batch_size)
# check also the singular cases where rot. angle = {0, pi, 2pi, 3pi} # check also the singular cases where rot. angle = {0, pi, 2pi, 3pi}

View File

@ -28,7 +28,7 @@ class TutorialHome extends React.Component {
</header> </header>
<p> <p>
Here you can learn about the structure and applications of Here you can learn about the structure and applications of
Pytorch3D from examples which are in the form of ipython PyTorch3D from examples which are in the form of ipython
notebooks. notebooks.
</p> </p>
<h3> Run interactively </h3> <h3> Run interactively </h3>