mirror of
https://github.com/facebookresearch/pytorch3d.git
synced 2025-10-14 07:12:49 +08:00
Reviewed By: MichaelRamamonjisoa Differential Revision: D83477594 fbshipit-source-id: 5ea67543e288e9a06ee5141f436e879aa5cfb7f3
167 lines
5.7 KiB
Python
167 lines
5.7 KiB
Python
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
# All rights reserved.
|
|
#
|
|
# This source code is licensed under the BSD-style license found in the
|
|
# LICENSE file in the root directory of this source tree.
|
|
|
|
import unittest
|
|
|
|
import numpy as np
|
|
import torch
|
|
from pytorch3d.structures.pointclouds import Pointclouds
|
|
|
|
from .common_testing import needs_multigpu, TestCaseMixin
|
|
|
|
|
|
class TestPointclouds(TestCaseMixin, unittest.TestCase):
|
|
def setUp(self) -> None:
|
|
np.random.seed(42)
|
|
torch.manual_seed(42)
|
|
|
|
@staticmethod
|
|
def init_cloud(
|
|
num_clouds: int = 3,
|
|
max_points: int = 100,
|
|
channels: int = 4,
|
|
lists_to_tensors: bool = False,
|
|
with_normals: bool = True,
|
|
with_features: bool = True,
|
|
min_points: int = 0,
|
|
requires_grad: bool = False,
|
|
):
|
|
"""
|
|
Function to generate a Pointclouds object of N meshes with
|
|
random number of points.
|
|
|
|
Args:
|
|
num_clouds: Number of clouds to generate.
|
|
channels: Number of features.
|
|
max_points: Max number of points per cloud.
|
|
lists_to_tensors: Determines whether the generated clouds should be
|
|
constructed from lists (=False) or
|
|
tensors (=True) of points/normals/features.
|
|
with_normals: bool whether to include normals
|
|
with_features: bool whether to include features
|
|
min_points: Min number of points per cloud
|
|
|
|
Returns:
|
|
Pointclouds object.
|
|
"""
|
|
device = torch.device("cuda:0")
|
|
p = torch.randint(low=min_points, high=max_points, size=(num_clouds,))
|
|
if lists_to_tensors:
|
|
p.fill_(p[0])
|
|
|
|
points_list = [
|
|
torch.rand(
|
|
(i, 3), device=device, dtype=torch.float32, requires_grad=requires_grad
|
|
)
|
|
for i in p
|
|
]
|
|
normals_list, features_list = None, None
|
|
if with_normals:
|
|
normals_list = [
|
|
torch.rand(
|
|
(i, 3),
|
|
device=device,
|
|
dtype=torch.float32,
|
|
requires_grad=requires_grad,
|
|
)
|
|
for i in p
|
|
]
|
|
if with_features:
|
|
features_list = [
|
|
torch.rand(
|
|
(i, channels),
|
|
device=device,
|
|
dtype=torch.float32,
|
|
requires_grad=requires_grad,
|
|
)
|
|
for i in p
|
|
]
|
|
|
|
if lists_to_tensors:
|
|
points_list = torch.stack(points_list)
|
|
if with_normals:
|
|
normals_list = torch.stack(normals_list)
|
|
if with_features:
|
|
features_list = torch.stack(features_list)
|
|
|
|
return Pointclouds(points_list, normals=normals_list, features=features_list)
|
|
|
|
@needs_multigpu
|
|
def test_to_list(self):
|
|
cloud = self.init_cloud(5, 100, 10)
|
|
device = torch.device("cuda:1")
|
|
|
|
new_cloud = cloud.to(device)
|
|
self.assertTrue(new_cloud.device == device)
|
|
self.assertTrue(cloud.device == torch.device("cuda:0"))
|
|
for attrib in [
|
|
"points_padded",
|
|
"points_packed",
|
|
"normals_padded",
|
|
"normals_packed",
|
|
"features_padded",
|
|
"features_packed",
|
|
"num_points_per_cloud",
|
|
"cloud_to_packed_first_idx",
|
|
"padded_to_packed_idx",
|
|
]:
|
|
self.assertClose(
|
|
getattr(new_cloud, attrib)().cpu(), getattr(cloud, attrib)().cpu()
|
|
)
|
|
for i in range(len(cloud)):
|
|
self.assertClose(
|
|
cloud.points_list()[i].cpu(), new_cloud.points_list()[i].cpu()
|
|
)
|
|
self.assertClose(
|
|
cloud.normals_list()[i].cpu(), new_cloud.normals_list()[i].cpu()
|
|
)
|
|
self.assertClose(
|
|
cloud.features_list()[i].cpu(), new_cloud.features_list()[i].cpu()
|
|
)
|
|
self.assertTrue(all(cloud.valid.cpu() == new_cloud.valid.cpu()))
|
|
self.assertTrue(cloud.equisized == new_cloud.equisized)
|
|
self.assertTrue(cloud._N == new_cloud._N)
|
|
self.assertTrue(cloud._P == new_cloud._P)
|
|
self.assertTrue(cloud._C == new_cloud._C)
|
|
|
|
@needs_multigpu
|
|
def test_to_tensor(self):
|
|
cloud = self.init_cloud(5, 100, 10, lists_to_tensors=True)
|
|
device = torch.device("cuda:1")
|
|
|
|
new_cloud = cloud.to(device)
|
|
self.assertTrue(new_cloud.device == device)
|
|
self.assertTrue(cloud.device == torch.device("cuda:0"))
|
|
for attrib in [
|
|
"points_padded",
|
|
"points_packed",
|
|
"normals_padded",
|
|
"normals_packed",
|
|
"features_padded",
|
|
"features_packed",
|
|
"num_points_per_cloud",
|
|
"cloud_to_packed_first_idx",
|
|
"padded_to_packed_idx",
|
|
]:
|
|
self.assertClose(
|
|
getattr(new_cloud, attrib)().cpu(), getattr(cloud, attrib)().cpu()
|
|
)
|
|
for i in range(len(cloud)):
|
|
self.assertClose(
|
|
cloud.points_list()[i].cpu(), new_cloud.points_list()[i].cpu()
|
|
)
|
|
self.assertClose(
|
|
cloud.normals_list()[i].cpu(), new_cloud.normals_list()[i].cpu()
|
|
)
|
|
self.assertClose(
|
|
cloud.features_list()[i].cpu(), new_cloud.features_list()[i].cpu()
|
|
)
|
|
self.assertTrue(all(cloud.valid.cpu() == new_cloud.valid.cpu()))
|
|
self.assertTrue(cloud.equisized == new_cloud.equisized)
|
|
self.assertTrue(cloud._N == new_cloud._N)
|
|
self.assertTrue(cloud._P == new_cloud._P)
|
|
self.assertTrue(cloud._C == new_cloud._C)
|