-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutils.py
126 lines (108 loc) · 3.97 KB
/
utils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import torch
from pytorch3d.renderer import (
AlphaCompositor,
RasterizationSettings,
MeshRenderer,
MeshRasterizer,
PointsRasterizationSettings,
PointsRenderer,
PointsRasterizer,
HardPhongShader,
)
from pytorch3d.io import load_obj
def get_device():
"""
Checks if GPU is available and returns device accordingly.
"""
if torch.cuda.is_available():
device = torch.device("cuda:0")
else:
device = torch.device("cpu")
return device
def get_points_renderer(
image_size=512, device=None, radius=0.01, background_color=(1, 1, 1)
):
"""
Returns a Pytorch3D renderer for point clouds.
Args:
image_size (int): The rendered image size.
device (torch.device): The torch device to use (CPU or GPU). If not specified,
will automatically use GPU if available, otherwise CPU.
radius (float): The radius of the rendered point in NDC.
background_color (tuple): The background color of the rendered image.
Returns:
PointsRenderer.
"""
if device is None:
if torch.cuda.is_available():
device = torch.device("cuda:0")
else:
device = torch.device("cpu")
raster_settings = PointsRasterizationSettings(image_size=image_size, radius=radius,)
renderer = PointsRenderer(
rasterizer=PointsRasterizer(raster_settings=raster_settings),
compositor=AlphaCompositor(background_color=background_color),
)
return renderer
def get_mesh_renderer(image_size=512, lights=None, device=None):
"""
Returns a Pytorch3D Mesh Renderer.
Args:
image_size (int): The rendered image size.
lights: A default Pytorch3D lights object.
device (torch.device): The torch device to use (CPU or GPU). If not specified,
will automatically use GPU if available, otherwise CPU.
"""
if device is None:
if torch.cuda.is_available():
device = torch.device("cuda:0")
else:
device = torch.device("cpu")
raster_settings = RasterizationSettings(
image_size=image_size, blur_radius=0.0, faces_per_pixel=1,
)
renderer = MeshRenderer(
rasterizer=MeshRasterizer(raster_settings=raster_settings),
shader=HardPhongShader(device=device, lights=lights),
)
return renderer
def unproject_depth_image(image, mask, depth, camera):
"""
Unprojects a depth image into a 3D point cloud.
Args:
image (torch.Tensor): A square image to unproject (S, S, 3).
mask (torch.Tensor): A binary mask for the image (S, S).
depth (torch.Tensor): The depth map of the image (S, S).
camera: The Pytorch3D camera to render the image.
Returns:
points (torch.Tensor): The 3D points of the unprojected image (N, 3).
rgba (torch.Tensor): The rgba color values corresponding to the unprojected
points (N, 4).
"""
device = camera.device
assert image.shape[0] == image.shape[1], "Image must be square."
image_shape = image.shape[0]
ndc_pixel_coordinates = torch.linspace(1, -1, image_shape)
Y, X = torch.meshgrid(ndc_pixel_coordinates, ndc_pixel_coordinates)
xy_depth = torch.dstack([X, Y, depth])
points = camera.unproject_points(
xy_depth.to(device), in_ndc=False, from_ndc=False, world_coordinates=True,
)
points = points[mask > 0.5]
rgb = image[mask > 0.5]
rgb = rgb.to(device)
# For some reason, the Pytorch3D compositor does not apply a background color
# unless the pointcloud is RGBA.
alpha = torch.ones_like(rgb)[..., :1]
rgb = torch.cat([rgb, alpha], dim=1)
return points, rgb
def load_cow_mesh(path="data/cow_mesh.obj"):
"""
Loads vertices and faces from an obj file.
Returns:
vertices (torch.Tensor): The vertices of the mesh (N_v, 3).
faces (torch.Tensor): The faces of the mesh (N_f, 3).
"""
vertices, faces, _ = load_obj(path)
faces = faces.verts_idx
return vertices, faces