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
......
This diff is collapsed.
...@@ -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()
......
This diff is collapsed.
...@@ -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()
......
This diff is collapsed.
This diff is collapsed.
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