PyTorch3D

PyTorch3D

  • ドキュメント
  • チュートリアル
  • API
  • GitHub

›

チュートリアル

  • 概要

3D演算子

  • メッシュのフィット
  • バンドル調整

レンダリング

  • テクスチャ付きメッシュのレンダリング
  • DensePoseメッシュのレンダリング
  • 色付き点群のレンダリング
  • レンダリングによるテクスチャ付きメッシュのフィット
  • 微分可能レンダリングによるカメラ位置の最適化
  • レイマーチングによるボリュームのフィット
  • レイマーチングによる簡略化されたNeRFのフィット

データローダー

  • ShapeNetCoreおよびR2N2用のデータローダー

Implicitron

  • implicitronを使用したカスタムボリューム関数のトレーニング
  • implicitron設定システムの詳細
Google Colabで実行
チュートリアルJupyter Notebookをダウンロード
チュートリアルソースコードをダウンロード
In [ ]
# Copyright (c) Meta Platforms, Inc. and affiliates. All rights reserved.

テクスチャ付きメッシュのレンダリング¶

このチュートリアルでは、以下の方法を説明します。

  • .objファイルからメッシュとテクスチャをロードする。
  • レンダラーを設定する
  • メッシュをレンダリングする
  • 照明やカメラの位置など、レンダリング設定を変更する
  • pytorch3d APIのバッチ処理機能を使用して、さまざまな視点からメッシュをレンダリングする

0. モジュールのインストールとインポート¶

torchとtorchvisionがインストールされていることを確認してください。 pytorch3dがインストールされていない場合は、次のセルを使用してインストールしてください。

In [ ]
import os
import sys
import torch
need_pytorch3d=False
try:
    import pytorch3d
except ModuleNotFoundError:
    need_pytorch3d=True
if need_pytorch3d:
    if torch.__version__.startswith("2.2.") and sys.platform.startswith("linux"):
        # We try to install PyTorch3D via a released wheel.
        pyt_version_str=torch.__version__.split("+")[0].replace(".", "")
        version_str="".join([
            f"py3{sys.version_info.minor}_cu",
            torch.version.cuda.replace(".",""),
            f"_pyt{pyt_version_str}"
        ])
        !pip install fvcore iopath
        !pip install --no-index --no-cache-dir pytorch3d -f https://dl.fbaipublicfiles.com/pytorch3d/packaging/wheels/{version_str}/download.html
    else:
        # We try to install PyTorch3D from source.
        !pip install 'git+https://github.com/facebookresearch/pytorch3d.git@stable'
In [ ]
import os
import torch
import matplotlib.pyplot as plt

# Util function for loading meshes
from pytorch3d.io import load_objs_as_meshes, load_obj

# Data structures and functions for rendering
from pytorch3d.structures import Meshes
from pytorch3d.vis.plotly_vis import AxisArgs, plot_batch_individually, plot_scene
from pytorch3d.vis.texture_vis import texturesuv_image_matplotlib
from pytorch3d.renderer import (
    look_at_view_transform,
    FoVPerspectiveCameras, 
    PointLights, 
    DirectionalLights, 
    Materials, 
    RasterizationSettings, 
    MeshRenderer, 
    MeshRasterizer,  
    SoftPhongShader,
    TexturesUV,
    TexturesVertex
)

# add path for demo utils functions 
import sys
import os
sys.path.append(os.path.abspath(''))

Google Colabを使用している場合は、画像グリッドをプロットするためのutilsファイルをフェッチします。

In [ ]
!wget https://raw.githubusercontent.com/facebookresearch/pytorch3d/main/docs/tutorials/utils/plot_image_grid.py
from plot_image_grid import image_grid

または、ローカルで実行する場合は、次のセルのコメントを解除して実行します。

In [ ]
# from utils import image_grid

1. メッシュとテクスチャファイルのロード¶

.objファイルとそれに関連付けられた.mtlファイルをロードし、TexturesおよびMeshesオブジェクトを作成します。

Meshesは、PyTorch3Dでさまざまなサイズのメッシュのバッチを扱うために提供されている独自のデータ構造です。

TexturesUVは、メッシュの頂点UVとテクスチャマップを格納するための補助的なデータ構造です。

Meshesには、レンダリングパイプライン全体で使用されるいくつかのクラスメソッドがあります。

Google Colabを使用してこのノートブックを実行する場合は、次のセルを実行して、メッシュobjファイルとテクスチャファイルをフェッチし、data/cow_meshパスに保存します。ローカルで実行している場合は、データはすでに正しいパスにあります。

In [ ]
!mkdir -p data/cow_mesh
!wget -P data/cow_mesh https://dl.fbaipublicfiles.com/pytorch3d/data/cow_mesh/cow.obj
!wget -P data/cow_mesh https://dl.fbaipublicfiles.com/pytorch3d/data/cow_mesh/cow.mtl
!wget -P data/cow_mesh https://dl.fbaipublicfiles.com/pytorch3d/data/cow_mesh/cow_texture.png
In [ ]
# Setup
if torch.cuda.is_available():
    device = torch.device("cuda:0")
    torch.cuda.set_device(device)
else:
    device = torch.device("cpu")

# Set paths
DATA_DIR = "./data"
obj_filename = os.path.join(DATA_DIR, "cow_mesh/cow.obj")

# Load obj file
mesh = load_objs_as_meshes([obj_filename], device=device)

テクスチャマップを視覚化しましょう¶

In [ ]
plt.figure(figsize=(7,7))
texture_image=mesh.textures.maps_padded()
plt.imshow(texture_image.squeeze().cpu().numpy())
plt.axis("off");

PyTorch3Dには、matplotlibでテクスチャマップを表示する組み込みの方法と、頂点に対応するマップ上のポイントがあります。 また、ファイルに保存できる同様のイメージを取得するためのメソッドtexturesuv_image_PILもあります。

In [ ]
plt.figure(figsize=(7,7))
texturesuv_image_matplotlib(mesh.textures, subsample=None)
plt.axis("off");

2. レンダラーの作成¶

PyTorch3Dのレンダラーは、ラスタライザーとシェーダーで構成されており、それぞれにカメラ(正投影/透視投影)などの多くのサブコンポーネントがあります。 ここでは、これらのコンポーネントの一部を初期化し、残りの部分にはデフォルト値を使用します。

この例では、まず、透視カメラ、点光源を使用し、Phongシェーディングを適用するレンダラーを作成します。 次に、モジュール式APIを使用してさまざまなコンポーネントを変更する方法を学びます。

In [ ]
# Initialize a camera.
# With world coordinates +Y up, +X left and +Z in, the front of the cow is facing the -Z direction. 
# So we move the camera by 180 in the azimuth direction so it is facing the front of the cow. 
R, T = look_at_view_transform(2.7, 0, 180) 
cameras = FoVPerspectiveCameras(device=device, R=R, T=T)

# Define the settings for rasterization and shading. Here we set the output image to be of size
# 512x512. As we are rendering images for visualization purposes only we will set faces_per_pixel=1
# and blur_radius=0.0. We also set bin_size and max_faces_per_bin to None which ensure that 
# the faster coarse-to-fine rasterization method is used. Refer to rasterize_meshes.py for 
# explanations of these parameters. Refer to docs/notes/renderer.md for an explanation of 
# the difference between naive and coarse-to-fine rasterization. 
raster_settings = RasterizationSettings(
    image_size=512, 
    blur_radius=0.0, 
    faces_per_pixel=1, 
)

# Place a point light in front of the object. As mentioned above, the front of the cow is facing the 
# -z direction. 
lights = PointLights(device=device, location=[[0.0, 0.0, -3.0]])

# Create a Phong renderer by composing a rasterizer and a shader. The textured Phong shader will 
# interpolate the texture uv coordinates for each vertex, sample from a texture image and 
# apply the Phong lighting model
renderer = MeshRenderer(
    rasterizer=MeshRasterizer(
        cameras=cameras, 
        raster_settings=raster_settings
    ),
    shader=SoftPhongShader(
        device=device, 
        cameras=cameras,
        lights=lights
    )
)

3. メッシュのレンダリング¶

光源がオブジェクトの前にあるため、明るく、画像には鏡面ハイライトがあります。

In [ ]
images = renderer(mesh)
plt.figure(figsize=(10, 10))
plt.imshow(images[0, ..., :3].cpu().numpy())
plt.axis("off");

4. 光源をオブジェクトの後ろに移動して再レンダリング¶

rendererの呼び出しを介して、任意のキーワード引数をrasterizer/shaderに渡すことができるため、設定が変更された場合でもレンダラーを再初期化する必要はありません。

この場合、ライトの位置を更新し、それをレンダラーの呼び出しに渡すだけで済みます。

周囲光のみで、鏡面ハイライトがないため、画像は暗くなります。

In [ ]
# Now move the light so it is on the +Z axis which will be behind the cow. 
lights.location = torch.tensor([0.0, 0.0, +1.0], device=device)[None]
images = renderer(mesh, lights=lights)
In [ ]
plt.figure(figsize=(10, 10))
plt.imshow(images[0, ..., :3].cpu().numpy())
plt.axis("off");

5. オブジェクトの回転、材質プロパティまたは光プロパティの変更¶

レンダリングパイプラインで他の多くの設定を変更することもできます。 ここでは

  • カメラの視角を変更します
  • 点光源の位置を変更します
  • メッシュの材料反射率プロパティを変更します
In [ ]
# Rotate the object by increasing the elevation and azimuth angles
R, T = look_at_view_transform(dist=2.7, elev=10, azim=-150)
cameras = FoVPerspectiveCameras(device=device, R=R, T=T)

# Move the light location so the light is shining on the cow's face.  
lights.location = torch.tensor([[2.0, 2.0, -2.0]], device=device)

# Change specular color to green and change material shininess 
materials = Materials(
    device=device,
    specular_color=[[0.0, 1.0, 0.0]],
    shininess=10.0
)

# Re render the mesh, passing in keyword arguments for the modified components.
images = renderer(mesh, lights=lights, materials=materials, cameras=cameras)
In [ ]
plt.figure(figsize=(10, 10))
plt.imshow(images[0, ..., :3].cpu().numpy())
plt.axis("off");

6. バッチレンダリング¶

PyTorch3D APIのコアな設計上の選択肢の1つは、すべてのコンポーネントでバッチ入力をサポートすることです。 レンダラーと関連コンポーネントはバッチ入力を受け取り、1回のフォワードパスでバッチ出力画像をレンダリングできます。 この機能を使用して、さまざまな視点からメッシュをレンダリングします。

In [ ]
# Set batch size - this is the number of different viewpoints from which we want to render the mesh.
batch_size = 20

# Create a batch of meshes by repeating the cow mesh and associated textures. 
# Meshes has a useful `extend` method which allows us do this very easily. 
# This also extends the textures. 
meshes = mesh.extend(batch_size)

# Get a batch of viewing angles. 
elev = torch.linspace(0, 180, batch_size)
azim = torch.linspace(-180, 180, batch_size)

# All the cameras helper methods support mixed type inputs and broadcasting. So we can 
# view the camera from the same distance and specify dist=2.7 as a float,
# and then specify elevation and azimuth angles for each viewpoint as tensors. 
R, T = look_at_view_transform(dist=2.7, elev=elev, azim=azim)
cameras = FoVPerspectiveCameras(device=device, R=R, T=T)

# Move the light back in front of the cow which is facing the -z direction.
lights.location = torch.tensor([[0.0, 0.0, -3.0]], device=device)
In [ ]
# We can pass arbitrary keyword arguments to the rasterizer/shader via the renderer
# so the renderer does not need to be reinitialized if any of the settings change.
images = renderer(meshes, cameras=cameras, lights=lights)
In [ ]
image_grid(images.cpu().numpy(), rows=4, cols=5, rgb=True)

7. Plotlyによる可視化¶

メッシュを視覚化するだけであれば、微分可能なレンダラーを使用する必要はありません。代わりに、plotlyを使用してメッシュをプロットすることをサポートしています。 これらのメッシュの場合、レンダリングのテクスチャを定義するためにTexturesVertexを使用します。 plot_meshesは、各Meshesオブジェクトのトレースを含むPlotlyフィギュアを作成します。

In [ ]
verts, faces_idx, _ = load_obj(obj_filename)
faces = faces_idx.verts_idx

# Initialize each vertex to be white in color.
verts_rgb = torch.ones_like(verts)[None]  # (1, V, 3)
textures = TexturesVertex(verts_features=verts_rgb.to(device))

# Create a Meshes object
mesh = Meshes(
    verts=[verts.to(device)],   
    faces=[faces.to(device)],
    textures=textures
)

# Render the plotly figure
fig = plot_scene({
    "subplot1": {
        "cow_mesh": mesh
    }
})
fig.show()
In [ ]
# use Plotly's default colors (no texture)
mesh = Meshes(
    verts=[verts.to(device)],   
    faces=[faces.to(device)]
)

# Render the plotly figure
fig = plot_scene({
    "subplot1": {
        "cow_mesh": mesh
    }
})
fig.show()
In [ ]
# create a batch of meshes, and offset one to prevent overlap
mesh_batch = Meshes(
    verts=[verts.to(device), (verts + 2).to(device)],   
    faces=[faces.to(device), faces.to(device)]
)

# plot mesh batch in the same trace
fig = plot_scene({
    "subplot1": {
        "cow_mesh_batch": mesh_batch
    }
})
fig.show()
In [ ]
# plot batch of meshes in different traces
fig = plot_scene({
    "subplot1": {
        "cow_mesh1": mesh_batch[0],
        "cow_mesh2": mesh_batch[1]
    }
})
fig.show()
In [ ]
# plot batch of meshes in different subplots
fig = plot_scene({
    "subplot1": {
        "cow_mesh1": mesh_batch[0]
    },
    "subplot2":{
        "cow_mesh2": mesh_batch[1]
    }
})
fig.show()

バッチの場合、シーンディクショナリを自分で構築するのを避けるために、plot_batch_individuallyを使用することもできます。

In [ ]
# extend the batch to have 4 meshes
mesh_4 = mesh_batch.extend(2)

# visualize the batch in different subplots, 2 per row
fig = plot_batch_individually(mesh_4)
# we can update the figure height and width
fig.update_layout(height=1000, width=500)
fig.show()

両方の関数で、軸引数と軸の背景を変更することもできます。

In [ ]
fig2 = plot_scene({
    "cow_plot1": {
        "cows": mesh_batch
    }
},
    xaxis={"backgroundcolor":"rgb(200, 200, 230)"},
    yaxis={"backgroundcolor":"rgb(230, 200, 200)"},
    zaxis={"backgroundcolor":"rgb(200, 230, 200)"}, 
    axis_args=AxisArgs(showgrid=True))
fig2.show()
In [ ]
fig3 = plot_batch_individually(
    mesh_4, 
    ncols=2,
    subplot_titles = ["cow1", "cow2", "cow3", "cow4"], # customize subplot titles
    xaxis={"backgroundcolor":"rgb(200, 200, 230)"},
    yaxis={"backgroundcolor":"rgb(230, 200, 200)"},
    zaxis={"backgroundcolor":"rgb(200, 230, 200)"}, 
    axis_args=AxisArgs(showgrid=True))
fig3.show()

8. まとめ¶

このチュートリアルでは、objファイルからテクスチャ付きメッシュをロードする方法、Meshesと呼ばれるPyTorch3Dデータ構造を初期化する方法、ラスタライザーとシェーダーで構成されるレンダラーを設定する方法、およびレンダリングパイプラインのいくつかのコンポーネントを変更する方法を学びました。 また、Plotlyフィギュアでメッシュをレンダリングする方法も学びました。

pytorch3d
Facebook Open Source
Copyright © 2024 Meta Platforms, Inc
法律:プライバシー利用規約