in pytorch3d/structures/pointclouds.py [0:0]
def __init__(self, points, normals=None, features=None) -> None:
"""
Args:
points:
Can be either
- List where each element is a tensor of shape (num_points, 3)
containing the (x, y, z) coordinates of each point.
- Padded float tensor with shape (num_clouds, num_points, 3).
normals:
Can be either
- List where each element is a tensor of shape (num_points, 3)
containing the normal vector for each point.
- Padded float tensor of shape (num_clouds, num_points, 3).
features:
Can be either
- List where each element is a tensor of shape (num_points, C)
containing the features for the points in the cloud.
- Padded float tensor of shape (num_clouds, num_points, C).
where C is the number of channels in the features.
For example 3 for RGB color.
Refer to comments above for descriptions of List and Padded
representations.
"""
self.device = torch.device("cpu")
# Indicates whether the clouds in the list/batch have the same number
# of points.
self.equisized = False
# Boolean indicator for each cloud in the batch.
# True if cloud has non zero number of points, False otherwise.
self.valid = None
self._N = 0 # batch size (number of clouds)
self._P = 0 # (max) number of points per cloud
self._C = None # number of channels in the features
# List of Tensors of points and features.
self._points_list = None
self._normals_list = None
self._features_list = None
# Number of points per cloud.
self._num_points_per_cloud = None # N
# Packed representation.
self._points_packed = None # (sum(P_n), 3)
self._normals_packed = None # (sum(P_n), 3)
self._features_packed = None # (sum(P_n), C)
self._packed_to_cloud_idx = None # sum(P_n)
# Index of each cloud's first point in the packed points.
# Assumes packing is sequential.
self._cloud_to_packed_first_idx = None # N
# Padded representation.
self._points_padded = None # (N, max(P_n), 3)
self._normals_padded = None # (N, max(P_n), 3)
self._features_padded = None # (N, max(P_n), C)
# Index to convert points from flattened padded to packed.
self._padded_to_packed_idx = None # N * max_P
# Identify type of points.
if isinstance(points, list):
self._points_list = points
self._N = len(self._points_list)
self.valid = torch.zeros((self._N,), dtype=torch.bool, device=self.device)
self._num_points_per_cloud = []
if self._N > 0:
self.device = self._points_list[0].device
for p in self._points_list:
if len(p) > 0 and (p.dim() != 2 or p.shape[1] != 3):
raise ValueError("Clouds in list must be of shape Px3 or empty")
if p.device != self.device:
raise ValueError("All points must be on the same device")
num_points_per_cloud = torch.tensor(
[len(p) for p in self._points_list], device=self.device
)
self._P = int(num_points_per_cloud.max())
self.valid = torch.tensor(
[len(p) > 0 for p in self._points_list],
dtype=torch.bool,
device=self.device,
)
if len(num_points_per_cloud.unique()) == 1:
self.equisized = True
self._num_points_per_cloud = num_points_per_cloud
elif torch.is_tensor(points):
if points.dim() != 3 or points.shape[2] != 3:
raise ValueError("Points tensor has incorrect dimensions.")
self._points_padded = points
self._N = self._points_padded.shape[0]
self._P = self._points_padded.shape[1]
self.device = self._points_padded.device
self.valid = torch.ones((self._N,), dtype=torch.bool, device=self.device)
self._num_points_per_cloud = torch.tensor(
[self._P] * self._N, device=self.device
)
self.equisized = True
else:
raise ValueError(
"Points must be either a list or a tensor with \
shape (batch_size, P, 3) where P is the maximum number of \
points in a cloud."
)
# parse normals
normals_parsed = self._parse_auxiliary_input(normals)
self._normals_list, self._normals_padded, normals_C = normals_parsed
if normals_C is not None and normals_C != 3:
raise ValueError("Normals are expected to be 3-dimensional")
# parse features
features_parsed = self._parse_auxiliary_input(features)
self._features_list, self._features_padded, features_C = features_parsed
if features_C is not None:
self._C = features_C