"tools/vscode:/vscode.git/clone" did not exist on "a8863510d13037ab160938993ab96cc9be4f1614"
Commit d57daa6f authored by Patrick Labatut's avatar Patrick Labatut Committed by Facebook GitHub Bot
Browse files

Address black + isort fbsource linter warnings

Summary: Address black + isort fbsource linter warnings from D20558374 (previous diff)

Reviewed By: nikhilaravi

Differential Revision: D20558373

fbshipit-source-id: d3607de4a01fb24c0d5269634563a7914bddf1c8
parent eb512ffd
# Copyright (c) Facebook, Inc. and its affiliates. All rights reserved. # Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
import unittest import unittest
import torch
import torch
from pytorch3d.renderer.compositing import ( from pytorch3d.renderer.compositing import (
alpha_composite, alpha_composite,
norm_weighted_sum, norm_weighted_sum,
...@@ -37,9 +37,7 @@ class TestAccumulatePoints(unittest.TestCase): ...@@ -37,9 +37,7 @@ class TestAccumulatePoints(unittest.TestCase):
continue continue
alpha = alphas[b, k, j, i] alpha = alphas[b, k, j, i]
output[b, c, j, i] += ( output[b, c, j, i] += features[c, n_idx] * alpha * t_alpha
features[c, n_idx] * alpha * t_alpha
)
t_alpha = (1 - alpha) * t_alpha t_alpha = (1 - alpha) * t_alpha
return output return output
...@@ -105,17 +103,13 @@ class TestAccumulatePoints(unittest.TestCase): ...@@ -105,17 +103,13 @@ class TestAccumulatePoints(unittest.TestCase):
continue continue
alpha = alphas[b, k, j, i] alpha = alphas[b, k, j, i]
output[b, c, j, i] += ( output[b, c, j, i] += features[c, n_idx] * alpha / t_alpha
features[c, n_idx] * alpha / t_alpha
)
return output return output
def test_python(self): def test_python(self):
device = torch.device("cpu") device = torch.device("cpu")
self._simple_alphacomposite( self._simple_alphacomposite(self.accumulate_alphacomposite_python, device)
self.accumulate_alphacomposite_python, device
)
self._simple_wsum(self.accumulate_weightedsum_python, device) self._simple_wsum(self.accumulate_weightedsum_python, device)
self._simple_wsumnorm(self.accumulate_weightedsumnorm_python, device) self._simple_wsumnorm(self.accumulate_weightedsumnorm_python, device)
...@@ -138,9 +132,7 @@ class TestAccumulatePoints(unittest.TestCase): ...@@ -138,9 +132,7 @@ class TestAccumulatePoints(unittest.TestCase):
self._python_vs_cpu_vs_cuda( self._python_vs_cpu_vs_cuda(
self.accumulate_weightedsumnorm_python, norm_weighted_sum self.accumulate_weightedsumnorm_python, norm_weighted_sum
) )
self._python_vs_cpu_vs_cuda( self._python_vs_cpu_vs_cuda(self.accumulate_weightedsum_python, weighted_sum)
self.accumulate_weightedsum_python, weighted_sum
)
def _python_vs_cpu_vs_cuda(self, accumulate_func_python, accumulate_func): def _python_vs_cpu_vs_cuda(self, accumulate_func_python, accumulate_func):
torch.manual_seed(231) torch.manual_seed(231)
...@@ -208,15 +200,11 @@ class TestAccumulatePoints(unittest.TestCase): ...@@ -208,15 +200,11 @@ class TestAccumulatePoints(unittest.TestCase):
grads2 = [gradsi.grad.data.clone().cpu() for gradsi in grads2] grads2 = [gradsi.grad.data.clone().cpu() for gradsi in grads2]
for i in range(0, len(grads1)): for i in range(0, len(grads1)):
self.assertTrue( self.assertTrue(torch.allclose(grads1[i].cpu(), grads2[i].cpu(), atol=1e-6))
torch.allclose(grads1[i].cpu(), grads2[i].cpu(), atol=1e-6)
)
def _simple_wsum(self, accum_func, device): def _simple_wsum(self, accum_func, device):
# Initialise variables # Initialise variables
features = torch.Tensor( features = torch.Tensor([[0.1, 0.4, 0.6, 0.9], [0.1, 0.4, 0.6, 0.9]]).to(device)
[[0.1, 0.4, 0.6, 0.9], [0.1, 0.4, 0.6, 0.9]]
).to(device)
alphas = torch.Tensor( alphas = torch.Tensor(
[ [
...@@ -285,15 +273,11 @@ class TestAccumulatePoints(unittest.TestCase): ...@@ -285,15 +273,11 @@ class TestAccumulatePoints(unittest.TestCase):
] ]
).to(device) ).to(device)
self.assertTrue( self.assertTrue(torch.allclose(result.cpu(), true_result.cpu(), rtol=1e-3))
torch.allclose(result.cpu(), true_result.cpu(), rtol=1e-3)
)
def _simple_wsumnorm(self, accum_func, device): def _simple_wsumnorm(self, accum_func, device):
# Initialise variables # Initialise variables
features = torch.Tensor( features = torch.Tensor([[0.1, 0.4, 0.6, 0.9], [0.1, 0.4, 0.6, 0.9]]).to(device)
[[0.1, 0.4, 0.6, 0.9], [0.1, 0.4, 0.6, 0.9]]
).to(device)
alphas = torch.Tensor( alphas = torch.Tensor(
[ [
...@@ -362,15 +346,11 @@ class TestAccumulatePoints(unittest.TestCase): ...@@ -362,15 +346,11 @@ class TestAccumulatePoints(unittest.TestCase):
] ]
).to(device) ).to(device)
self.assertTrue( self.assertTrue(torch.allclose(result.cpu(), true_result.cpu(), rtol=1e-3))
torch.allclose(result.cpu(), true_result.cpu(), rtol=1e-3)
)
def _simple_alphacomposite(self, accum_func, device): def _simple_alphacomposite(self, accum_func, device):
# Initialise variables # Initialise variables
features = torch.Tensor( features = torch.Tensor([[0.1, 0.4, 0.6, 0.9], [0.1, 0.4, 0.6, 0.9]]).to(device)
[[0.1, 0.4, 0.6, 0.9], [0.1, 0.4, 0.6, 0.9]]
).to(device)
alphas = torch.Tensor( alphas = torch.Tensor(
[ [
......
# Copyright (c) Facebook, Inc. and its affiliates. All rights reserved. # Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
import unittest import unittest
import torch
import torch
from pytorch3d.ops import cubify from pytorch3d.ops import cubify
...@@ -33,9 +33,7 @@ class TestCubify(unittest.TestCase): ...@@ -33,9 +33,7 @@ class TestCubify(unittest.TestCase):
# 1st-check # 1st-check
verts, faces = meshes.get_mesh_verts_faces(0) verts, faces = meshes.get_mesh_verts_faces(0)
self.assertTrue( self.assertTrue(torch.allclose(faces.max(), torch.tensor([verts.size(0) - 1])))
torch.allclose(faces.max(), torch.tensor([verts.size(0) - 1]))
)
self.assertTrue( self.assertTrue(
torch.allclose( torch.allclose(
verts, verts,
...@@ -80,9 +78,7 @@ class TestCubify(unittest.TestCase): ...@@ -80,9 +78,7 @@ class TestCubify(unittest.TestCase):
) )
# 2nd-check # 2nd-check
verts, faces = meshes.get_mesh_verts_faces(1) verts, faces = meshes.get_mesh_verts_faces(1)
self.assertTrue( self.assertTrue(torch.allclose(faces.max(), torch.tensor([verts.size(0) - 1])))
torch.allclose(faces.max(), torch.tensor([verts.size(0) - 1]))
)
self.assertTrue( self.assertTrue(
torch.allclose( torch.allclose(
verts, verts,
...@@ -275,9 +271,7 @@ class TestCubify(unittest.TestCase): ...@@ -275,9 +271,7 @@ class TestCubify(unittest.TestCase):
@staticmethod @staticmethod
def cubify_with_init(batch_size: int, V: int): def cubify_with_init(batch_size: int, V: int):
device = torch.device("cuda:0") device = torch.device("cuda:0")
voxels = torch.rand( voxels = torch.rand((batch_size, V, V, V), dtype=torch.float32, device=device)
(batch_size, V, V, V), dtype=torch.float32, device=device
)
torch.cuda.synchronize() torch.cuda.synchronize()
def convert(): def convert():
......
...@@ -2,13 +2,12 @@ ...@@ -2,13 +2,12 @@
import unittest import unittest
import torch
import torch
from common_testing import TestCaseMixin
from pytorch3d.ops import mesh_face_areas_normals from pytorch3d.ops import mesh_face_areas_normals
from pytorch3d.structures.meshes import Meshes from pytorch3d.structures.meshes import Meshes
from common_testing import TestCaseMixin
class TestFaceAreasNormals(TestCaseMixin, unittest.TestCase): class TestFaceAreasNormals(TestCaseMixin, unittest.TestCase):
def setUp(self) -> None: def setUp(self) -> None:
...@@ -27,10 +26,7 @@ class TestFaceAreasNormals(TestCaseMixin, unittest.TestCase): ...@@ -27,10 +26,7 @@ class TestFaceAreasNormals(TestCaseMixin, unittest.TestCase):
faces_list = [] faces_list = []
for _ in range(num_meshes): for _ in range(num_meshes):
verts = torch.rand( verts = torch.rand(
(num_verts, 3), (num_verts, 3), dtype=torch.float32, device=device, requires_grad=True
dtype=torch.float32,
device=device,
requires_grad=True,
) )
faces = torch.randint( faces = torch.randint(
num_verts, size=(num_faces, 3), dtype=torch.int64, device=device num_verts, size=(num_faces, 3), dtype=torch.int64, device=device
...@@ -55,9 +51,7 @@ class TestFaceAreasNormals(TestCaseMixin, unittest.TestCase): ...@@ -55,9 +51,7 @@ class TestFaceAreasNormals(TestCaseMixin, unittest.TestCase):
v02 = vertices_faces[:, 2] - vertices_faces[:, 0] v02 = vertices_faces[:, 2] - vertices_faces[:, 0]
normals = torch.cross(v01, v02, dim=1) # (F, 3) normals = torch.cross(v01, v02, dim=1) # (F, 3)
face_areas = normals.norm(dim=-1) / 2 face_areas = normals.norm(dim=-1) / 2
face_normals = torch.nn.functional.normalize( face_normals = torch.nn.functional.normalize(normals, p=2, dim=1, eps=1e-6)
normals, p=2, dim=1, eps=1e-6
)
return face_areas, face_normals return face_areas, face_normals
def _test_face_areas_normals_helper(self, device, dtype=torch.float32): def _test_face_areas_normals_helper(self, device, dtype=torch.float32):
...@@ -76,10 +70,7 @@ class TestFaceAreasNormals(TestCaseMixin, unittest.TestCase): ...@@ -76,10 +70,7 @@ class TestFaceAreasNormals(TestCaseMixin, unittest.TestCase):
verts_torch = verts.detach().clone().to(dtype) verts_torch = verts.detach().clone().to(dtype)
verts_torch.requires_grad = True verts_torch.requires_grad = True
faces_torch = faces.detach().clone() faces_torch = faces.detach().clone()
( (areas_torch, normals_torch) = TestFaceAreasNormals.face_areas_normals_python(
areas_torch,
normals_torch,
) = TestFaceAreasNormals.face_areas_normals_python(
verts_torch, faces_torch verts_torch, faces_torch
) )
self.assertClose(areas_torch, areas, atol=1e-7) self.assertClose(areas_torch, areas, atol=1e-7)
......
# Copyright (c) Facebook, Inc. and its affiliates. All rights reserved. # Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
import unittest import unittest
import torch import torch
import torch.nn as nn import torch.nn as nn
from common_testing import TestCaseMixin
from pytorch3d import _C from pytorch3d import _C
from pytorch3d.ops.graph_conv import ( from pytorch3d.ops.graph_conv import GraphConv, gather_scatter, gather_scatter_python
GraphConv,
gather_scatter,
gather_scatter_python,
)
from pytorch3d.structures.meshes import Meshes from pytorch3d.structures.meshes import Meshes
from pytorch3d.utils import ico_sphere from pytorch3d.utils import ico_sphere
from common_testing import TestCaseMixin
class TestGraphConv(TestCaseMixin, unittest.TestCase): class TestGraphConv(TestCaseMixin, unittest.TestCase):
def test_undirected(self): def test_undirected(self):
...@@ -89,8 +84,7 @@ class TestGraphConv(TestCaseMixin, unittest.TestCase): ...@@ -89,8 +84,7 @@ class TestGraphConv(TestCaseMixin, unittest.TestCase):
w1 = torch.tensor([[-1, -1, -1]], dtype=dtype) w1 = torch.tensor([[-1, -1, -1]], dtype=dtype)
expected_y = torch.tensor( expected_y = torch.tensor(
[[1 + 2 + 3 - 4 - 5 - 6 - 7 - 8 - 9], [4 + 5 + 6], [7 + 8 + 9]], [[1 + 2 + 3 - 4 - 5 - 6 - 7 - 8 - 9], [4 + 5 + 6], [7 + 8 + 9]], dtype=dtype
dtype=dtype,
) )
conv = GraphConv(3, 1, directed=True).to(dtype) conv = GraphConv(3, 1, directed=True).to(dtype)
...@@ -126,17 +120,13 @@ class TestGraphConv(TestCaseMixin, unittest.TestCase): ...@@ -126,17 +120,13 @@ class TestGraphConv(TestCaseMixin, unittest.TestCase):
def test_cpu_cuda_tensor_error(self): def test_cpu_cuda_tensor_error(self):
device = torch.device("cuda:0") device = torch.device("cuda:0")
verts = torch.tensor( verts = torch.tensor(
[[1, 2, 3], [4, 5, 6], [7, 8, 9]], [[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=torch.float32, device=device
dtype=torch.float32,
device=device,
) )
edges = torch.tensor([[0, 1], [0, 2]]) edges = torch.tensor([[0, 1], [0, 2]])
conv = GraphConv(3, 1, directed=True).to(torch.float32) conv = GraphConv(3, 1, directed=True).to(torch.float32)
with self.assertRaises(Exception) as err: with self.assertRaises(Exception) as err:
conv(verts, edges) conv(verts, edges)
self.assertTrue( self.assertTrue("tensors must be on the same device." in str(err.exception))
"tensors must be on the same device." in str(err.exception)
)
def test_gather_scatter(self): def test_gather_scatter(self):
""" """
...@@ -178,12 +168,10 @@ class TestGraphConv(TestCaseMixin, unittest.TestCase): ...@@ -178,12 +168,10 @@ class TestGraphConv(TestCaseMixin, unittest.TestCase):
backend: str = "cuda", backend: str = "cuda",
): ):
device = torch.device("cuda") if backend == "cuda" else "cpu" device = torch.device("cuda") if backend == "cuda" else "cpu"
verts_list = torch.tensor( verts_list = torch.tensor(num_verts * [[0.11, 0.22, 0.33]], device=device).view(
num_verts * [[0.11, 0.22, 0.33]], device=device
).view(-1, 3)
faces_list = torch.tensor(num_faces * [[1, 2, 3]], device=device).view(
-1, 3 -1, 3
) )
faces_list = torch.tensor(num_faces * [[1, 2, 3]], device=device).view(-1, 3)
meshes = Meshes(num_meshes * [verts_list], num_meshes * [faces_list]) meshes = Meshes(num_meshes * [verts_list], num_meshes * [faces_list])
gconv = GraphConv(gconv_dim, gconv_dim, directed=directed) gconv = GraphConv(gconv_dim, gconv_dim, directed=directed)
gconv.to(device) gconv.to(device)
...@@ -191,9 +179,7 @@ class TestGraphConv(TestCaseMixin, unittest.TestCase): ...@@ -191,9 +179,7 @@ class TestGraphConv(TestCaseMixin, unittest.TestCase):
total_verts = meshes.verts_packed().shape[0] total_verts = meshes.verts_packed().shape[0]
# Features. # Features.
x = torch.randn( x = torch.randn(total_verts, gconv_dim, device=device, requires_grad=True)
total_verts, gconv_dim, device=device, requires_grad=True
)
torch.cuda.synchronize() torch.cuda.synchronize()
def run_graph_conv(): def run_graph_conv():
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
import unittest import unittest
from itertools import product from itertools import product
import torch
import torch
from pytorch3d.ops.knn import _knn_points_idx_naive, knn_points_idx from pytorch3d.ops.knn import _knn_points_idx_naive, knn_points_idx
......
# Copyright (c) Facebook, Inc. and its affiliates. All rights reserved. # Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
import numpy as np
import unittest import unittest
import torch
import numpy as np
import torch
from common_testing import TestCaseMixin
from pytorch3d.renderer.lighting import DirectionalLights, PointLights from pytorch3d.renderer.lighting import DirectionalLights, PointLights
from pytorch3d.transforms import RotateAxisAngle from pytorch3d.transforms import RotateAxisAngle
from common_testing import TestCaseMixin
class TestLights(TestCaseMixin, unittest.TestCase): class TestLights(TestCaseMixin, unittest.TestCase):
def test_init_lights(self): def test_init_lights(self):
...@@ -56,9 +55,7 @@ class TestLights(TestCaseMixin, unittest.TestCase): ...@@ -56,9 +55,7 @@ class TestLights(TestCaseMixin, unittest.TestCase):
self.assertSeparate(new_prop, prop) self.assertSeparate(new_prop, prop)
def test_lights_accessor(self): def test_lights_accessor(self):
d_light = DirectionalLights( d_light = DirectionalLights(ambient_color=((0.0, 0.0, 0.0), (1.0, 1.0, 1.0)))
ambient_color=((0.0, 0.0, 0.0), (1.0, 1.0, 1.0))
)
p_light = PointLights(ambient_color=((0.0, 0.0, 0.0), (1.0, 1.0, 1.0))) p_light = PointLights(ambient_color=((0.0, 0.0, 0.0), (1.0, 1.0, 1.0)))
for light in [d_light, p_light]: for light in [d_light, p_light]:
# Update element # Update element
...@@ -96,14 +93,12 @@ class TestLights(TestCaseMixin, unittest.TestCase): ...@@ -96,14 +93,12 @@ class TestLights(TestCaseMixin, unittest.TestCase):
""" """
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
DirectionalLights( DirectionalLights(
ambient_color=torch.randn(10, 3), ambient_color=torch.randn(10, 3), diffuse_color=torch.randn(15, 3)
diffuse_color=torch.randn(15, 3),
) )
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
PointLights( PointLights(
ambient_color=torch.randn(10, 3), ambient_color=torch.randn(10, 3), diffuse_color=torch.randn(15, 3)
diffuse_color=torch.randn(15, 3),
) )
def test_initialize_lights_dimensions_fail(self): def test_initialize_lights_dimensions_fail(self):
...@@ -138,8 +133,7 @@ class TestDiffuseLighting(TestCaseMixin, unittest.TestCase): ...@@ -138,8 +133,7 @@ class TestDiffuseLighting(TestCaseMixin, unittest.TestCase):
normals = torch.tensor([0, 0, 1], dtype=torch.float32) normals = torch.tensor([0, 0, 1], dtype=torch.float32)
normals = normals[None, None, :] normals = normals[None, None, :]
expected_output = torch.tensor( expected_output = torch.tensor(
[1 / np.sqrt(2), 1 / np.sqrt(2), 1 / np.sqrt(2)], [1 / np.sqrt(2), 1 / np.sqrt(2), 1 / np.sqrt(2)], dtype=torch.float32
dtype=torch.float32,
) )
expected_output = expected_output.view(1, 1, 3).repeat(3, 1, 1) expected_output = expected_output.view(1, 1, 3).repeat(3, 1, 1)
light = DirectionalLights(diffuse_color=color, direction=direction) light = DirectionalLights(diffuse_color=color, direction=direction)
...@@ -169,13 +163,10 @@ class TestDiffuseLighting(TestCaseMixin, unittest.TestCase): ...@@ -169,13 +163,10 @@ class TestDiffuseLighting(TestCaseMixin, unittest.TestCase):
points = torch.tensor([0, 0, 0], dtype=torch.float32) points = torch.tensor([0, 0, 0], dtype=torch.float32)
normals = torch.tensor([0, 0, 1], dtype=torch.float32) normals = torch.tensor([0, 0, 1], dtype=torch.float32)
expected_output = torch.tensor( expected_output = torch.tensor(
[1 / np.sqrt(2), 1 / np.sqrt(2), 1 / np.sqrt(2)], [1 / np.sqrt(2), 1 / np.sqrt(2), 1 / np.sqrt(2)], dtype=torch.float32
dtype=torch.float32,
) )
expected_output = expected_output.view(-1, 1, 3) expected_output = expected_output.view(-1, 1, 3)
light = PointLights( light = PointLights(diffuse_color=color[None, :], location=location[None, :])
diffuse_color=color[None, :], location=location[None, :]
)
output_light = light.diffuse( output_light = light.diffuse(
points=points[None, None, :], normals=normals[None, None, :] points=points[None, None, :], normals=normals[None, None, :]
) )
...@@ -184,9 +175,7 @@ class TestDiffuseLighting(TestCaseMixin, unittest.TestCase): ...@@ -184,9 +175,7 @@ class TestDiffuseLighting(TestCaseMixin, unittest.TestCase):
# Change light direction to be 90 degrees apart from normal direction. # Change light direction to be 90 degrees apart from normal direction.
location = torch.tensor([0, 1, 0], dtype=torch.float32) location = torch.tensor([0, 1, 0], dtype=torch.float32)
expected_output = torch.zeros_like(expected_output) expected_output = torch.zeros_like(expected_output)
light = PointLights( light = PointLights(diffuse_color=color[None, :], location=location[None, :])
diffuse_color=color[None, :], location=location[None, :]
)
output_light = light.diffuse( output_light = light.diffuse(
points=points[None, None, :], normals=normals[None, None, :] points=points[None, None, :], normals=normals[None, None, :]
) )
...@@ -204,8 +193,7 @@ class TestDiffuseLighting(TestCaseMixin, unittest.TestCase): ...@@ -204,8 +193,7 @@ class TestDiffuseLighting(TestCaseMixin, unittest.TestCase):
) )
normals = torch.tensor([0, 0, 1], dtype=torch.float32) normals = torch.tensor([0, 0, 1], dtype=torch.float32)
expected_out = torch.tensor( expected_out = torch.tensor(
[1 / np.sqrt(2), 1 / np.sqrt(2), 1 / np.sqrt(2)], [1 / np.sqrt(2), 1 / np.sqrt(2), 1 / np.sqrt(2)], dtype=torch.float32
dtype=torch.float32,
) )
# Reshape # Reshape
...@@ -231,8 +219,7 @@ class TestDiffuseLighting(TestCaseMixin, unittest.TestCase): ...@@ -231,8 +219,7 @@ class TestDiffuseLighting(TestCaseMixin, unittest.TestCase):
) )
normals = torch.tensor([0, 0, 1], dtype=torch.float32) normals = torch.tensor([0, 0, 1], dtype=torch.float32)
expected_out = torch.tensor( expected_out = torch.tensor(
[1 / np.sqrt(2), 1 / np.sqrt(2), 1 / np.sqrt(2)], [1 / np.sqrt(2), 1 / np.sqrt(2), 1 / np.sqrt(2)], dtype=torch.float32
dtype=torch.float32,
) )
# Reshape # Reshape
...@@ -258,9 +245,7 @@ class TestDiffuseLighting(TestCaseMixin, unittest.TestCase): ...@@ -258,9 +245,7 @@ class TestDiffuseLighting(TestCaseMixin, unittest.TestCase):
device = torch.device("cuda:0") device = torch.device("cuda:0")
color = torch.tensor([1, 1, 1], dtype=torch.float32, device=device) color = torch.tensor([1, 1, 1], dtype=torch.float32, device=device)
direction = torch.tensor( direction = torch.tensor(
[0, 1 / np.sqrt(2), 1 / np.sqrt(2)], [0, 1 / np.sqrt(2), 1 / np.sqrt(2)], dtype=torch.float32, device=device
dtype=torch.float32,
device=device,
) )
normals = torch.tensor([0, 0, 1], dtype=torch.float32, device=device) normals = torch.tensor([0, 0, 1], dtype=torch.float32, device=device)
normals = normals.view(1, 1, 1, 1, 3).expand(N, H, W, K, -1) normals = normals.view(1, 1, 1, 1, 3).expand(N, H, W, K, -1)
...@@ -373,9 +358,7 @@ class TestSpecularLighting(TestCaseMixin, unittest.TestCase): ...@@ -373,9 +358,7 @@ class TestSpecularLighting(TestCaseMixin, unittest.TestCase):
normals = torch.tensor([0, 1, 0], dtype=torch.float32) normals = torch.tensor([0, 1, 0], dtype=torch.float32)
expected_output = torch.tensor([1.0, 0.0, 1.0], dtype=torch.float32) expected_output = torch.tensor([1.0, 0.0, 1.0], dtype=torch.float32)
expected_output = expected_output.view(-1, 1, 3) expected_output = expected_output.view(-1, 1, 3)
lights = PointLights( lights = PointLights(specular_color=color[None, :], location=location[None, :])
specular_color=color[None, :], location=location[None, :]
)
output_light = lights.specular( output_light = lights.specular(
points=points[None, None, :], points=points[None, None, :],
normals=normals[None, None, :], normals=normals[None, None, :],
...@@ -528,8 +511,7 @@ class TestSpecularLighting(TestCaseMixin, unittest.TestCase): ...@@ -528,8 +511,7 @@ class TestSpecularLighting(TestCaseMixin, unittest.TestCase):
mesh_to_vert_idx = torch.tensor(mesh_to_vert_idx, dtype=torch.int64) mesh_to_vert_idx = torch.tensor(mesh_to_vert_idx, dtype=torch.int64)
color = torch.tensor([[1, 1, 1], [1, 0, 1]], dtype=torch.float32) color = torch.tensor([[1, 1, 1], [1, 0, 1]], dtype=torch.float32)
direction = torch.tensor( direction = torch.tensor(
[[-1 / np.sqrt(2), 1 / np.sqrt(2), 0], [-1, 1, 0]], [[-1 / np.sqrt(2), 1 / np.sqrt(2), 0], [-1, 1, 0]], dtype=torch.float32
dtype=torch.float32,
) )
camera_position = torch.tensor( camera_position = torch.tensor(
[ [
......
# Copyright (c) Facebook, Inc. and its affiliates. All rights reserved. # Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
import unittest import unittest
import torch
from pytorch3d.renderer.materials import Materials
import torch
from common_testing import TestCaseMixin from common_testing import TestCaseMixin
from pytorch3d.renderer.materials import Materials
class TestMaterials(TestCaseMixin, unittest.TestCase): class TestMaterials(TestCaseMixin, unittest.TestCase):
...@@ -64,8 +63,7 @@ class TestMaterials(TestCaseMixin, unittest.TestCase): ...@@ -64,8 +63,7 @@ class TestMaterials(TestCaseMixin, unittest.TestCase):
""" """
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
Materials( Materials(
ambient_color=torch.randn(10, 3), ambient_color=torch.randn(10, 3), diffuse_color=torch.randn(15, 3)
diffuse_color=torch.randn(15, 3),
) )
def test_initialize_materials_dimensions_fail(self): def test_initialize_materials_dimensions_fail(self):
...@@ -80,16 +78,12 @@ class TestMaterials(TestCaseMixin, unittest.TestCase): ...@@ -80,16 +78,12 @@ class TestMaterials(TestCaseMixin, unittest.TestCase):
Materials(shininess=torch.randn(10, 2)) Materials(shininess=torch.randn(10, 2))
def test_initialize_materials_mixed_inputs(self): def test_initialize_materials_mixed_inputs(self):
mat = Materials( mat = Materials(ambient_color=torch.randn(1, 3), diffuse_color=((1, 1, 1),))
ambient_color=torch.randn(1, 3), diffuse_color=((1, 1, 1),)
)
self.assertTrue(mat.ambient_color.shape == (1, 3)) self.assertTrue(mat.ambient_color.shape == (1, 3))
self.assertTrue(mat.diffuse_color.shape == (1, 3)) self.assertTrue(mat.diffuse_color.shape == (1, 3))
def test_initialize_materials_mixed_inputs_broadcast(self): def test_initialize_materials_mixed_inputs_broadcast(self):
mat = Materials( mat = Materials(ambient_color=torch.randn(10, 3), diffuse_color=((1, 1, 1),))
ambient_color=torch.randn(10, 3), diffuse_color=((1, 1, 1),)
)
self.assertTrue(mat.ambient_color.shape == (10, 3)) self.assertTrue(mat.ambient_color.shape == (10, 3))
self.assertTrue(mat.diffuse_color.shape == (10, 3)) self.assertTrue(mat.diffuse_color.shape == (10, 3))
self.assertTrue(mat.specular_color.shape == (10, 3)) self.assertTrue(mat.specular_color.shape == (10, 3))
......
# Copyright (c) Facebook, Inc. and its affiliates. All rights reserved. # Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
import unittest import unittest
import torch
import torch
from common_testing import TestCaseMixin
from pytorch3d.loss import mesh_edge_loss from pytorch3d.loss import mesh_edge_loss
from pytorch3d.structures import Meshes from pytorch3d.structures import Meshes
from common_testing import TestCaseMixin
from test_sample_points_from_meshes import TestSamplePoints from test_sample_points_from_meshes import TestSamplePoints
...@@ -27,9 +26,7 @@ class TestMeshEdgeLoss(TestCaseMixin, unittest.TestCase): ...@@ -27,9 +26,7 @@ class TestMeshEdgeLoss(TestCaseMixin, unittest.TestCase):
mesh = Meshes(verts=verts_list, faces=faces_list) mesh = Meshes(verts=verts_list, faces=faces_list)
loss = mesh_edge_loss(mesh, target_length=target_length) loss = mesh_edge_loss(mesh, target_length=target_length)
self.assertClose( self.assertClose(loss, torch.tensor([0.0], dtype=torch.float32, device=device))
loss, torch.tensor([0.0], dtype=torch.float32, device=device)
)
self.assertTrue(loss.requires_grad) self.assertTrue(loss.requires_grad)
@staticmethod @staticmethod
...@@ -53,9 +50,7 @@ class TestMeshEdgeLoss(TestCaseMixin, unittest.TestCase): ...@@ -53,9 +50,7 @@ class TestMeshEdgeLoss(TestCaseMixin, unittest.TestCase):
num_edges = mesh_edges.size(0) num_edges = mesh_edges.size(0)
for e in range(num_edges): for e in range(num_edges):
v0, v1 = verts_edges[e, 0], verts_edges[e, 1] v0, v1 = verts_edges[e, 0], verts_edges[e, 1]
predlosses[b] += ( predlosses[b] += ((v0 - v1).norm(dim=0, p=2) - target_length) ** 2.0
(v0 - v1).norm(dim=0, p=2) - target_length
) ** 2.0
if num_edges > 0: if num_edges > 0:
predlosses[b] = predlosses[b] / num_edges predlosses[b] = predlosses[b] / num_edges
...@@ -96,12 +91,8 @@ class TestMeshEdgeLoss(TestCaseMixin, unittest.TestCase): ...@@ -96,12 +91,8 @@ class TestMeshEdgeLoss(TestCaseMixin, unittest.TestCase):
self.assertClose(loss, predloss) self.assertClose(loss, predloss)
@staticmethod @staticmethod
def mesh_edge_loss( def mesh_edge_loss(num_meshes: int = 10, max_v: int = 100, max_f: int = 300):
num_meshes: int = 10, max_v: int = 100, max_f: int = 300 meshes = TestSamplePoints.init_meshes(num_meshes, max_v, max_f, device="cuda:0")
):
meshes = TestSamplePoints.init_meshes(
num_meshes, max_v, max_f, device="cuda:0"
)
torch.cuda.synchronize() torch.cuda.synchronize()
def compute_loss(): def compute_loss():
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
import unittest import unittest
import torch
import torch
from pytorch3d.loss.mesh_laplacian_smoothing import mesh_laplacian_smoothing from pytorch3d.loss.mesh_laplacian_smoothing import mesh_laplacian_smoothing
from pytorch3d.structures.meshes import Meshes from pytorch3d.structures.meshes import Meshes
...@@ -56,9 +56,7 @@ class TestLaplacianSmoothing(unittest.TestCase): ...@@ -56,9 +56,7 @@ class TestLaplacianSmoothing(unittest.TestCase):
V = verts_packed.shape[0] V = verts_packed.shape[0]
L = torch.zeros((V, V), dtype=torch.float32, device=meshes.device) L = torch.zeros((V, V), dtype=torch.float32, device=meshes.device)
inv_areas = torch.zeros( inv_areas = torch.zeros((V, 1), dtype=torch.float32, device=meshes.device)
(V, 1), dtype=torch.float32, device=meshes.device
)
for f in faces_packed: for f in faces_packed:
v0 = verts_packed[f[0], :] v0 = verts_packed[f[0], :]
...@@ -69,9 +67,7 @@ class TestLaplacianSmoothing(unittest.TestCase): ...@@ -69,9 +67,7 @@ class TestLaplacianSmoothing(unittest.TestCase):
C = (v0 - v1).norm() C = (v0 - v1).norm()
s = 0.5 * (A + B + C) s = 0.5 * (A + B + C)
face_area = ( face_area = (s * (s - A) * (s - B) * (s - C)).clamp_(min=1e-12).sqrt()
(s * (s - A) * (s - B) * (s - C)).clamp_(min=1e-12).sqrt()
)
inv_areas[f[0]] += face_area inv_areas[f[0]] += face_area
inv_areas[f[1]] += face_area inv_areas[f[1]] += face_area
inv_areas[f[2]] += face_area inv_areas[f[2]] += face_area
...@@ -114,16 +110,13 @@ class TestLaplacianSmoothing(unittest.TestCase): ...@@ -114,16 +110,13 @@ class TestLaplacianSmoothing(unittest.TestCase):
return loss.sum() / len(meshes) return loss.sum() / len(meshes)
@staticmethod @staticmethod
def init_meshes( def init_meshes(num_meshes: int = 10, num_verts: int = 1000, num_faces: int = 3000):
num_meshes: int = 10, num_verts: int = 1000, num_faces: int = 3000
):
device = torch.device("cuda:0") device = torch.device("cuda:0")
verts_list = [] verts_list = []
faces_list = [] faces_list = []
for _ in range(num_meshes): for _ in range(num_meshes):
verts = ( verts = (
torch.rand((num_verts, 3), dtype=torch.float32, device=device) torch.rand((num_verts, 3), dtype=torch.float32, device=device) * 2.0
* 2.0
- 1.0 - 1.0
) # verts in the space of [-1, 1] ) # verts in the space of [-1, 1]
faces = torch.stack( faces = torch.stack(
...@@ -148,9 +141,7 @@ class TestLaplacianSmoothing(unittest.TestCase): ...@@ -148,9 +141,7 @@ class TestLaplacianSmoothing(unittest.TestCase):
# feats in list # feats in list
out = mesh_laplacian_smoothing(meshes, method="uniform") out = mesh_laplacian_smoothing(meshes, method="uniform")
naive_out = TestLaplacianSmoothing.laplacian_smoothing_naive_uniform( naive_out = TestLaplacianSmoothing.laplacian_smoothing_naive_uniform(meshes)
meshes
)
self.assertTrue(torch.allclose(out, naive_out)) self.assertTrue(torch.allclose(out, naive_out))
...@@ -190,9 +181,7 @@ class TestLaplacianSmoothing(unittest.TestCase): ...@@ -190,9 +181,7 @@ class TestLaplacianSmoothing(unittest.TestCase):
verts_list = [] verts_list = []
faces_list = [] faces_list = []
for _ in range(num_meshes): for _ in range(num_meshes):
verts = torch.rand( verts = torch.rand((num_verts, 3), dtype=torch.float32, device=device)
(num_verts, 3), dtype=torch.float32, device=device
)
faces = torch.randint( faces = torch.randint(
num_verts, size=(num_faces, 3), dtype=torch.int64, device=device num_verts, size=(num_faces, 3), dtype=torch.int64, device=device
) )
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
import unittest import unittest
import torch
import torch
from pytorch3d.loss.mesh_normal_consistency import mesh_normal_consistency from pytorch3d.loss.mesh_normal_consistency import mesh_normal_consistency
from pytorch3d.structures.meshes import Meshes from pytorch3d.structures.meshes import Meshes
from pytorch3d.utils.ico_sphere import ico_sphere from pytorch3d.utils.ico_sphere import ico_sphere
...@@ -33,17 +33,14 @@ class TestMeshNormalConsistency(unittest.TestCase): ...@@ -33,17 +33,14 @@ class TestMeshNormalConsistency(unittest.TestCase):
return faces return faces
@staticmethod @staticmethod
def init_meshes( def init_meshes(num_meshes: int = 10, num_verts: int = 1000, num_faces: int = 3000):
num_meshes: int = 10, num_verts: int = 1000, num_faces: int = 3000
):
device = torch.device("cuda:0") device = torch.device("cuda:0")
valid_faces = TestMeshNormalConsistency.init_faces(num_verts).to(device) valid_faces = TestMeshNormalConsistency.init_faces(num_verts).to(device)
verts_list = [] verts_list = []
faces_list = [] faces_list = []
for _ in range(num_meshes): for _ in range(num_meshes):
verts = ( verts = (
torch.rand((num_verts, 3), dtype=torch.float32, device=device) torch.rand((num_verts, 3), dtype=torch.float32, device=device) * 2.0
* 2.0
- 1.0 - 1.0
) # verts in the space of [-1, 1] ) # verts in the space of [-1, 1]
""" """
...@@ -105,8 +102,7 @@ class TestMeshNormalConsistency(unittest.TestCase): ...@@ -105,8 +102,7 @@ class TestMeshNormalConsistency(unittest.TestCase):
( (
1 1
- torch.cosine_similarity( - torch.cosine_similarity(
normals[i].view(1, 3), normals[i].view(1, 3), -normals[j].view(1, 3)
-normals[j].view(1, 3),
) )
) )
) )
...@@ -137,9 +133,7 @@ class TestMeshNormalConsistency(unittest.TestCase): ...@@ -137,9 +133,7 @@ class TestMeshNormalConsistency(unittest.TestCase):
device = torch.device("cuda:0") device = torch.device("cuda:0")
# mesh1 shown above # mesh1 shown above
verts1 = torch.rand((4, 3), dtype=torch.float32, device=device) verts1 = torch.rand((4, 3), dtype=torch.float32, device=device)
faces1 = torch.tensor( faces1 = torch.tensor([[0, 1, 2], [2, 1, 3]], dtype=torch.int64, device=device)
[[0, 1, 2], [2, 1, 3]], dtype=torch.int64, device=device
)
# mesh2 is a cuboid with 8 verts, 12 faces and 18 edges # mesh2 is a cuboid with 8 verts, 12 faces and 18 edges
verts2 = torch.tensor( verts2 = torch.tensor(
...@@ -181,9 +175,7 @@ class TestMeshNormalConsistency(unittest.TestCase): ...@@ -181,9 +175,7 @@ class TestMeshNormalConsistency(unittest.TestCase):
[[0, 1, 2], [2, 1, 3], [2, 1, 4]], dtype=torch.int64, device=device [[0, 1, 2], [2, 1, 3], [2, 1, 4]], dtype=torch.int64, device=device
) )
meshes = Meshes( meshes = Meshes(verts=[verts1, verts2, verts3], faces=[faces1, faces2, faces3])
verts=[verts1, verts2, verts3], faces=[faces1, faces2, faces3]
)
# mesh1: normal consistency computation # mesh1: normal consistency computation
n0 = (verts1[1] - verts1[2]).cross(verts1[3] - verts1[2]) n0 = (verts1[1] - verts1[2]).cross(verts1[3] - verts1[2])
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
import unittest import unittest
import torch
import torch
from pytorch3d.renderer.mesh.utils import _clip_barycentric_coordinates from pytorch3d.renderer.mesh.utils import _clip_barycentric_coordinates
......
# Copyright (c) Facebook, Inc. and its affiliates. All rights reserved. # Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
import numpy as np
import unittest import unittest
import torch
from pytorch3d.structures.meshes import Meshes
import numpy as np
import torch
from common_testing import TestCaseMixin from common_testing import TestCaseMixin
from pytorch3d.structures.meshes import Meshes
class TestMeshes(TestCaseMixin, unittest.TestCase): class TestMeshes(TestCaseMixin, unittest.TestCase):
...@@ -54,9 +53,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -54,9 +53,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
# For lists of faces and vertices, we can sample different v/f # For lists of faces and vertices, we can sample different v/f
# per mesh. # per mesh.
f = torch.randint(max_f, size=(num_meshes,), dtype=torch.int32) f = torch.randint(max_f, size=(num_meshes,), dtype=torch.int32)
v = torch.randint( v = torch.randint(3, high=max_v, size=(num_meshes,), dtype=torch.int32)
3, high=max_v, size=(num_meshes,), dtype=torch.int32
)
# Generate the actual vertices and faces. # Generate the actual vertices and faces.
for i in range(num_meshes): for i in range(num_meshes):
...@@ -90,12 +87,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -90,12 +87,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
device=device, device=device,
), ),
torch.tensor( torch.tensor(
[ [[0.1, 0.3, 0.3], [0.6, 0.7, 0.8], [0.2, 0.3, 0.4], [0.1, 0.5, 0.3]],
[0.1, 0.3, 0.3],
[0.6, 0.7, 0.8],
[0.2, 0.3, 0.4],
[0.1, 0.5, 0.3],
],
dtype=torch.float32, dtype=torch.float32,
device=device, device=device,
), ),
...@@ -113,9 +105,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -113,9 +105,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
] ]
faces = [ faces = [
torch.tensor([[0, 1, 2]], dtype=torch.int64, device=device), torch.tensor([[0, 1, 2]], dtype=torch.int64, device=device),
torch.tensor( torch.tensor([[0, 1, 2], [1, 2, 3]], dtype=torch.int64, device=device),
[[0, 1, 2], [1, 2, 3]], dtype=torch.int64, device=device
),
torch.tensor( torch.tensor(
[ [
[1, 2, 0], [1, 2, 0],
...@@ -136,12 +126,8 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -136,12 +126,8 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
mesh = TestMeshes.init_simple_mesh("cuda:0") mesh = TestMeshes.init_simple_mesh("cuda:0")
# Check that faces/verts per mesh are set in init: # Check that faces/verts per mesh are set in init:
self.assertClose( self.assertClose(mesh._num_faces_per_mesh.cpu(), torch.tensor([1, 2, 7]))
mesh._num_faces_per_mesh.cpu(), torch.tensor([1, 2, 7]) self.assertClose(mesh._num_verts_per_mesh.cpu(), torch.tensor([3, 4, 5]))
)
self.assertClose(
mesh._num_verts_per_mesh.cpu(), torch.tensor([3, 4, 5])
)
# Check computed tensors # Check computed tensors
self.assertClose( self.assertClose(
...@@ -163,8 +149,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -163,8 +149,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
mesh.mesh_to_faces_packed_first_idx().cpu(), torch.tensor([0, 1, 3]) mesh.mesh_to_faces_packed_first_idx().cpu(), torch.tensor([0, 1, 3])
) )
self.assertClose( self.assertClose(
mesh.num_edges_per_mesh().cpu(), mesh.num_edges_per_mesh().cpu(), torch.tensor([3, 5, 10], dtype=torch.int32)
torch.tensor([3, 5, 10], dtype=torch.int32),
) )
def test_simple_random_meshes(self): def test_simple_random_meshes(self):
...@@ -172,9 +157,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -172,9 +157,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
# Define the test mesh object either as a list or tensor of faces/verts. # Define the test mesh object either as a list or tensor of faces/verts.
for lists_to_tensors in (False, True): for lists_to_tensors in (False, True):
N = 10 N = 10
mesh = TestMeshes.init_mesh( mesh = TestMeshes.init_mesh(N, 100, 300, lists_to_tensors=lists_to_tensors)
N, 100, 300, lists_to_tensors=lists_to_tensors
)
verts_list = mesh.verts_list() verts_list = mesh.verts_list()
faces_list = mesh.faces_list() faces_list = mesh.faces_list()
...@@ -207,12 +190,8 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -207,12 +190,8 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
for n in range(N): for n in range(N):
v = verts_list[n].shape[0] v = verts_list[n].shape[0]
f = faces_list[n].shape[0] f = faces_list[n].shape[0]
self.assertClose( self.assertClose(verts_packed[curv : curv + v, :], verts_list[n])
verts_packed[curv : curv + v, :], verts_list[n] self.assertClose(faces_packed[curf : curf + f, :] - curv, faces_list[n])
)
self.assertClose(
faces_packed[curf : curf + f, :] - curv, faces_list[n]
)
self.assertTrue(vert_to_mesh[curv : curv + v].eq(n).all()) self.assertTrue(vert_to_mesh[curv : curv + v].eq(n).all())
self.assertTrue(face_to_mesh[curf : curf + f].eq(n).all()) self.assertTrue(face_to_mesh[curf : curf + f].eq(n).all())
self.assertTrue(mesh_to_vert[n] == curv) self.assertTrue(mesh_to_vert[n] == curv)
...@@ -232,9 +211,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -232,9 +211,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
npedges = np.concatenate((e12, e20, e01), axis=0) npedges = np.concatenate((e12, e20, e01), axis=0)
npedges = np.sort(npedges, axis=1) npedges = np.sort(npedges, axis=1)
unique_edges, unique_idx = np.unique( unique_edges, unique_idx = np.unique(npedges, return_index=True, axis=0)
npedges, return_index=True, axis=0
)
self.assertTrue(np.allclose(edges, unique_edges)) self.assertTrue(np.allclose(edges, unique_edges))
temp = face_to_mesh.cpu().numpy() temp = face_to_mesh.cpu().numpy()
temp = np.concatenate((temp, temp, temp), axis=0) temp = np.concatenate((temp, temp, temp), axis=0)
...@@ -266,13 +243,9 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -266,13 +243,9 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
v = torch.randint( v = torch.randint(
3, high=V, size=(1,), dtype=torch.int32, device=device 3, high=V, size=(1,), dtype=torch.int32, device=device
)[0] )[0]
f = torch.randint( f = torch.randint(F, size=(1,), dtype=torch.int32, device=device)[0]
F, size=(1,), dtype=torch.int32, device=device
)[0]
verts = torch.rand((v, 3), dtype=torch.float32, device=device) verts = torch.rand((v, 3), dtype=torch.float32, device=device)
faces = torch.randint( faces = torch.randint(v, size=(f, 3), dtype=torch.int64, device=device)
v, size=(f, 3), dtype=torch.int64, device=device
)
else: else:
verts = torch.tensor([], dtype=torch.float32, device=device) verts = torch.tensor([], dtype=torch.float32, device=device)
faces = torch.tensor([], dtype=torch.int64, device=device) faces = torch.tensor([], dtype=torch.int64, device=device)
...@@ -309,16 +282,12 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -309,16 +282,12 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
) )
for n in range(N): for n in range(N):
verts.append(torch.rand((V, 3), dtype=torch.float32, device=device)) verts.append(torch.rand((V, 3), dtype=torch.float32, device=device))
this_faces = torch.full( this_faces = torch.full((F, 3), -1, dtype=torch.int64, device=device)
(F, 3), -1, dtype=torch.int64, device=device
)
if valid[n]: if valid[n]:
v = torch.randint( v = torch.randint(
3, high=V, size=(1,), dtype=torch.int32, device=device 3, high=V, size=(1,), dtype=torch.int32, device=device
)[0] )[0]
f = torch.randint( f = torch.randint(F, size=(1,), dtype=torch.int32, device=device)[0]
F, size=(1,), dtype=torch.int32, device=device
)[0]
this_faces[:f, :] = torch.randint( this_faces[:f, :] = torch.randint(
v, size=(f, 3), dtype=torch.int64, device=device v, size=(f, 3), dtype=torch.int64, device=device
) )
...@@ -329,9 +298,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -329,9 +298,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
mesh = Meshes(verts=torch.stack(verts), faces=torch.stack(faces)) mesh = Meshes(verts=torch.stack(verts), faces=torch.stack(faces))
# Check verts/faces per mesh are set correctly in init. # Check verts/faces per mesh are set correctly in init.
self.assertListEqual( self.assertListEqual(mesh._num_faces_per_mesh.tolist(), num_faces.tolist())
mesh._num_faces_per_mesh.tolist(), num_faces.tolist()
)
self.assertListEqual(mesh._num_verts_per_mesh.tolist(), [V] * N) self.assertListEqual(mesh._num_verts_per_mesh.tolist(), [V] * N)
for n, (vv, ff) in enumerate(zip(mesh.verts_list(), mesh.faces_list())): for n, (vv, ff) in enumerate(zip(mesh.verts_list(), mesh.faces_list())):
...@@ -339,12 +306,8 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -339,12 +306,8 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
self.assertClose(vv, verts[n]) self.assertClose(vv, verts[n])
new_faces = [ff.clone() for ff in faces] new_faces = [ff.clone() for ff in faces]
v = torch.randint( v = torch.randint(3, high=V, size=(1,), dtype=torch.int32, device=device)[0]
3, high=V, size=(1,), dtype=torch.int32, device=device f = torch.randint(F - 10, size=(1,), dtype=torch.int32, device=device)[0]
)[0]
f = torch.randint(F - 10, size=(1,), dtype=torch.int32, device=device)[
0
]
this_faces = torch.full((F, 3), -1, dtype=torch.int64, device=device) this_faces = torch.full((F, 3), -1, dtype=torch.int64, device=device)
this_faces[10 : f + 10, :] = torch.randint( this_faces[10 : f + 10, :] = torch.randint(
v, size=(f, 3), dtype=torch.int64, device=device v, size=(f, 3), dtype=torch.int64, device=device
...@@ -376,9 +339,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -376,9 +339,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
torch.allclose(new_mesh._verts_list[0], mesh._verts_list[0]) torch.allclose(new_mesh._verts_list[0], mesh._verts_list[0])
) )
self.assertFalse( self.assertFalse(
torch.allclose( torch.allclose(mesh.num_verts_per_mesh(), new_mesh.num_verts_per_mesh())
mesh.num_verts_per_mesh(), new_mesh.num_verts_per_mesh()
)
) )
self.assertSeparate(new_mesh.verts_packed(), mesh.verts_packed()) self.assertSeparate(new_mesh.verts_packed(), mesh.verts_packed())
self.assertSeparate(new_mesh.verts_padded(), mesh.verts_padded()) self.assertSeparate(new_mesh.verts_padded(), mesh.verts_padded())
...@@ -438,9 +399,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -438,9 +399,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
mesh._compute_face_areas_normals(refresh=True) mesh._compute_face_areas_normals(refresh=True)
mesh._compute_vertex_normals(refresh=True) mesh._compute_vertex_normals(refresh=True)
deform = torch.rand( deform = torch.rand((all_v, 3), dtype=torch.float32, device=mesh.device)
(all_v, 3), dtype=torch.float32, device=mesh.device
)
# new meshes class to hold the deformed mesh # new meshes class to hold the deformed mesh
new_mesh_naive = naive_offset_verts(mesh, deform) new_mesh_naive = naive_offset_verts(mesh, deform)
...@@ -458,9 +417,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -458,9 +417,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
self.assertClose( self.assertClose(
new_mesh.verts_list()[i], new_mesh_naive.verts_list()[i] new_mesh.verts_list()[i], new_mesh_naive.verts_list()[i]
) )
self.assertClose( self.assertClose(mesh.faces_list()[i], new_mesh_naive.faces_list()[i])
mesh.faces_list()[i], new_mesh_naive.faces_list()[i]
)
self.assertClose( self.assertClose(
new_mesh.faces_list()[i], new_mesh_naive.faces_list()[i] new_mesh.faces_list()[i], new_mesh_naive.faces_list()[i]
) )
...@@ -475,21 +432,11 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -475,21 +432,11 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
) )
# check padded & packed # check padded & packed
self.assertClose( self.assertClose(new_mesh.faces_padded(), new_mesh_naive.faces_padded())
new_mesh.faces_padded(), new_mesh_naive.faces_padded() self.assertClose(new_mesh.verts_padded(), new_mesh_naive.verts_padded())
) self.assertClose(new_mesh.faces_packed(), new_mesh_naive.faces_packed())
self.assertClose( self.assertClose(new_mesh.verts_packed(), new_mesh_naive.verts_packed())
new_mesh.verts_padded(), new_mesh_naive.verts_padded() self.assertClose(new_mesh.edges_packed(), new_mesh_naive.edges_packed())
)
self.assertClose(
new_mesh.faces_packed(), new_mesh_naive.faces_packed()
)
self.assertClose(
new_mesh.verts_packed(), new_mesh_naive.verts_packed()
)
self.assertClose(
new_mesh.edges_packed(), new_mesh_naive.edges_packed()
)
self.assertClose( self.assertClose(
new_mesh.verts_packed_to_mesh_idx(), new_mesh.verts_packed_to_mesh_idx(),
new_mesh_naive.verts_packed_to_mesh_idx(), new_mesh_naive.verts_packed_to_mesh_idx(),
...@@ -499,8 +446,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -499,8 +446,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
new_mesh_naive.mesh_to_verts_packed_first_idx(), new_mesh_naive.mesh_to_verts_packed_first_idx(),
) )
self.assertClose( self.assertClose(
new_mesh.num_verts_per_mesh(), new_mesh.num_verts_per_mesh(), new_mesh_naive.num_verts_per_mesh()
new_mesh_naive.num_verts_per_mesh(),
) )
self.assertClose( self.assertClose(
new_mesh.faces_packed_to_mesh_idx(), new_mesh.faces_packed_to_mesh_idx(),
...@@ -511,8 +457,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -511,8 +457,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
new_mesh_naive.mesh_to_faces_packed_first_idx(), new_mesh_naive.mesh_to_faces_packed_first_idx(),
) )
self.assertClose( self.assertClose(
new_mesh.num_faces_per_mesh(), new_mesh.num_faces_per_mesh(), new_mesh_naive.num_faces_per_mesh()
new_mesh_naive.num_faces_per_mesh(),
) )
self.assertClose( self.assertClose(
new_mesh.edges_packed_to_mesh_idx(), new_mesh.edges_packed_to_mesh_idx(),
...@@ -527,24 +472,19 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -527,24 +472,19 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
# check face areas, normals and vertex normals # check face areas, normals and vertex normals
self.assertClose( self.assertClose(
new_mesh.verts_normals_packed(), new_mesh.verts_normals_packed(), new_mesh_naive.verts_normals_packed()
new_mesh_naive.verts_normals_packed(),
) )
self.assertClose( self.assertClose(
new_mesh.verts_normals_padded(), new_mesh.verts_normals_padded(), new_mesh_naive.verts_normals_padded()
new_mesh_naive.verts_normals_padded(),
) )
self.assertClose( self.assertClose(
new_mesh.faces_normals_packed(), new_mesh.faces_normals_packed(), new_mesh_naive.faces_normals_packed()
new_mesh_naive.faces_normals_packed(),
) )
self.assertClose( self.assertClose(
new_mesh.faces_normals_padded(), new_mesh.faces_normals_padded(), new_mesh_naive.faces_normals_padded()
new_mesh_naive.faces_normals_padded(),
) )
self.assertClose( self.assertClose(
new_mesh.faces_areas_packed(), new_mesh.faces_areas_packed(), new_mesh_naive.faces_areas_packed()
new_mesh_naive.faces_areas_packed(),
) )
def test_scale_verts(self): def test_scale_verts(self):
...@@ -579,13 +519,11 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -579,13 +519,11 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
for i in range(N): for i in range(N):
if test == "tensor": if test == "tensor":
self.assertClose( self.assertClose(
scales[i] * mesh.verts_list()[i], scales[i] * mesh.verts_list()[i], new_mesh.verts_list()[i]
new_mesh.verts_list()[i],
) )
else: else:
self.assertClose( self.assertClose(
scales * mesh.verts_list()[i], scales * mesh.verts_list()[i], new_mesh.verts_list()[i]
new_mesh.verts_list()[i],
) )
self.assertClose( self.assertClose(
new_mesh.verts_list()[i], new_mesh_naive.verts_list()[i] new_mesh.verts_list()[i], new_mesh_naive.verts_list()[i]
...@@ -607,21 +545,11 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -607,21 +545,11 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
) )
# check padded & packed # check padded & packed
self.assertClose( self.assertClose(new_mesh.faces_padded(), new_mesh_naive.faces_padded())
new_mesh.faces_padded(), new_mesh_naive.faces_padded() self.assertClose(new_mesh.verts_padded(), new_mesh_naive.verts_padded())
) self.assertClose(new_mesh.faces_packed(), new_mesh_naive.faces_packed())
self.assertClose( self.assertClose(new_mesh.verts_packed(), new_mesh_naive.verts_packed())
new_mesh.verts_padded(), new_mesh_naive.verts_padded() self.assertClose(new_mesh.edges_packed(), new_mesh_naive.edges_packed())
)
self.assertClose(
new_mesh.faces_packed(), new_mesh_naive.faces_packed()
)
self.assertClose(
new_mesh.verts_packed(), new_mesh_naive.verts_packed()
)
self.assertClose(
new_mesh.edges_packed(), new_mesh_naive.edges_packed()
)
self.assertClose( self.assertClose(
new_mesh.verts_packed_to_mesh_idx(), new_mesh.verts_packed_to_mesh_idx(),
new_mesh_naive.verts_packed_to_mesh_idx(), new_mesh_naive.verts_packed_to_mesh_idx(),
...@@ -631,8 +559,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -631,8 +559,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
new_mesh_naive.mesh_to_verts_packed_first_idx(), new_mesh_naive.mesh_to_verts_packed_first_idx(),
) )
self.assertClose( self.assertClose(
new_mesh.num_verts_per_mesh(), new_mesh.num_verts_per_mesh(), new_mesh_naive.num_verts_per_mesh()
new_mesh_naive.num_verts_per_mesh(),
) )
self.assertClose( self.assertClose(
new_mesh.faces_packed_to_mesh_idx(), new_mesh.faces_packed_to_mesh_idx(),
...@@ -643,8 +570,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -643,8 +570,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
new_mesh_naive.mesh_to_faces_packed_first_idx(), new_mesh_naive.mesh_to_faces_packed_first_idx(),
) )
self.assertClose( self.assertClose(
new_mesh.num_faces_per_mesh(), new_mesh.num_faces_per_mesh(), new_mesh_naive.num_faces_per_mesh()
new_mesh_naive.num_faces_per_mesh(),
) )
self.assertClose( self.assertClose(
new_mesh.edges_packed_to_mesh_idx(), new_mesh.edges_packed_to_mesh_idx(),
...@@ -675,8 +601,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -675,8 +601,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
new_mesh_naive.faces_normals_padded(), new_mesh_naive.faces_normals_padded(),
) )
self.assertClose( self.assertClose(
new_mesh.faces_areas_packed(), new_mesh.faces_areas_packed(), new_mesh_naive.faces_areas_packed()
new_mesh_naive.faces_areas_packed(),
) )
def test_extend_list(self): def test_extend_list(self):
...@@ -730,10 +655,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -730,10 +655,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
self.assertTrue(len(split_meshes[0]) == 2) self.assertTrue(len(split_meshes[0]) == 2)
self.assertTrue( self.assertTrue(
split_meshes[0].verts_list() split_meshes[0].verts_list()
== [ == [mesh.get_mesh_verts_faces(0)[0], mesh.get_mesh_verts_faces(1)[0]]
mesh.get_mesh_verts_faces(0)[0],
mesh.get_mesh_verts_faces(1)[0],
]
) )
self.assertTrue(len(split_meshes[1]) == 3) self.assertTrue(len(split_meshes[1]) == 3)
self.assertTrue( self.assertTrue(
...@@ -756,9 +678,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -756,9 +678,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
verts_faces = [(10, 100), (20, 200)] verts_faces = [(10, 100), (20, 200)]
for (V, F) in verts_faces: for (V, F) in verts_faces:
verts = torch.rand((V, 3), dtype=torch.float32, device=device) verts = torch.rand((V, 3), dtype=torch.float32, device=device)
faces = torch.randint( faces = torch.randint(V, size=(F, 3), dtype=torch.int64, device=device)
V, size=(F, 3), dtype=torch.int64, device=device
)
verts_list.append(verts) verts_list.append(verts)
faces_list.append(faces) faces_list.append(faces)
...@@ -782,9 +702,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -782,9 +702,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
faces_list = [] faces_list = []
for (V, F) in [(10, 100)]: for (V, F) in [(10, 100)]:
verts = torch.rand((V, 3), dtype=torch.float32, device=device) verts = torch.rand((V, 3), dtype=torch.float32, device=device)
faces = torch.randint( faces = torch.randint(V, size=(F, 3), dtype=torch.int64, device=device)
V, size=(F, 3), dtype=torch.int64, device=device
)
verts_list.append(verts) verts_list.append(verts)
faces_list.append(faces) faces_list.append(faces)
...@@ -802,9 +720,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -802,9 +720,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
verts_faces = [(10, 100), (20, 200), (30, 300)] verts_faces = [(10, 100), (20, 200), (30, 300)]
for (V, F) in verts_faces: for (V, F) in verts_faces:
verts = torch.rand((V, 3), dtype=torch.float32, device=device) verts = torch.rand((V, 3), dtype=torch.float32, device=device)
faces = torch.randint( faces = torch.randint(V, size=(F, 3), dtype=torch.int64, device=device)
V, size=(F, 3), dtype=torch.int64, device=device
)
verts_list.append(verts) verts_list.append(verts)
faces_list.append(faces) faces_list.append(faces)
...@@ -814,9 +730,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -814,9 +730,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
verts_padded = mesh.verts_padded() verts_padded = mesh.verts_padded()
verts_padded_flat = verts_padded.view(-1, 3) verts_padded_flat = verts_padded.view(-1, 3)
self.assertClose( self.assertClose(verts_padded_flat[verts_padded_to_packed_idx], verts_packed)
verts_padded_flat[verts_padded_to_packed_idx], verts_packed
)
idx = verts_padded_to_packed_idx.view(-1, 1).expand(-1, 3) idx = verts_padded_to_packed_idx.view(-1, 1).expand(-1, 3)
self.assertClose(verts_padded_flat.gather(0, idx), verts_packed) self.assertClose(verts_padded_flat.gather(0, idx), verts_packed)
...@@ -828,9 +742,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -828,9 +742,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
verts_faces = [(10, 100), (20, 200), (30, 300)] verts_faces = [(10, 100), (20, 200), (30, 300)]
for (V, F) in verts_faces: for (V, F) in verts_faces:
verts = torch.rand((V, 3), dtype=torch.float32, device=device) verts = torch.rand((V, 3), dtype=torch.float32, device=device)
faces = torch.randint( faces = torch.randint(V, size=(F, 3), dtype=torch.int64, device=device)
V, size=(F, 3), dtype=torch.int64, device=device
)
verts_list.append(verts) verts_list.append(verts)
faces_list.append(faces) faces_list.append(faces)
...@@ -1006,12 +918,10 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -1006,12 +918,10 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
verts_normals_packed = meshes.verts_normals_packed() verts_normals_packed = meshes.verts_normals_packed()
faces_normals_packed = meshes.faces_normals_packed() faces_normals_packed = meshes.faces_normals_packed()
self.assertTrue( self.assertTrue(
list(verts_normals_packed.shape) list(verts_normals_packed.shape) == [verts.shape[0] + verts2.shape[0], 3]
== [verts.shape[0] + verts2.shape[0], 3]
) )
self.assertTrue( self.assertTrue(
list(faces_normals_packed.shape) list(faces_normals_packed.shape) == [faces.shape[0] + faces2.shape[0], 3]
== [faces.shape[0] + faces2.shape[0], 3]
) )
# Single mesh where two faces share one vertex so the normal is # Single mesh where two faces share one vertex so the normal is
...@@ -1079,17 +989,12 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -1079,17 +989,12 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
# with areas > eps=1e-6 # with areas > eps=1e-6
nonzero = face_areas_cpu > 1e-6 nonzero = face_areas_cpu > 1e-6
self.assertClose( self.assertClose(
face_normals_cpu[nonzero], face_normals_cpu[nonzero], face_normals_cuda.cpu()[nonzero], atol=1e-6
face_normals_cuda.cpu()[nonzero],
atol=1e-6,
) )
@staticmethod @staticmethod
def compute_packed_with_init( def compute_packed_with_init(
num_meshes: int = 10, num_meshes: int = 10, max_v: int = 100, max_f: int = 300, device: str = "cpu"
max_v: int = 100,
max_f: int = 300,
device: str = "cpu",
): ):
mesh = TestMeshes.init_mesh(num_meshes, max_v, max_f, device=device) mesh = TestMeshes.init_mesh(num_meshes, max_v, max_f, device=device)
torch.cuda.synchronize() torch.cuda.synchronize()
...@@ -1102,10 +1007,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase): ...@@ -1102,10 +1007,7 @@ class TestMeshes(TestCaseMixin, unittest.TestCase):
@staticmethod @staticmethod
def compute_padded_with_init( def compute_padded_with_init(
num_meshes: int = 10, num_meshes: int = 10, max_v: int = 100, max_f: int = 300, device: str = "cpu"
max_v: int = 100,
max_f: int = 300,
device: str = "cpu",
): ):
mesh = TestMeshes.init_mesh(num_meshes, max_v, max_f, device=device) mesh = TestMeshes.init_mesh(num_meshes, max_v, max_f, device=device)
torch.cuda.synchronize() torch.cuda.synchronize()
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
import unittest import unittest
from itertools import product from itertools import product
import torch
import torch
from pytorch3d import _C from pytorch3d import _C
...@@ -33,9 +33,7 @@ class TestNearestNeighborPoints(unittest.TestCase): ...@@ -33,9 +33,7 @@ class TestNearestNeighborPoints(unittest.TestCase):
# to the cpp or cuda versions of the function # to the cpp or cuda versions of the function
# depending on the input type. # depending on the input type.
idx1 = _C.nn_points_idx(x, y) idx1 = _C.nn_points_idx(x, y)
idx2 = TestNearestNeighborPoints.nn_points_idx_naive( idx2 = TestNearestNeighborPoints.nn_points_idx_naive(x, y)
x, y
)
self.assertTrue(idx1.size(1) == P1) self.assertTrue(idx1.size(1) == P1)
self.assertTrue(torch.all(idx1 == idx2)) self.assertTrue(torch.all(idx1 == idx2))
......
...@@ -4,14 +4,13 @@ import os ...@@ -4,14 +4,13 @@ import os
import unittest import unittest
from io import StringIO from io import StringIO
from pathlib import Path from pathlib import Path
import torch
import torch
from common_testing import TestCaseMixin
from pytorch3d.io import load_obj, load_objs_as_meshes, save_obj from pytorch3d.io import load_obj, load_objs_as_meshes, save_obj
from pytorch3d.structures import Meshes, Textures, join_meshes from pytorch3d.structures import Meshes, Textures, join_meshes
from pytorch3d.utils import torus from pytorch3d.utils import torus
from common_testing import TestCaseMixin
class TestMeshObjIO(TestCaseMixin, unittest.TestCase): class TestMeshObjIO(TestCaseMixin, unittest.TestCase):
def test_load_obj_simple(self): def test_load_obj_simple(self):
...@@ -34,12 +33,7 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase): ...@@ -34,12 +33,7 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase):
tex_maps = aux.texture_images tex_maps = aux.texture_images
expected_verts = torch.tensor( expected_verts = torch.tensor(
[ [[0.1, 0.2, 0.3], [0.2, 0.3, 0.4], [0.3, 0.4, 0.5], [0.4, 0.5, 0.6]],
[0.1, 0.2, 0.3],
[0.2, 0.3, 0.4],
[0.3, 0.4, 0.5],
[0.4, 0.5, 0.6],
],
dtype=torch.float32, dtype=torch.float32,
) )
expected_faces = torch.tensor( expected_faces = torch.tensor(
...@@ -124,12 +118,8 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase): ...@@ -124,12 +118,8 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase):
[[0.749279, 0.501284], [0.999110, 0.501077], [0.999455, 0.750380]], [[0.749279, 0.501284], [0.999110, 0.501077], [0.999455, 0.750380]],
dtype=torch.float32, dtype=torch.float32,
) )
expected_faces_normals_idx = torch.tensor( expected_faces_normals_idx = torch.tensor([[1, 1, 1]], dtype=torch.int64)
[[1, 1, 1]], dtype=torch.int64 expected_faces_textures_idx = torch.tensor([[0, 0, 1]], dtype=torch.int64)
)
expected_faces_textures_idx = torch.tensor(
[[0, 0, 1]], dtype=torch.int64
)
self.assertTrue(torch.all(verts == expected_verts)) self.assertTrue(torch.all(verts == expected_verts))
self.assertTrue(torch.all(faces.verts_idx == expected_faces)) self.assertTrue(torch.all(faces.verts_idx == expected_faces))
...@@ -153,23 +143,13 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase): ...@@ -153,23 +143,13 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase):
] ]
) )
obj_file = StringIO(obj_file) obj_file = StringIO(obj_file)
expected_faces_normals_idx = torch.tensor( expected_faces_normals_idx = torch.tensor([[0, 0, 1]], dtype=torch.int64)
[[0, 0, 1]], dtype=torch.int64
)
expected_normals = torch.tensor( expected_normals = torch.tensor(
[ [[0.000000, 0.000000, -1.000000], [-1.000000, -0.000000, -0.000000]],
[0.000000, 0.000000, -1.000000],
[-1.000000, -0.000000, -0.000000],
],
dtype=torch.float32, dtype=torch.float32,
) )
expected_verts = torch.tensor( expected_verts = torch.tensor(
[ [[0.1, 0.2, 0.3], [0.2, 0.3, 0.4], [0.3, 0.4, 0.5], [0.4, 0.5, 0.6]],
[0.1, 0.2, 0.3],
[0.2, 0.3, 0.4],
[0.3, 0.4, 0.5],
[0.4, 0.5, 0.6],
],
dtype=torch.float32, dtype=torch.float32,
) )
verts, faces, aux = load_obj(obj_file) verts, faces, aux = load_obj(obj_file)
...@@ -198,19 +178,12 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase): ...@@ -198,19 +178,12 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase):
] ]
) )
obj_file = StringIO(obj_file) obj_file = StringIO(obj_file)
expected_faces_textures_idx = torch.tensor( expected_faces_textures_idx = torch.tensor([[0, 0, 1]], dtype=torch.int64)
[[0, 0, 1]], dtype=torch.int64
)
expected_textures = torch.tensor( expected_textures = torch.tensor(
[[0.999110, 0.501077], [0.999455, 0.750380]], dtype=torch.float32 [[0.999110, 0.501077], [0.999455, 0.750380]], dtype=torch.float32
) )
expected_verts = torch.tensor( expected_verts = torch.tensor(
[ [[0.1, 0.2, 0.3], [0.2, 0.3, 0.4], [0.3, 0.4, 0.5], [0.4, 0.5, 0.6]],
[0.1, 0.2, 0.3],
[0.2, 0.3, 0.4],
[0.3, 0.4, 0.5],
[0.4, 0.5, 0.6],
],
dtype=torch.float32, dtype=torch.float32,
) )
verts, faces, aux = load_obj(obj_file) verts, faces, aux = load_obj(obj_file)
...@@ -257,9 +230,7 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase): ...@@ -257,9 +230,7 @@ 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( self.assertTrue("Vertex properties are inconsistent" in str(err.exception))
"Vertex properties are inconsistent" in str(err.exception)
)
def test_load_obj_error_too_many_vertex_properties(self): def test_load_obj_error_too_many_vertex_properties(self):
obj_file = "\n".join(["f 2/1/1/3"]) obj_file = "\n".join(["f 2/1/1/3"])
...@@ -267,9 +238,7 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase): ...@@ -267,9 +238,7 @@ 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( self.assertTrue("Face vertices can ony have 3 properties" in str(err.exception))
"Face vertices can ony 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(
...@@ -320,7 +289,9 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase): ...@@ -320,7 +289,9 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase):
verts = torch.FloatTensor([[0.1, 0.2, 0.3, 0.4]]) # (V, 4) verts = torch.FloatTensor([[0.1, 0.2, 0.3, 0.4]]) # (V, 4)
faces = torch.LongTensor([[0, 1, 2]]) faces = torch.LongTensor([[0, 1, 2]])
save_obj(StringIO(), verts, faces) save_obj(StringIO(), verts, faces)
expected_message = "Argument 'verts' should either be empty or of shape (num_verts, 3)." expected_message = (
"Argument 'verts' should either be empty or of shape (num_verts, 3)."
)
self.assertTrue(expected_message, error.exception) self.assertTrue(expected_message, error.exception)
# Invalid faces shape # Invalid faces shape
...@@ -328,7 +299,9 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase): ...@@ -328,7 +299,9 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase):
verts = torch.FloatTensor([[0.1, 0.2, 0.3]]) verts = torch.FloatTensor([[0.1, 0.2, 0.3]])
faces = torch.LongTensor([[0, 1, 2, 3]]) # (F, 4) faces = torch.LongTensor([[0, 1, 2, 3]]) # (F, 4)
save_obj(StringIO(), verts, faces) save_obj(StringIO(), verts, faces)
expected_message = "Argument 'faces' should either be empty or of shape (num_faces, 3)." expected_message = (
"Argument 'faces' should either be empty or of shape (num_faces, 3)."
)
self.assertTrue(expected_message, error.exception) self.assertTrue(expected_message, error.exception)
def test_save_obj_invalid_indices(self): def test_save_obj_invalid_indices(self):
...@@ -395,12 +368,7 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase): ...@@ -395,12 +368,7 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase):
def test_save_obj(self): def test_save_obj(self):
verts = torch.tensor( verts = torch.tensor(
[ [[0.01, 0.2, 0.301], [0.2, 0.03, 0.408], [0.3, 0.4, 0.05], [0.6, 0.7, 0.8]],
[0.01, 0.2, 0.301],
[0.2, 0.03, 0.408],
[0.3, 0.4, 0.05],
[0.6, 0.7, 0.8],
],
dtype=torch.float32, dtype=torch.float32,
) )
faces = torch.tensor( faces = torch.tensor(
...@@ -424,9 +392,7 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase): ...@@ -424,9 +392,7 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase):
self.assertEqual(actual_file, expected_file) self.assertEqual(actual_file, expected_file)
def test_load_mtl(self): def test_load_mtl(self):
DATA_DIR = ( DATA_DIR = Path(__file__).resolve().parent.parent / "docs/tutorials/data"
Path(__file__).resolve().parent.parent / "docs/tutorials/data"
)
obj_filename = "cow_mesh/cow.obj" obj_filename = "cow_mesh/cow.obj"
filename = os.path.join(DATA_DIR, obj_filename) filename = os.path.join(DATA_DIR, obj_filename)
verts, faces, aux = load_obj(filename) verts, faces, aux = load_obj(filename)
...@@ -452,19 +418,13 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase): ...@@ -452,19 +418,13 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase):
# Check all keys and values in dictionary are the same. # Check all keys and values in dictionary are the same.
for n1, n2 in zip(materials.keys(), expected_materials.keys()): for n1, n2 in zip(materials.keys(), expected_materials.keys()):
self.assertTrue(n1 == n2) self.assertTrue(n1 == n2)
for k1, k2 in zip( for k1, k2 in zip(materials[n1].keys(), expected_materials[n2].keys()):
materials[n1].keys(), expected_materials[n2].keys()
):
self.assertTrue( self.assertTrue(
torch.allclose( torch.allclose(materials[n1][k1], expected_materials[n2][k2])
materials[n1][k1], expected_materials[n2][k2]
)
) )
def test_load_mtl_noload(self): def test_load_mtl_noload(self):
DATA_DIR = ( DATA_DIR = Path(__file__).resolve().parent.parent / "docs/tutorials/data"
Path(__file__).resolve().parent.parent / "docs/tutorials/data"
)
obj_filename = "cow_mesh/cow.obj" obj_filename = "cow_mesh/cow.obj"
filename = os.path.join(DATA_DIR, obj_filename) filename = os.path.join(DATA_DIR, obj_filename)
verts, faces, aux = load_obj(filename, load_textures=False) verts, faces, aux = load_obj(filename, load_textures=False)
...@@ -490,12 +450,7 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase): ...@@ -490,12 +450,7 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase):
verts, faces, aux = load_obj(obj_file) verts, faces, aux = load_obj(obj_file)
expected_verts = torch.tensor( expected_verts = torch.tensor(
[ [[0.1, 0.2, 0.3], [0.2, 0.3, 0.4], [0.3, 0.4, 0.5], [0.4, 0.5, 0.6]],
[0.1, 0.2, 0.3],
[0.2, 0.3, 0.4],
[0.3, 0.4, 0.5],
[0.4, 0.5, 0.6],
],
dtype=torch.float32, dtype=torch.float32,
) )
expected_faces = torch.tensor([[0, 1, 2], [0, 1, 3]], dtype=torch.int64) expected_faces = torch.tensor([[0, 1, 2], [0, 1, 3]], dtype=torch.int64)
...@@ -514,12 +469,7 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase): ...@@ -514,12 +469,7 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase):
verts, faces, aux = load_obj(filename) verts, faces, aux = load_obj(filename)
expected_verts = torch.tensor( expected_verts = torch.tensor(
[ [[0.1, 0.2, 0.3], [0.2, 0.3, 0.4], [0.3, 0.4, 0.5], [0.4, 0.5, 0.6]],
[0.1, 0.2, 0.3],
[0.2, 0.3, 0.4],
[0.3, 0.4, 0.5],
[0.4, 0.5, 0.6],
],
dtype=torch.float32, dtype=torch.float32,
) )
expected_faces = torch.tensor([[0, 1, 2], [0, 1, 3]], dtype=torch.int64) expected_faces = torch.tensor([[0, 1, 2], [0, 1, 3]], dtype=torch.int64)
...@@ -533,12 +483,7 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase): ...@@ -533,12 +483,7 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase):
verts, faces, aux = load_obj(filename, load_textures=False) verts, faces, aux = load_obj(filename, load_textures=False)
expected_verts = torch.tensor( expected_verts = torch.tensor(
[ [[0.1, 0.2, 0.3], [0.2, 0.3, 0.4], [0.3, 0.4, 0.5], [0.4, 0.5, 0.6]],
[0.1, 0.2, 0.3],
[0.2, 0.3, 0.4],
[0.3, 0.4, 0.5],
[0.4, 0.5, 0.6],
],
dtype=torch.float32, dtype=torch.float32,
) )
expected_faces = torch.tensor([[0, 1, 2], [0, 1, 3]], dtype=torch.int64) expected_faces = torch.tensor([[0, 1, 2], [0, 1, 3]], dtype=torch.int64)
...@@ -555,12 +500,7 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase): ...@@ -555,12 +500,7 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase):
verts, faces, aux = load_obj(filename) verts, faces, aux = load_obj(filename)
expected_verts = torch.tensor( expected_verts = torch.tensor(
[ [[0.1, 0.2, 0.3], [0.2, 0.3, 0.4], [0.3, 0.4, 0.5], [0.4, 0.5, 0.6]],
[0.1, 0.2, 0.3],
[0.2, 0.3, 0.4],
[0.3, 0.4, 0.5],
[0.4, 0.5, 0.6],
],
dtype=torch.float32, dtype=torch.float32,
) )
expected_faces = torch.tensor([[0, 1, 2], [0, 1, 3]], dtype=torch.int64) expected_faces = torch.tensor([[0, 1, 2], [0, 1, 3]], dtype=torch.int64)
...@@ -574,12 +514,7 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase): ...@@ -574,12 +514,7 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase):
verts, faces, aux = load_obj(filename, load_textures=False) verts, faces, aux = load_obj(filename, load_textures=False)
expected_verts = torch.tensor( expected_verts = torch.tensor(
[ [[0.1, 0.2, 0.3], [0.2, 0.3, 0.4], [0.3, 0.4, 0.5], [0.4, 0.5, 0.6]],
[0.1, 0.2, 0.3],
[0.2, 0.3, 0.4],
[0.3, 0.4, 0.5],
[0.4, 0.5, 0.6],
],
dtype=torch.float32, dtype=torch.float32,
) )
expected_faces = torch.tensor([[0, 1, 2], [0, 1, 3]], dtype=torch.int64) expected_faces = torch.tensor([[0, 1, 2], [0, 1, 3]], dtype=torch.int64)
...@@ -607,33 +542,24 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase): ...@@ -607,33 +542,24 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase):
check_item(mesh.verts_padded(), mesh3.verts_padded()) check_item(mesh.verts_padded(), mesh3.verts_padded())
check_item(mesh.faces_padded(), mesh3.faces_padded()) check_item(mesh.faces_padded(), mesh3.faces_padded())
if mesh.textures is not None: if mesh.textures is not None:
check_item(mesh.textures.maps_padded(), mesh3.textures.maps_padded())
check_item( check_item(
mesh.textures.maps_padded(), mesh3.textures.maps_padded() mesh.textures.faces_uvs_padded(), mesh3.textures.faces_uvs_padded()
) )
check_item( check_item(
mesh.textures.faces_uvs_padded(), mesh.textures.verts_uvs_padded(), mesh3.textures.verts_uvs_padded()
mesh3.textures.faces_uvs_padded(),
) )
check_item( check_item(
mesh.textures.verts_uvs_padded(), mesh.textures.verts_rgb_padded(), mesh3.textures.verts_rgb_padded()
mesh3.textures.verts_uvs_padded(),
)
check_item(
mesh.textures.verts_rgb_padded(),
mesh3.textures.verts_rgb_padded(),
) )
DATA_DIR = ( DATA_DIR = Path(__file__).resolve().parent.parent / "docs/tutorials/data"
Path(__file__).resolve().parent.parent / "docs/tutorials/data"
)
obj_filename = DATA_DIR / "cow_mesh/cow.obj" obj_filename = DATA_DIR / "cow_mesh/cow.obj"
mesh = load_objs_as_meshes([obj_filename]) mesh = load_objs_as_meshes([obj_filename])
mesh3 = load_objs_as_meshes([obj_filename, obj_filename, obj_filename]) mesh3 = load_objs_as_meshes([obj_filename, obj_filename, obj_filename])
check_triple(mesh, mesh3) check_triple(mesh, mesh3)
self.assertTupleEqual( self.assertTupleEqual(mesh.textures.maps_padded().shape, (1, 1024, 1024, 3))
mesh.textures.maps_padded().shape, (1, 1024, 1024, 3)
)
mesh_notex = load_objs_as_meshes([obj_filename], load_textures=False) mesh_notex = load_objs_as_meshes([obj_filename], load_textures=False)
mesh3_notex = load_objs_as_meshes( mesh3_notex = load_objs_as_meshes(
...@@ -655,9 +581,7 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase): ...@@ -655,9 +581,7 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase):
teapot_obj = DATA_DIR / "teapot.obj" teapot_obj = DATA_DIR / "teapot.obj"
mesh_teapot = load_objs_as_meshes([teapot_obj]) mesh_teapot = load_objs_as_meshes([teapot_obj])
teapot_verts, teapot_faces = mesh_teapot.get_mesh_verts_faces(0) teapot_verts, teapot_faces = mesh_teapot.get_mesh_verts_faces(0)
mix_mesh = load_objs_as_meshes( mix_mesh = load_objs_as_meshes([obj_filename, teapot_obj], load_textures=False)
[obj_filename, teapot_obj], load_textures=False
)
self.assertEqual(len(mix_mesh), 2) self.assertEqual(len(mix_mesh), 2)
self.assertClose(mix_mesh.verts_list()[0], mesh.verts_list()[0]) self.assertClose(mix_mesh.verts_list()[0], mesh.verts_list()[0])
self.assertClose(mix_mesh.faces_list()[0], mesh.faces_list()[0]) self.assertClose(mix_mesh.faces_list()[0], mesh.faces_list()[0])
...@@ -671,15 +595,11 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase): ...@@ -671,15 +595,11 @@ class TestMeshObjIO(TestCaseMixin, unittest.TestCase):
self.assertClose(cow3_tea.faces_list()[3], mesh_teapot.faces_list()[0]) self.assertClose(cow3_tea.faces_list()[3], mesh_teapot.faces_list()[0])
@staticmethod @staticmethod
def _bm_save_obj( def _bm_save_obj(verts: torch.Tensor, faces: torch.Tensor, decimal_places: int):
verts: torch.Tensor, faces: torch.Tensor, decimal_places: int
):
return lambda: save_obj(StringIO(), verts, faces, decimal_places) return lambda: save_obj(StringIO(), verts, faces, decimal_places)
@staticmethod @staticmethod
def _bm_load_obj( def _bm_load_obj(verts: torch.Tensor, faces: torch.Tensor, decimal_places: int):
verts: torch.Tensor, faces: torch.Tensor, decimal_places: int
):
f = StringIO() f = StringIO()
save_obj(f, verts, faces, decimal_places) save_obj(f, verts, faces, decimal_places)
s = f.getvalue() s = f.getvalue()
......
# Copyright (c) Facebook, Inc. and its affiliates. All rights reserved. # Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
import unittest import unittest
import torch
import torch
from common_testing import TestCaseMixin
from pytorch3d.ops import packed_to_padded, padded_to_packed from pytorch3d.ops import packed_to_padded, padded_to_packed
from pytorch3d.structures.meshes import Meshes from pytorch3d.structures.meshes import Meshes
from common_testing import TestCaseMixin
class TestPackedToPadded(TestCaseMixin, unittest.TestCase): class TestPackedToPadded(TestCaseMixin, unittest.TestCase):
def setUp(self) -> None: def setUp(self) -> None:
...@@ -25,9 +24,7 @@ class TestPackedToPadded(TestCaseMixin, unittest.TestCase): ...@@ -25,9 +24,7 @@ class TestPackedToPadded(TestCaseMixin, unittest.TestCase):
verts_list = [] verts_list = []
faces_list = [] faces_list = []
for _ in range(num_meshes): for _ in range(num_meshes):
verts = torch.rand( verts = torch.rand((num_verts, 3), dtype=torch.float32, device=device)
(num_verts, 3), dtype=torch.float32, device=device
)
faces = torch.randint( faces = torch.randint(
num_verts, size=(num_faces, 3), dtype=torch.int64, device=device num_verts, size=(num_faces, 3), dtype=torch.int64, device=device
) )
...@@ -47,9 +44,7 @@ class TestPackedToPadded(TestCaseMixin, unittest.TestCase): ...@@ -47,9 +44,7 @@ class TestPackedToPadded(TestCaseMixin, unittest.TestCase):
if D == 0: if D == 0:
inputs_padded = torch.zeros((num_meshes, max_size), device=device) inputs_padded = torch.zeros((num_meshes, max_size), device=device)
else: else:
inputs_padded = torch.zeros( inputs_padded = torch.zeros((num_meshes, max_size, D), device=device)
(num_meshes, max_size, D), device=device
)
for m in range(num_meshes): for m in range(num_meshes):
s = first_idxs[m] s = first_idxs[m]
if m == num_meshes - 1: if m == num_meshes - 1:
...@@ -92,13 +87,9 @@ class TestPackedToPadded(TestCaseMixin, unittest.TestCase): ...@@ -92,13 +87,9 @@ class TestPackedToPadded(TestCaseMixin, unittest.TestCase):
max_faces = meshes.num_faces_per_mesh().max().item() max_faces = meshes.num_faces_per_mesh().max().item()
if D == 0: if D == 0:
values = torch.rand( values = torch.rand((faces.shape[0],), device=device, requires_grad=True)
(faces.shape[0],), device=device, requires_grad=True
)
else: else:
values = torch.rand( values = torch.rand((faces.shape[0], D), device=device, requires_grad=True)
(faces.shape[0], D), device=device, requires_grad=True
)
values_torch = values.detach().clone() values_torch = values.detach().clone()
values_torch.requires_grad = True values_torch.requires_grad = True
values_padded = packed_to_padded( values_padded = packed_to_padded(
...@@ -120,10 +111,7 @@ class TestPackedToPadded(TestCaseMixin, unittest.TestCase): ...@@ -120,10 +111,7 @@ class TestPackedToPadded(TestCaseMixin, unittest.TestCase):
values_padded_torch.backward(grad_inputs) values_padded_torch.backward(grad_inputs)
grad_outputs_torch1 = values_torch.grad grad_outputs_torch1 = values_torch.grad
grad_outputs_torch2 = TestPackedToPadded.padded_to_packed_python( grad_outputs_torch2 = TestPackedToPadded.padded_to_packed_python(
grad_inputs, grad_inputs, mesh_to_faces_packed_first_idx, values.size(0), device=device
mesh_to_faces_packed_first_idx,
values.size(0),
device=device,
) )
self.assertClose(grad_outputs, grad_outputs_torch1) self.assertClose(grad_outputs, grad_outputs_torch1)
self.assertClose(grad_outputs, grad_outputs_torch2) self.assertClose(grad_outputs, grad_outputs_torch2)
...@@ -165,9 +153,7 @@ class TestPackedToPadded(TestCaseMixin, unittest.TestCase): ...@@ -165,9 +153,7 @@ class TestPackedToPadded(TestCaseMixin, unittest.TestCase):
values_torch = values.detach().clone() values_torch = values.detach().clone()
values_torch.requires_grad = True values_torch.requires_grad = True
values_packed = padded_to_packed( values_packed = padded_to_packed(
values, values, mesh_to_faces_packed_first_idx, num_faces_per_mesh.sum().item()
mesh_to_faces_packed_first_idx,
num_faces_per_mesh.sum().item(),
) )
values_packed_torch = TestPackedToPadded.padded_to_packed_python( values_packed_torch = TestPackedToPadded.padded_to_packed_python(
values_torch, values_torch,
...@@ -180,9 +166,7 @@ class TestPackedToPadded(TestCaseMixin, unittest.TestCase): ...@@ -180,9 +166,7 @@ class TestPackedToPadded(TestCaseMixin, unittest.TestCase):
# check backward # check backward
if D == 0: if D == 0:
grad_inputs = torch.rand( grad_inputs = torch.rand((num_faces_per_mesh.sum().item()), device=device)
(num_faces_per_mesh.sum().item()), device=device
)
else: else:
grad_inputs = torch.rand( grad_inputs = torch.rand(
(num_faces_per_mesh.sum().item(), D), device=device (num_faces_per_mesh.sum().item(), D), device=device
...@@ -192,10 +176,7 @@ class TestPackedToPadded(TestCaseMixin, unittest.TestCase): ...@@ -192,10 +176,7 @@ class TestPackedToPadded(TestCaseMixin, unittest.TestCase):
values_packed_torch.backward(grad_inputs) values_packed_torch.backward(grad_inputs)
grad_outputs_torch1 = values_torch.grad grad_outputs_torch1 = values_torch.grad
grad_outputs_torch2 = TestPackedToPadded.packed_to_padded_python( grad_outputs_torch2 = TestPackedToPadded.packed_to_padded_python(
grad_inputs, grad_inputs, mesh_to_faces_packed_first_idx, values.size(1), device=device
mesh_to_faces_packed_first_idx,
values.size(1),
device=device,
) )
self.assertClose(grad_outputs, grad_outputs_torch1) self.assertClose(grad_outputs, grad_outputs_torch1)
self.assertClose(grad_outputs, grad_outputs_torch2) self.assertClose(grad_outputs, grad_outputs_torch2)
...@@ -219,34 +200,24 @@ class TestPackedToPadded(TestCaseMixin, unittest.TestCase): ...@@ -219,34 +200,24 @@ class TestPackedToPadded(TestCaseMixin, unittest.TestCase):
self._test_padded_to_packed_helper(16, "cuda:0") self._test_padded_to_packed_helper(16, "cuda:0")
def test_invalid_inputs_shapes(self, device="cuda:0"): def test_invalid_inputs_shapes(self, device="cuda:0"):
with self.assertRaisesRegex( with self.assertRaisesRegex(ValueError, "input can only be 2-dimensional."):
ValueError, "input can only be 2-dimensional."
):
values = torch.rand((100, 50, 2), device=device) values = torch.rand((100, 50, 2), device=device)
first_idxs = torch.tensor([0, 80], dtype=torch.int64, device=device) first_idxs = torch.tensor([0, 80], dtype=torch.int64, device=device)
packed_to_padded(values, first_idxs, 100) packed_to_padded(values, first_idxs, 100)
with self.assertRaisesRegex( with self.assertRaisesRegex(ValueError, "input can only be 3-dimensional."):
ValueError, "input can only be 3-dimensional."
):
values = torch.rand((100,), device=device) values = torch.rand((100,), device=device)
first_idxs = torch.tensor([0, 80], dtype=torch.int64, device=device) first_idxs = torch.tensor([0, 80], dtype=torch.int64, device=device)
padded_to_packed(values, first_idxs, 20) padded_to_packed(values, first_idxs, 20)
with self.assertRaisesRegex( with self.assertRaisesRegex(ValueError, "input can only be 3-dimensional."):
ValueError, "input can only be 3-dimensional."
):
values = torch.rand((100, 50, 2, 2), device=device) values = torch.rand((100, 50, 2, 2), device=device)
first_idxs = torch.tensor([0, 80], dtype=torch.int64, device=device) first_idxs = torch.tensor([0, 80], dtype=torch.int64, device=device)
padded_to_packed(values, first_idxs, 20) padded_to_packed(values, first_idxs, 20)
@staticmethod @staticmethod
def packed_to_padded_with_init( def packed_to_padded_with_init(
num_meshes: int, num_meshes: int, num_verts: int, num_faces: int, num_d: int, device: str = "cpu"
num_verts: int,
num_faces: int,
num_d: int,
device: str = "cpu",
): ):
meshes = TestPackedToPadded.init_meshes( meshes = TestPackedToPadded.init_meshes(
num_meshes, num_verts, num_faces, device num_meshes, num_verts, num_faces, device
...@@ -268,11 +239,7 @@ class TestPackedToPadded(TestCaseMixin, unittest.TestCase): ...@@ -268,11 +239,7 @@ class TestPackedToPadded(TestCaseMixin, unittest.TestCase):
@staticmethod @staticmethod
def packed_to_padded_with_init_torch( def packed_to_padded_with_init_torch(
num_meshes: int, num_meshes: int, num_verts: int, num_faces: int, num_d: int, device: str = "cpu"
num_verts: int,
num_faces: int,
num_d: int,
device: str = "cpu",
): ):
meshes = TestPackedToPadded.init_meshes( meshes = TestPackedToPadded.init_meshes(
num_meshes, num_verts, num_faces, device num_meshes, num_verts, num_faces, device
......
...@@ -3,13 +3,12 @@ ...@@ -3,13 +3,12 @@
import struct import struct
import unittest import unittest
from io import BytesIO, StringIO from io import BytesIO, StringIO
import torch
import torch
from common_testing import TestCaseMixin
from pytorch3d.io.ply_io import _load_ply_raw, load_ply, save_ply from pytorch3d.io.ply_io import _load_ply_raw, load_ply, save_ply
from pytorch3d.utils import torus from pytorch3d.utils import torus
from common_testing import TestCaseMixin
class TestMeshPlyIO(TestCaseMixin, unittest.TestCase): class TestMeshPlyIO(TestCaseMixin, unittest.TestCase):
def test_raw_load_simple_ascii(self): def test_raw_load_simple_ascii(self):
...@@ -155,14 +154,7 @@ class TestMeshPlyIO(TestCaseMixin, unittest.TestCase): ...@@ -155,14 +154,7 @@ class TestMeshPlyIO(TestCaseMixin, unittest.TestCase):
def test_load_simple_binary(self): def test_load_simple_binary(self):
for big_endian in [True, False]: for big_endian in [True, False]:
verts = ( verts = (
"0 0 0 " "0 0 0 " "0 0 1 " "0 1 1 " "0 1 0 " "1 0 0 " "1 0 1 " "1 1 1 " "1 1 0"
"0 0 1 "
"0 1 1 "
"0 1 0 "
"1 0 0 "
"1 0 1 "
"1 1 1 "
"1 1 0"
).split() ).split()
faces = ( faces = (
"4 0 1 2 3 " "4 0 1 2 3 "
...@@ -176,9 +168,7 @@ class TestMeshPlyIO(TestCaseMixin, unittest.TestCase): ...@@ -176,9 +168,7 @@ class TestMeshPlyIO(TestCaseMixin, unittest.TestCase):
"3 4 5 1" "3 4 5 1"
).split() ).split()
short_one = b"\00\01" if big_endian else b"\01\00" short_one = b"\00\01" if big_endian else b"\01\00"
mixed_data = b"\00\00" b"\03\03" + ( mixed_data = b"\00\00" b"\03\03" + (short_one + b"\00\01\01\01" b"\00\02")
short_one + b"\00\01\01\01" b"\00\02"
)
minus_one_data = b"\xff" * 14 minus_one_data = b"\xff" * 14
endian_char = ">" if big_endian else "<" endian_char = ">" if big_endian else "<"
format = ( format = (
...@@ -306,9 +296,7 @@ class TestMeshPlyIO(TestCaseMixin, unittest.TestCase): ...@@ -306,9 +296,7 @@ class TestMeshPlyIO(TestCaseMixin, unittest.TestCase):
lines2 = lines.copy() lines2 = lines.copy()
lines2[8] = "1 2" lines2[8] = "1 2"
with self.assertRaisesRegex( with self.assertRaisesRegex(ValueError, "Inconsistent data for vertex."):
ValueError, "Inconsistent data for vertex."
):
_load_ply_raw(StringIO("\n".join(lines2))) _load_ply_raw(StringIO("\n".join(lines2)))
lines2 = lines[:-1] lines2 = lines[:-1]
...@@ -344,9 +332,7 @@ class TestMeshPlyIO(TestCaseMixin, unittest.TestCase): ...@@ -344,9 +332,7 @@ class TestMeshPlyIO(TestCaseMixin, unittest.TestCase):
lines2 = lines.copy() lines2 = lines.copy()
lines2.insert(4, "element bad 1") lines2.insert(4, "element bad 1")
with self.assertRaisesRegex( with self.assertRaisesRegex(ValueError, "Found an element with no properties."):
ValueError, "Found an element with no properties."
):
_load_ply_raw(StringIO("\n".join(lines2))) _load_ply_raw(StringIO("\n".join(lines2)))
lines2 = lines.copy() lines2 = lines.copy()
...@@ -369,25 +355,19 @@ class TestMeshPlyIO(TestCaseMixin, unittest.TestCase): ...@@ -369,25 +355,19 @@ class TestMeshPlyIO(TestCaseMixin, unittest.TestCase):
lines2 = lines.copy() lines2 = lines.copy()
lines2.insert(4, "property double y") lines2.insert(4, "property double y")
with self.assertRaisesRegex( with self.assertRaisesRegex(ValueError, "Too little data for an element."):
ValueError, "Too little data for an element."
):
_load_ply_raw(StringIO("\n".join(lines2))) _load_ply_raw(StringIO("\n".join(lines2)))
lines2[-2] = "3.3 4.2" lines2[-2] = "3.3 4.2"
_load_ply_raw(StringIO("\n".join(lines2))) _load_ply_raw(StringIO("\n".join(lines2)))
lines2[-2] = "3.3 4.3 2" lines2[-2] = "3.3 4.3 2"
with self.assertRaisesRegex( with self.assertRaisesRegex(ValueError, "Too much data for an element."):
ValueError, "Too much data for an element."
):
_load_ply_raw(StringIO("\n".join(lines2))) _load_ply_raw(StringIO("\n".join(lines2)))
# Now make the ply file actually be readable as a Mesh # Now make the ply file actually be readable as a Mesh
with self.assertRaisesRegex( with self.assertRaisesRegex(ValueError, "The ply file has no face element."):
ValueError, "The ply file has no face element."
):
load_ply(StringIO("\n".join(lines))) load_ply(StringIO("\n".join(lines)))
lines2 = lines.copy() lines2 = lines.copy()
...@@ -398,9 +378,7 @@ class TestMeshPlyIO(TestCaseMixin, unittest.TestCase): ...@@ -398,9 +378,7 @@ class TestMeshPlyIO(TestCaseMixin, unittest.TestCase):
lines2.insert(5, "property float z") lines2.insert(5, "property float z")
lines2.insert(5, "property float y") lines2.insert(5, "property float y")
lines2[-2] = "0 0 0" lines2[-2] = "0 0 0"
with self.assertRaisesRegex( with self.assertRaisesRegex(ValueError, "Faces must have at least 3 vertices."):
ValueError, "Faces must have at least 3 vertices."
):
load_ply(StringIO("\n".join(lines2))) load_ply(StringIO("\n".join(lines2)))
# Good one # Good one
...@@ -408,17 +386,11 @@ class TestMeshPlyIO(TestCaseMixin, unittest.TestCase): ...@@ -408,17 +386,11 @@ class TestMeshPlyIO(TestCaseMixin, unittest.TestCase):
load_ply(StringIO("\n".join(lines2))) load_ply(StringIO("\n".join(lines2)))
@staticmethod @staticmethod
def _bm_save_ply( def _bm_save_ply(verts: torch.Tensor, faces: torch.Tensor, decimal_places: int):
verts: torch.Tensor, faces: torch.Tensor, decimal_places: int return lambda: save_ply(StringIO(), verts, faces, decimal_places=decimal_places)
):
return lambda: save_ply(
StringIO(), verts, faces, decimal_places=decimal_places
)
@staticmethod @staticmethod
def _bm_load_ply( def _bm_load_ply(verts: torch.Tensor, faces: torch.Tensor, decimal_places: int):
verts: torch.Tensor, faces: torch.Tensor, decimal_places: int
):
f = StringIO() f = StringIO()
save_ply(f, verts, faces, decimal_places) save_ply(f, verts, faces, decimal_places)
s = f.getvalue() s = f.getvalue()
......
# Copyright (c) Facebook, Inc. and its affiliates. All rights reserved. # Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
import numpy as np
import unittest import unittest
import torch
from pytorch3d.structures.pointclouds import Pointclouds
import numpy as np
import torch
from common_testing import TestCaseMixin from common_testing import TestCaseMixin
from pytorch3d.structures.pointclouds import Pointclouds
class TestPointclouds(TestCaseMixin, unittest.TestCase): class TestPointclouds(TestCaseMixin, unittest.TestCase):
...@@ -52,13 +51,11 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -52,13 +51,11 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
normals_list, features_list = None, None normals_list, features_list = None, None
if with_normals: if with_normals:
normals_list = [ normals_list = [
torch.rand((i, 3), device=device, dtype=torch.float32) torch.rand((i, 3), device=device, dtype=torch.float32) for i in p
for i in p
] ]
if with_features: if with_features:
features_list = [ features_list = [
torch.rand((i, channels), device=device, dtype=torch.float32) torch.rand((i, channels), device=device, dtype=torch.float32) for i in p
for i in p
] ]
if lists_to_tensors: if lists_to_tensors:
...@@ -68,9 +65,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -68,9 +65,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
if with_features: if with_features:
features_list = torch.stack(features_list) features_list = torch.stack(features_list)
return Pointclouds( return Pointclouds(points_list, normals=normals_list, features=features_list)
points_list, normals=normals_list, features=features_list
)
def test_simple(self): def test_simple(self):
device = torch.device("cuda:0") device = torch.device("cuda:0")
...@@ -81,12 +76,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -81,12 +76,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
device=device, device=device,
), ),
torch.tensor( torch.tensor(
[ [[0.1, 0.3, 0.3], [0.6, 0.7, 0.8], [0.2, 0.3, 0.4], [0.1, 0.5, 0.3]],
[0.1, 0.3, 0.3],
[0.6, 0.7, 0.8],
[0.2, 0.3, 0.4],
[0.1, 0.5, 0.3],
],
dtype=torch.float32, dtype=torch.float32,
device=device, device=device,
), ),
...@@ -111,9 +101,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -111,9 +101,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
self.assertClose( self.assertClose(
clouds.cloud_to_packed_first_idx().cpu(), torch.tensor([0, 3, 7]) clouds.cloud_to_packed_first_idx().cpu(), torch.tensor([0, 3, 7])
) )
self.assertClose( self.assertClose(clouds.num_points_per_cloud().cpu(), torch.tensor([3, 4, 5]))
clouds.num_points_per_cloud().cpu(), torch.tensor([3, 4, 5])
)
self.assertClose( self.assertClose(
clouds.padded_to_packed_idx().cpu(), clouds.padded_to_packed_idx().cpu(),
torch.tensor([0, 1, 2, 5, 6, 7, 8, 10, 11, 12, 13, 14]), torch.tensor([0, 1, 2, 5, 6, 7, 8, 10, 11, 12, 13, 14]),
...@@ -129,11 +117,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -129,11 +117,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
"points_padded", "points_padded",
"padded_to_packed_idx", "padded_to_packed_idx",
] ]
public_normals_getters = [ public_normals_getters = ["normals_list", "normals_packed", "normals_padded"]
"normals_list",
"normals_packed",
"normals_padded",
]
public_features_getters = [ public_features_getters = [
"features_list", "features_list",
"features_packed", "features_packed",
...@@ -147,17 +131,13 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -147,17 +131,13 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
points_data = [torch.zeros((max_len, 3)).uniform_() for i in lengths] points_data = [torch.zeros((max_len, 3)).uniform_() for i in lengths]
normals_data = [torch.zeros((max_len, 3)).uniform_() for i in lengths] normals_data = [torch.zeros((max_len, 3)).uniform_() for i in lengths]
features_data = [torch.zeros((max_len, C)).uniform_() for i in lengths] features_data = [torch.zeros((max_len, C)).uniform_() for i in lengths]
for length, p, n, f in zip( for length, p, n, f in zip(lengths, points_data, normals_data, features_data):
lengths, points_data, normals_data, features_data
):
p[length:] = 0.0 p[length:] = 0.0
n[length:] = 0.0 n[length:] = 0.0
f[length:] = 0.0 f[length:] = 0.0
points_list = [d[:length] for length, d in zip(lengths, points_data)] points_list = [d[:length] for length, d in zip(lengths, points_data)]
normals_list = [d[:length] for length, d in zip(lengths, normals_data)] normals_list = [d[:length] for length, d in zip(lengths, normals_data)]
features_list = [ features_list = [d[:length] for length, d in zip(lengths, features_data)]
d[:length] for length, d in zip(lengths, features_data)
]
points_packed = torch.cat(points_data) points_packed = torch.cat(points_data)
normals_packed = torch.cat(normals_data) normals_packed = torch.cat(normals_data)
features_packed = torch.cat(features_data) features_packed = torch.cat(features_data)
...@@ -173,13 +153,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -173,13 +153,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
("emptylist_emptylist_emptylist", [], [], []), ("emptylist_emptylist_emptylist", [], [], []),
] ]
false_cases_inputs = [ false_cases_inputs = [
( ("list_packed", points_list, normals_packed, features_packed, ValueError),
"list_packed",
points_list,
normals_packed,
features_packed,
ValueError,
),
("packed_0", points_packed, None, None, ValueError), ("packed_0", points_packed, None, None, ValueError),
] ]
...@@ -230,15 +204,11 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -230,15 +204,11 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
self.assertIsNone(features_padded) self.assertIsNone(features_padded)
for n in range(N): for n in range(N):
p = points_list[n].shape[0] p = points_list[n].shape[0]
self.assertClose( self.assertClose(points_padded[n, :p, :], points_list[n])
points_padded[n, :p, :], points_list[n]
)
if with_normals: if with_normals:
norms = normals_list[n].shape[0] norms = normals_list[n].shape[0]
self.assertEqual(p, norms) self.assertEqual(p, norms)
self.assertClose( self.assertClose(normals_padded[n, :p, :], normals_list[n])
normals_padded[n, :p, :], normals_list[n]
)
if with_features: if with_features:
f = features_list[n].shape[0] f = features_list[n].shape[0]
self.assertEqual(p, f) self.assertEqual(p, f)
...@@ -248,9 +218,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -248,9 +218,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
if points_padded.shape[1] > p: if points_padded.shape[1] > p:
self.assertTrue(points_padded[n, p:, :].eq(0).all()) self.assertTrue(points_padded[n, p:, :].eq(0).all())
if with_features: if with_features:
self.assertTrue( self.assertTrue(features_padded[n, p:, :].eq(0).all())
features_padded[n, p:, :].eq(0).all()
)
self.assertEqual(points_per_cloud[n], p) self.assertEqual(points_per_cloud[n], p)
# Check compute packed. # Check compute packed.
...@@ -272,17 +240,13 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -272,17 +240,13 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
) )
if with_normals: if with_normals:
self.assertClose( self.assertClose(
normals_packed[cur : cur + p, :], normals_packed[cur : cur + p, :], normals_list[n]
normals_list[n],
) )
if with_features: if with_features:
self.assertClose( self.assertClose(
features_packed[cur : cur + p, :], features_packed[cur : cur + p, :], features_list[n]
features_list[n],
) )
self.assertTrue( self.assertTrue(packed_to_cloud[cur : cur + p].eq(n).all())
packed_to_cloud[cur : cur + p].eq(n).all()
)
self.assertTrue(cloud_to_packed[n] == cur) self.assertTrue(cloud_to_packed[n] == cur)
cur += p cur += p
...@@ -312,9 +276,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -312,9 +276,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
)[0] )[0]
points = torch.rand((p, 3), dtype=torch.float32, device=device) points = torch.rand((p, 3), dtype=torch.float32, device=device)
normals = torch.rand((p, 3), dtype=torch.float32, device=device) normals = torch.rand((p, 3), dtype=torch.float32, device=device)
features = torch.rand( features = torch.rand((p, C), dtype=torch.float32, device=device)
(p, C), dtype=torch.float32, device=device
)
else: else:
points = torch.tensor([], dtype=torch.float32, device=device) points = torch.tensor([], dtype=torch.float32, device=device)
normals = torch.tensor([], dtype=torch.float32, device=device) normals = torch.tensor([], dtype=torch.float32, device=device)
...@@ -331,9 +293,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -331,9 +293,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
if with_features: if with_features:
this_features = features_list this_features = features_list
clouds = Pointclouds( clouds = Pointclouds(
points=points_list, points=points_list, normals=this_normals, features=this_features
normals=this_normals,
features=this_features,
) )
points_padded = clouds.points_padded() points_padded = clouds.points_padded()
normals_padded = clouds.normals_padded() normals_padded = clouds.normals_padded()
...@@ -346,13 +306,9 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -346,13 +306,9 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
for n in range(N): for n in range(N):
p = len(points_list[n]) p = len(points_list[n])
if p > 0: if p > 0:
self.assertClose( self.assertClose(points_padded[n, :p, :], points_list[n])
points_padded[n, :p, :], points_list[n]
)
if with_normals: if with_normals:
self.assertClose( self.assertClose(normals_padded[n, :p, :], normals_list[n])
normals_padded[n, :p, :], normals_list[n]
)
if with_features: if with_features:
self.assertClose( self.assertClose(
features_padded[n, :p, :], features_list[n] features_padded[n, :p, :], features_list[n]
...@@ -360,13 +316,9 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -360,13 +316,9 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
if points_padded.shape[1] > p: if points_padded.shape[1] > p:
self.assertTrue(points_padded[n, p:, :].eq(0).all()) self.assertTrue(points_padded[n, p:, :].eq(0).all())
if with_normals: if with_normals:
self.assertTrue( self.assertTrue(normals_padded[n, p:, :].eq(0).all())
normals_padded[n, p:, :].eq(0).all()
)
if with_features: if with_features:
self.assertTrue( self.assertTrue(features_padded[n, p:, :].eq(0).all())
features_padded[n, p:, :].eq(0).all()
)
self.assertTrue(points_per_cloud[n] == p) self.assertTrue(points_per_cloud[n] == p)
def test_clone_list(self): def test_clone_list(self):
...@@ -379,12 +331,8 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -379,12 +331,8 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
new_clouds = clouds.clone() new_clouds = clouds.clone()
# Check cloned and original objects do not share tensors. # Check cloned and original objects do not share tensors.
self.assertSeparate( self.assertSeparate(new_clouds.points_list()[0], clouds.points_list()[0])
new_clouds.points_list()[0], clouds.points_list()[0] self.assertSeparate(new_clouds.normals_list()[0], clouds.normals_list()[0])
)
self.assertSeparate(
new_clouds.normals_list()[0], clouds.normals_list()[0]
)
self.assertSeparate( self.assertSeparate(
new_clouds.features_list()[0], clouds.features_list()[0] new_clouds.features_list()[0], clouds.features_list()[0]
) )
...@@ -412,12 +360,8 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -412,12 +360,8 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
new_clouds = clouds.clone() new_clouds = clouds.clone()
# Check cloned and original objects do not share tensors. # Check cloned and original objects do not share tensors.
self.assertSeparate( self.assertSeparate(new_clouds.points_list()[0], clouds.points_list()[0])
new_clouds.points_list()[0], clouds.points_list()[0] self.assertSeparate(new_clouds.normals_list()[0], clouds.normals_list()[0])
)
self.assertSeparate(
new_clouds.normals_list()[0], clouds.normals_list()[0]
)
self.assertSeparate( self.assertSeparate(
new_clouds.features_list()[0], clouds.features_list()[0] new_clouds.features_list()[0], clouds.features_list()[0]
) )
...@@ -442,9 +386,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -442,9 +386,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
for i in range(N): for i in range(N):
self.assertClose(cloud1.points_list()[i], cloud2.points_list()[i]) self.assertClose(cloud1.points_list()[i], cloud2.points_list()[i])
self.assertClose(cloud1.normals_list()[i], cloud2.normals_list()[i]) self.assertClose(cloud1.normals_list()[i], cloud2.normals_list()[i])
self.assertClose( self.assertClose(cloud1.features_list()[i], cloud2.features_list()[i])
cloud1.features_list()[i], cloud2.features_list()[i]
)
has_normals = cloud1.normals_list() is not None has_normals = cloud1.normals_list() is not None
self.assertTrue(has_normals == (cloud2.normals_list() is not None)) self.assertTrue(has_normals == (cloud2.normals_list() is not None))
has_features = cloud1.features_list() is not None has_features = cloud1.features_list() is not None
...@@ -459,22 +401,13 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -459,22 +401,13 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
if has_features: if has_features:
self.assertClose(cloud1.features_padded(), cloud2.features_padded()) self.assertClose(cloud1.features_padded(), cloud2.features_padded())
self.assertClose(cloud1.features_packed(), cloud2.features_packed()) self.assertClose(cloud1.features_packed(), cloud2.features_packed())
self.assertClose(cloud1.packed_to_cloud_idx(), cloud2.packed_to_cloud_idx())
self.assertClose( self.assertClose(
cloud1.packed_to_cloud_idx(), cloud2.packed_to_cloud_idx() cloud1.cloud_to_packed_first_idx(), cloud2.cloud_to_packed_first_idx()
)
self.assertClose(
cloud1.cloud_to_packed_first_idx(),
cloud2.cloud_to_packed_first_idx(),
)
self.assertClose(
cloud1.num_points_per_cloud(), cloud2.num_points_per_cloud()
)
self.assertClose(
cloud1.packed_to_cloud_idx(), cloud2.packed_to_cloud_idx()
)
self.assertClose(
cloud1.padded_to_packed_idx(), cloud2.padded_to_packed_idx()
) )
self.assertClose(cloud1.num_points_per_cloud(), cloud2.num_points_per_cloud())
self.assertClose(cloud1.packed_to_cloud_idx(), cloud2.packed_to_cloud_idx())
self.assertClose(cloud1.padded_to_packed_idx(), cloud2.padded_to_packed_idx())
self.assertTrue(all(cloud1.valid == cloud2.valid)) self.assertTrue(all(cloud1.valid == cloud2.valid))
self.assertTrue(cloud1.equisized == cloud2.equisized) self.assertTrue(cloud1.equisized == cloud2.equisized)
...@@ -482,9 +415,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -482,9 +415,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
def naive_offset(clouds, offsets_packed): def naive_offset(clouds, offsets_packed):
new_points_packed = clouds.points_packed() + offsets_packed new_points_packed = clouds.points_packed() + offsets_packed
new_points_list = list( new_points_list = list(
new_points_packed.split( new_points_packed.split(clouds.num_points_per_cloud().tolist(), 0)
clouds.num_points_per_cloud().tolist(), 0
)
) )
return Pointclouds( return Pointclouds(
points=new_points_list, points=new_points_list,
...@@ -502,9 +433,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -502,9 +433,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
clouds._compute_padded() clouds._compute_padded()
clouds.padded_to_packed_idx() clouds.padded_to_packed_idx()
deform = torch.rand( deform = torch.rand((all_p, 3), dtype=torch.float32, device=clouds.device)
(all_p, 3), dtype=torch.float32, device=clouds.device
)
new_clouds_naive = naive_offset(clouds, deform) new_clouds_naive = naive_offset(clouds, deform)
new_clouds = clouds.offset(deform) new_clouds = clouds.offset(deform)
...@@ -521,8 +450,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -521,8 +450,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
clouds.normals_list()[i], new_clouds_naive.normals_list()[i] clouds.normals_list()[i], new_clouds_naive.normals_list()[i]
) )
self.assertClose( self.assertClose(
clouds.features_list()[i], clouds.features_list()[i], new_clouds_naive.features_list()[i]
new_clouds_naive.features_list()[i],
) )
self.assertCloudsEqual(new_clouds, new_clouds_naive) self.assertCloudsEqual(new_clouds, new_clouds_naive)
...@@ -550,15 +478,13 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -550,15 +478,13 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
new_clouds = clouds.scale(scales) new_clouds = clouds.scale(scales)
for i in range(N): for i in range(N):
self.assertClose( self.assertClose(
scales[i] * clouds.points_list()[i], scales[i] * clouds.points_list()[i], new_clouds.points_list()[i]
new_clouds.points_list()[i],
) )
self.assertClose( self.assertClose(
clouds.normals_list()[i], new_clouds_naive.normals_list()[i] clouds.normals_list()[i], new_clouds_naive.normals_list()[i]
) )
self.assertClose( self.assertClose(
clouds.features_list()[i], clouds.features_list()[i], new_clouds_naive.features_list()[i]
new_clouds_naive.features_list()[i],
) )
self.assertCloudsEqual(new_clouds, new_clouds_naive) self.assertCloudsEqual(new_clouds, new_clouds_naive)
...@@ -576,20 +502,15 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -576,20 +502,15 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
for i in range(len(clouds)): for i in range(len(clouds)):
for n in range(N): for n in range(N):
self.assertClose( self.assertClose(
clouds.points_list()[i], clouds.points_list()[i], new_clouds.points_list()[i * N + n]
new_clouds.points_list()[i * N + n],
) )
self.assertClose( self.assertClose(
clouds.normals_list()[i], clouds.normals_list()[i], new_clouds.normals_list()[i * N + n]
new_clouds.normals_list()[i * N + n],
) )
self.assertClose( self.assertClose(
clouds.features_list()[i], clouds.features_list()[i], new_clouds.features_list()[i * N + n]
new_clouds.features_list()[i * N + n],
)
self.assertTrue(
clouds.valid[i] == new_clouds.valid[i * N + n]
) )
self.assertTrue(clouds.valid[i] == new_clouds.valid[i * N + n])
self.assertAllSeparate( self.assertAllSeparate(
clouds.points_list() clouds.points_list()
+ new_clouds.points_list() + new_clouds.points_list()
...@@ -627,8 +548,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -627,8 +548,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
"padded_to_packed_idx", "padded_to_packed_idx",
]: ]:
self.assertClose( self.assertClose(
getattr(new_cloud, attrib)().cpu(), getattr(new_cloud, attrib)().cpu(), getattr(cloud, attrib)().cpu()
getattr(cloud, attrib)().cpu(),
) )
for i in range(len(cloud)): for i in range(len(cloud)):
self.assertClose( self.assertClose(
...@@ -638,8 +558,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -638,8 +558,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
cloud.normals_list()[i].cpu(), new_cloud.normals_list()[i].cpu() cloud.normals_list()[i].cpu(), new_cloud.normals_list()[i].cpu()
) )
self.assertClose( self.assertClose(
cloud.features_list()[i].cpu(), cloud.features_list()[i].cpu(), new_cloud.features_list()[i].cpu()
new_cloud.features_list()[i].cpu(),
) )
self.assertTrue(all(cloud.valid.cpu() == new_cloud.valid.cpu())) self.assertTrue(all(cloud.valid.cpu() == new_cloud.valid.cpu()))
self.assertTrue(cloud.equisized == new_cloud.equisized) self.assertTrue(cloud.equisized == new_cloud.equisized)
...@@ -666,8 +585,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -666,8 +585,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
"padded_to_packed_idx", "padded_to_packed_idx",
]: ]:
self.assertClose( self.assertClose(
getattr(new_cloud, attrib)().cpu(), getattr(new_cloud, attrib)().cpu(), getattr(cloud, attrib)().cpu()
getattr(cloud, attrib)().cpu(),
) )
for i in range(len(cloud)): for i in range(len(cloud)):
self.assertClose( self.assertClose(
...@@ -677,8 +595,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -677,8 +595,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
cloud.normals_list()[i].cpu(), new_cloud.normals_list()[i].cpu() cloud.normals_list()[i].cpu(), new_cloud.normals_list()[i].cpu()
) )
self.assertClose( self.assertClose(
cloud.features_list()[i].cpu(), cloud.features_list()[i].cpu(), new_cloud.features_list()[i].cpu()
new_cloud.features_list()[i].cpu(),
) )
self.assertTrue(all(cloud.valid.cpu() == new_cloud.valid.cpu())) self.assertTrue(all(cloud.valid.cpu() == new_cloud.valid.cpu()))
self.assertTrue(cloud.equisized == new_cloud.equisized) self.assertTrue(cloud.equisized == new_cloud.equisized)
...@@ -698,11 +615,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -698,11 +615,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
self.assertEqual(len(split_clouds[1]), 3) self.assertEqual(len(split_clouds[1]), 3)
self.assertTrue( self.assertTrue(
split_clouds[1].points_list() split_clouds[1].points_list()
== [ == [clouds.get_cloud(2)[0], clouds.get_cloud(3)[0], clouds.get_cloud(4)[0]]
clouds.get_cloud(2)[0],
clouds.get_cloud(3)[0],
clouds.get_cloud(4)[0],
]
) )
split_sizes = [2, 0.3] split_sizes = [2, 0.3]
...@@ -751,9 +664,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -751,9 +664,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
points_padded = clouds.points_padded() points_padded = clouds.points_padded()
points_padded_flat = points_padded.view(-1, 3) points_padded_flat = points_padded.view(-1, 3)
self.assertClose( self.assertClose(points_padded_flat[padded_to_packed_idx], points_packed)
points_padded_flat[padded_to_packed_idx], points_packed
)
idx = padded_to_packed_idx.view(-1, 1).expand(-1, 3) idx = padded_to_packed_idx.view(-1, 1).expand(-1, 3)
self.assertClose(points_padded_flat.gather(0, idx), points_packed) self.assertClose(points_padded_flat.gather(0, idx), points_packed)
...@@ -765,16 +676,13 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -765,16 +676,13 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
def check_equal(selected, indices): def check_equal(selected, indices):
for selectedIdx, index in indices: for selectedIdx, index in indices:
self.assertClose( self.assertClose(
selected.points_list()[selectedIdx], selected.points_list()[selectedIdx], clouds.points_list()[index]
clouds.points_list()[index],
) )
self.assertClose( self.assertClose(
selected.normals_list()[selectedIdx], selected.normals_list()[selectedIdx], clouds.normals_list()[index]
clouds.normals_list()[index],
) )
self.assertClose( self.assertClose(
selected.features_list()[selectedIdx], selected.features_list()[selectedIdx], clouds.features_list()[index]
clouds.features_list()[index],
) )
# int index # int index
...@@ -820,11 +728,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -820,11 +728,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
for with_normfeat in (True, False): for with_normfeat in (True, False):
for with_new_normfeat in (True, False): for with_new_normfeat in (True, False):
clouds = self.init_cloud( clouds = self.init_cloud(
N, N, P, C, with_normals=with_normfeat, with_features=with_normfeat
P,
C,
with_normals=with_normfeat,
with_features=with_normfeat,
) )
num_points_per_cloud = clouds.num_points_per_cloud() num_points_per_cloud = clouds.num_points_per_cloud()
...@@ -843,8 +747,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -843,8 +747,7 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
clouds.points_padded().shape, device=clouds.device clouds.points_padded().shape, device=clouds.device
) )
new_normals_list = [ new_normals_list = [
new_normals[i, : num_points_per_cloud[i]] new_normals[i, : num_points_per_cloud[i]] for i in range(N)
for i in range(N)
] ]
feat_shape = [ feat_shape = [
clouds.points_padded().shape[0], clouds.points_padded().shape[0],
...@@ -853,14 +756,11 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -853,14 +756,11 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
] ]
new_features = torch.rand(feat_shape, device=clouds.device) new_features = torch.rand(feat_shape, device=clouds.device)
new_features_list = [ new_features_list = [
new_features[i, : num_points_per_cloud[i]] new_features[i, : num_points_per_cloud[i]] for i in range(N)
for i in range(N)
] ]
# update # update
new_clouds = clouds.update_padded( new_clouds = clouds.update_padded(new_points, new_normals, new_features)
new_points, new_normals, new_features
)
self.assertIsNone(new_clouds._points_list) self.assertIsNone(new_clouds._points_list)
self.assertIsNone(new_clouds._points_packed) self.assertIsNone(new_clouds._points_packed)
...@@ -868,13 +768,9 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -868,13 +768,9 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
self.assertTrue(all(new_clouds.valid == clouds.valid)) self.assertTrue(all(new_clouds.valid == clouds.valid))
self.assertClose(new_clouds.points_padded(), new_points) self.assertClose(new_clouds.points_padded(), new_points)
self.assertClose( self.assertClose(new_clouds.points_packed(), torch.cat(new_points_list))
new_clouds.points_packed(), torch.cat(new_points_list)
)
for i in range(N): for i in range(N):
self.assertClose( self.assertClose(new_clouds.points_list()[i], new_points_list[i])
new_clouds.points_list()[i], new_points_list[i]
)
if with_new_normfeat: if with_new_normfeat:
for i in range(N): for i in range(N):
...@@ -890,27 +786,22 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -890,27 +786,22 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
) )
self.assertClose(new_clouds.features_padded(), new_features) self.assertClose(new_clouds.features_padded(), new_features)
self.assertClose( self.assertClose(
new_clouds.features_packed(), new_clouds.features_packed(), torch.cat(new_features_list)
torch.cat(new_features_list),
) )
else: else:
if with_normfeat: if with_normfeat:
for i in range(N): for i in range(N):
self.assertClose( self.assertClose(
new_clouds.normals_list()[i], new_clouds.normals_list()[i], clouds.normals_list()[i]
clouds.normals_list()[i],
) )
self.assertClose( self.assertClose(
new_clouds.features_list()[i], new_clouds.features_list()[i], clouds.features_list()[i]
clouds.features_list()[i],
) )
self.assertNotSeparate( self.assertNotSeparate(
new_clouds.normals_list()[i], new_clouds.normals_list()[i], clouds.normals_list()[i]
clouds.normals_list()[i],
) )
self.assertNotSeparate( self.assertNotSeparate(
new_clouds.features_list()[i], new_clouds.features_list()[i], clouds.features_list()[i]
clouds.features_list()[i],
) )
self.assertClose( self.assertClose(
...@@ -920,19 +811,16 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase): ...@@ -920,19 +811,16 @@ class TestPointclouds(TestCaseMixin, unittest.TestCase):
new_clouds.normals_packed(), clouds.normals_packed() new_clouds.normals_packed(), clouds.normals_packed()
) )
self.assertClose( self.assertClose(
new_clouds.features_padded(), new_clouds.features_padded(), clouds.features_padded()
clouds.features_padded(),
) )
self.assertClose( self.assertClose(
new_clouds.features_packed(), new_clouds.features_packed(), clouds.features_packed()
clouds.features_packed(),
) )
self.assertNotSeparate( self.assertNotSeparate(
new_clouds.normals_padded(), clouds.normals_padded() new_clouds.normals_padded(), clouds.normals_padded()
) )
self.assertNotSeparate( self.assertNotSeparate(
new_clouds.features_padded(), new_clouds.features_padded(), clouds.features_padded()
clouds.features_padded(),
) )
else: else:
self.assertIsNone(new_clouds.normals_list()) self.assertIsNone(new_clouds.normals_list())
......
...@@ -2,8 +2,9 @@ ...@@ -2,8 +2,9 @@
import functools import functools
import unittest import unittest
import torch
import torch
from common_testing import TestCaseMixin
from pytorch3d import _C from pytorch3d import _C
from pytorch3d.renderer.mesh.rasterize_meshes import ( from pytorch3d.renderer.mesh.rasterize_meshes import (
rasterize_meshes, rasterize_meshes,
...@@ -12,20 +13,14 @@ from pytorch3d.renderer.mesh.rasterize_meshes import ( ...@@ -12,20 +13,14 @@ from pytorch3d.renderer.mesh.rasterize_meshes import (
from pytorch3d.structures import Meshes from pytorch3d.structures import Meshes
from pytorch3d.utils import ico_sphere from pytorch3d.utils import ico_sphere
from common_testing import TestCaseMixin
class TestRasterizeMeshes(TestCaseMixin, unittest.TestCase): class TestRasterizeMeshes(TestCaseMixin, unittest.TestCase):
def test_simple_python(self): def test_simple_python(self):
device = torch.device("cpu") device = torch.device("cpu")
self._simple_triangle_raster( self._simple_triangle_raster(rasterize_meshes_python, device, bin_size=-1)
rasterize_meshes_python, device, bin_size=-1
)
self._simple_blurry_raster(rasterize_meshes_python, device, bin_size=-1) self._simple_blurry_raster(rasterize_meshes_python, device, bin_size=-1)
self._test_behind_camera(rasterize_meshes_python, device, bin_size=-1) self._test_behind_camera(rasterize_meshes_python, device, bin_size=-1)
self._test_perspective_correct( self._test_perspective_correct(rasterize_meshes_python, device, bin_size=-1)
rasterize_meshes_python, device, bin_size=-1
)
def test_simple_cpu_naive(self): def test_simple_cpu_naive(self):
device = torch.device("cpu") device = torch.device("cpu")
...@@ -350,9 +345,7 @@ class TestRasterizeMeshes(TestCaseMixin, unittest.TestCase): ...@@ -350,9 +345,7 @@ class TestRasterizeMeshes(TestCaseMixin, unittest.TestCase):
fn1 = functools.partial(rasterize_meshes, meshes1, **kwargs) fn1 = functools.partial(rasterize_meshes, meshes1, **kwargs)
fn2 = functools.partial(rasterize_meshes_python, meshes2, **kwargs) fn2 = functools.partial(rasterize_meshes_python, meshes2, **kwargs)
args = () args = ()
self._compare_impls( self._compare_impls(fn1, fn2, args, args, verts1, verts2, compare_grads=True)
fn1, fn2, args, args, verts1, verts2, compare_grads=True
)
def test_cpp_vs_cuda_perspective_correct(self): def test_cpp_vs_cuda_perspective_correct(self):
meshes = ico_sphere(2, device=torch.device("cpu")) meshes = ico_sphere(2, device=torch.device("cpu"))
...@@ -367,9 +360,7 @@ class TestRasterizeMeshes(TestCaseMixin, unittest.TestCase): ...@@ -367,9 +360,7 @@ class TestRasterizeMeshes(TestCaseMixin, unittest.TestCase):
fn1 = functools.partial(rasterize_meshes, meshes1, **kwargs) fn1 = functools.partial(rasterize_meshes, meshes1, **kwargs)
fn2 = functools.partial(rasterize_meshes, meshes2, bin_size=0, **kwargs) fn2 = functools.partial(rasterize_meshes, meshes2, bin_size=0, **kwargs)
args = () args = ()
self._compare_impls( self._compare_impls(fn1, fn2, args, args, verts1, verts2, compare_grads=True)
fn1, fn2, args, args, verts1, verts2, compare_grads=True
)
def test_cuda_naive_vs_binned_perspective_correct(self): def test_cuda_naive_vs_binned_perspective_correct(self):
meshes = ico_sphere(2, device=torch.device("cuda")) meshes = ico_sphere(2, device=torch.device("cuda"))
...@@ -384,9 +375,7 @@ class TestRasterizeMeshes(TestCaseMixin, unittest.TestCase): ...@@ -384,9 +375,7 @@ class TestRasterizeMeshes(TestCaseMixin, unittest.TestCase):
fn1 = functools.partial(rasterize_meshes, meshes1, bin_size=0, **kwargs) fn1 = functools.partial(rasterize_meshes, meshes1, bin_size=0, **kwargs)
fn2 = functools.partial(rasterize_meshes, meshes2, bin_size=8, **kwargs) fn2 = functools.partial(rasterize_meshes, meshes2, bin_size=8, **kwargs)
args = () args = ()
self._compare_impls( self._compare_impls(fn1, fn2, args, args, verts1, verts2, compare_grads=True)
fn1, fn2, args, args, verts1, verts2, compare_grads=True
)
def _compare_impls( def _compare_impls(
self, self,
...@@ -433,9 +422,7 @@ class TestRasterizeMeshes(TestCaseMixin, unittest.TestCase): ...@@ -433,9 +422,7 @@ class TestRasterizeMeshes(TestCaseMixin, unittest.TestCase):
grad_verts2 = grad_var2.grad.data.clone().cpu() grad_verts2 = grad_var2.grad.data.clone().cpu()
self.assertClose(grad_verts1, grad_verts2, rtol=1e-3) self.assertClose(grad_verts1, grad_verts2, rtol=1e-3)
def _test_perspective_correct( def _test_perspective_correct(self, rasterize_meshes_fn, device, bin_size=None):
self, rasterize_meshes_fn, device, bin_size=None
):
# fmt: off # fmt: off
verts = torch.tensor([ verts = torch.tensor([
[-0.4, -0.4, 10], # noqa: E241, E201 [-0.4, -0.4, 10], # noqa: E241, E201
...@@ -542,12 +529,8 @@ class TestRasterizeMeshes(TestCaseMixin, unittest.TestCase): ...@@ -542,12 +529,8 @@ class TestRasterizeMeshes(TestCaseMixin, unittest.TestCase):
zbuf_f_bary = w0_f * z0 + w1_f * z1 + w2_f * z2 zbuf_f_bary = w0_f * z0 + w1_f * z1 + w2_f * z2
zbuf_t_bary = w0_t * z0 + w1_t * z1 + w2_t * z2 zbuf_t_bary = w0_t * z0 + w1_t * z1 + w2_t * z2
mask = idx_expected != -1 mask = idx_expected != -1
zbuf_f_bary_diff = ( zbuf_f_bary_diff = (zbuf_f_bary[mask] - zbuf_f_expected[mask]).abs().max()
(zbuf_f_bary[mask] - zbuf_f_expected[mask]).abs().max() zbuf_t_bary_diff = (zbuf_t_bary[mask] - zbuf_t_expected[mask]).abs().max()
)
zbuf_t_bary_diff = (
(zbuf_t_bary[mask] - zbuf_t_expected[mask]).abs().max()
)
self.assertLess(zbuf_f_bary_diff, 1e-4) self.assertLess(zbuf_f_bary_diff, 1e-4)
self.assertLess(zbuf_t_bary_diff, 1e-4) self.assertLess(zbuf_t_bary_diff, 1e-4)
...@@ -719,9 +702,7 @@ class TestRasterizeMeshes(TestCaseMixin, unittest.TestCase): ...@@ -719,9 +702,7 @@ class TestRasterizeMeshes(TestCaseMixin, unittest.TestCase):
# k = 1, second closest point. # k = 1, second closest point.
expected_p2face_k1 = expected_p2face_k0.clone() expected_p2face_k1 = expected_p2face_k0.clone()
expected_p2face_k1[0, :] = ( expected_p2face_k1[0, :] = torch.ones_like(expected_p2face_k1[0, :]) * -1
torch.ones_like(expected_p2face_k1[0, :]) * -1
)
# fmt: off # fmt: off
expected_p2face_k1[1, :] = torch.tensor( expected_p2face_k1[1, :] = torch.tensor(
...@@ -763,9 +744,7 @@ class TestRasterizeMeshes(TestCaseMixin, unittest.TestCase): ...@@ -763,9 +744,7 @@ class TestRasterizeMeshes(TestCaseMixin, unittest.TestCase):
# Coordinate conventions +Y up, +Z in, +X left # Coordinate conventions +Y up, +Z in, +X left
if bin_size == -1: if bin_size == -1:
# simple python, no bin_size # simple python, no bin_size
p2face, zbuf, bary, pix_dists = raster_fn( p2face, zbuf, bary, pix_dists = raster_fn(meshes, image_size, 0.0, 2)
meshes, image_size, 0.0, 2
)
else: else:
p2face, zbuf, bary, pix_dists = raster_fn( p2face, zbuf, bary, pix_dists = raster_fn(
meshes, image_size, 0.0, 2, bin_size meshes, image_size, 0.0, 2, bin_size
...@@ -914,9 +893,7 @@ class TestRasterizeMeshes(TestCaseMixin, unittest.TestCase): ...@@ -914,9 +893,7 @@ class TestRasterizeMeshes(TestCaseMixin, unittest.TestCase):
# Expected faces using axes convention +Y down, + X right, + Z in # Expected faces using axes convention +Y down, + X right, + Z in
bin_faces_expected = ( bin_faces_expected = (
torch.ones( torch.ones((1, 2, 2, max_faces_per_bin), dtype=torch.int32, device=device)
(1, 2, 2, max_faces_per_bin), dtype=torch.int32, device=device
)
* -1 * -1
) )
bin_faces_expected[0, 0, 0, 0] = torch.tensor([1]) bin_faces_expected[0, 0, 0, 0] = torch.tensor([1])
...@@ -979,12 +956,7 @@ class TestRasterizeMeshes(TestCaseMixin, unittest.TestCase): ...@@ -979,12 +956,7 @@ class TestRasterizeMeshes(TestCaseMixin, unittest.TestCase):
def rasterize(): def rasterize():
rasterize_meshes( rasterize_meshes(
meshes_batch, meshes_batch, image_size, blur_radius, 8, bin_size, max_faces_per_bin
image_size,
blur_radius,
8,
bin_size,
max_faces_per_bin,
) )
torch.cuda.synchronize() torch.cuda.synchronize()
......
# Copyright (c) Facebook, Inc. and its affiliates. All rights reserved. # Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
import numpy as np
import unittest import unittest
import torch
import numpy as np
import torch
from common_testing import TestCaseMixin
from pytorch3d import _C from pytorch3d import _C
from pytorch3d.renderer.points.rasterize_points import ( from pytorch3d.renderer.points.rasterize_points import (
rasterize_points, rasterize_points,
...@@ -12,8 +13,6 @@ from pytorch3d.renderer.points.rasterize_points import ( ...@@ -12,8 +13,6 @@ from pytorch3d.renderer.points.rasterize_points import (
) )
from pytorch3d.structures.pointclouds import Pointclouds from pytorch3d.structures.pointclouds import Pointclouds
from common_testing import TestCaseMixin
class TestRasterizePoints(TestCaseMixin, unittest.TestCase): class TestRasterizePoints(TestCaseMixin, unittest.TestCase):
def test_python_simple_cpu(self): def test_python_simple_cpu(self):
...@@ -38,9 +37,7 @@ class TestRasterizePoints(TestCaseMixin, unittest.TestCase): ...@@ -38,9 +37,7 @@ class TestRasterizePoints(TestCaseMixin, unittest.TestCase):
self._test_behind_camera(rasterize_points, torch.device("cpu")) self._test_behind_camera(rasterize_points, torch.device("cpu"))
def test_cuda_behind_camera(self): def test_cuda_behind_camera(self):
self._test_behind_camera( self._test_behind_camera(rasterize_points, torch.device("cuda"), bin_size=0)
rasterize_points, torch.device("cuda"), bin_size=0
)
def test_cpp_vs_naive_vs_binned(self): def test_cpp_vs_naive_vs_binned(self):
# Make sure that the backward pass runs for all pathways # Make sure that the backward pass runs for all pathways
...@@ -167,20 +164,8 @@ class TestRasterizePoints(TestCaseMixin, unittest.TestCase): ...@@ -167,20 +164,8 @@ class TestRasterizePoints(TestCaseMixin, unittest.TestCase):
points_cuda = points_cpu.cuda().detach().requires_grad_(True) points_cuda = points_cpu.cuda().detach().requires_grad_(True)
pointclouds_cpu = Pointclouds(points=points_cpu) pointclouds_cpu = Pointclouds(points=points_cpu)
pointclouds_cuda = Pointclouds(points=points_cuda) pointclouds_cuda = Pointclouds(points=points_cuda)
args_cpu = ( args_cpu = (pointclouds_cpu, image_size, radius, points_per_pixel, bin_size)
pointclouds_cpu, args_cuda = (pointclouds_cuda, image_size, radius, points_per_pixel, bin_size)
image_size,
radius,
points_per_pixel,
bin_size,
)
args_cuda = (
pointclouds_cuda,
image_size,
radius,
points_per_pixel,
bin_size,
)
self._compare_impls( self._compare_impls(
rasterize_points, rasterize_points,
rasterize_points, rasterize_points,
...@@ -332,9 +317,7 @@ class TestRasterizePoints(TestCaseMixin, unittest.TestCase): ...@@ -332,9 +317,7 @@ class TestRasterizePoints(TestCaseMixin, unittest.TestCase):
], device=device) ], device=device)
# fmt: on # fmt: on
dists1_expected = torch.zeros( dists1_expected = torch.zeros((5, 5, 2), dtype=torch.float32, device=device)
(5, 5, 2), dtype=torch.float32, device=device
)
# fmt: off # fmt: off
dists1_expected[:, :, 0] = torch.tensor([ dists1_expected[:, :, 0] = torch.tensor([
[-1.00, -1.00, 0.16, -1.00, -1.00], # noqa: E241 [-1.00, -1.00, 0.16, -1.00, -1.00], # noqa: E241
......
# Copyright (c) Facebook, Inc. and its affiliates. All rights reserved. # Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
import numpy as np
import unittest import unittest
from pathlib import Path from pathlib import Path
import numpy as np
import torch import torch
from PIL import Image from PIL import Image
from pytorch3d.renderer.cameras import OpenGLPerspectiveCameras, look_at_view_transform
from pytorch3d.renderer.cameras import ( from pytorch3d.renderer.mesh.rasterizer import MeshRasterizer, RasterizationSettings
OpenGLPerspectiveCameras,
look_at_view_transform,
)
from pytorch3d.renderer.mesh.rasterizer import (
MeshRasterizer,
RasterizationSettings,
)
from pytorch3d.utils.ico_sphere import ico_sphere from pytorch3d.utils.ico_sphere import ico_sphere
DATA_DIR = Path(__file__).resolve().parent / "data" DATA_DIR = Path(__file__).resolve().parent / "data"
DEBUG = False # Set DEBUG to true to save outputs from the tests. DEBUG = False # Set DEBUG to true to save outputs from the tests.
...@@ -52,9 +47,7 @@ class TestMeshRasterizer(unittest.TestCase): ...@@ -52,9 +47,7 @@ class TestMeshRasterizer(unittest.TestCase):
) )
# Init rasterizer # Init rasterizer
rasterizer = MeshRasterizer( rasterizer = MeshRasterizer(cameras=cameras, raster_settings=raster_settings)
cameras=cameras, raster_settings=raster_settings
)
#################################### ####################################
# 1. Test rasterizing a single mesh # 1. Test rasterizing a single mesh
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment