Spaces:
Runtime error
Runtime error
| import warnings | |
| from typing import List, Optional, Union | |
| import torch | |
| from pytorch3d.io import IO | |
| from pytorch3d.io import load_objs_as_meshes as _load_objs_as_meshes | |
| from pytorch3d.io import save_obj | |
| from pytorch3d.renderer import TexturesUV, TexturesVertex | |
| from pytorch3d.structures import ( | |
| Meshes, | |
| Pointclouds, | |
| join_meshes_as_batch, | |
| join_meshes_as_scene, | |
| padded_to_list, | |
| ) | |
| from .path_utils import prepare_output_path | |
| def join_batch_meshes_as_scene( | |
| meshes: List[Meshes], | |
| include_textures: bool = True, | |
| ) -> Meshes: | |
| """Join `meshes` as a scene each batch. Only for Pytorch3D `meshes`. The | |
| Meshes must share the same batch size, and topology could be different. | |
| They must all be on the same device. If `include_textures` is true, the | |
| textures should be the same type, all be None is not accepted. If | |
| `include_textures` is False, textures are ignored. The return meshes will | |
| have no textures. | |
| Args: | |
| meshes (List[Meshes]): A `list` of `Meshes` with the same batches. | |
| Required. | |
| include_textures: (bool) whether to try to join the textures. | |
| Returns: | |
| New Meshes which has join different Meshes by each batch. | |
| """ | |
| for mesh in meshes: | |
| mesh._verts_list = padded_to_list(mesh.verts_padded(), | |
| mesh.num_verts_per_mesh().tolist()) | |
| num_scene_size = len(meshes) | |
| num_batch_size = len(meshes[0]) | |
| for i in range(num_scene_size): | |
| assert len( | |
| meshes[i] | |
| ) == num_batch_size, 'Please make sure that the Meshes all have' | |
| 'the same batch size.' | |
| meshes_all = [] | |
| for j in range(num_batch_size): | |
| meshes_batch = [] | |
| for i in range(num_scene_size): | |
| meshes_batch.append(meshes[i][j]) | |
| meshes_all.append(join_meshes_as_scene(meshes_batch, include_textures)) | |
| meshes_final = join_meshes_as_batch(meshes_all, include_textures) | |
| return meshes_final | |
| def mesh_to_pointcloud_vc( | |
| meshes: Meshes, | |
| include_textures: bool = True, | |
| alpha: float = 1.0, | |
| ) -> Pointclouds: | |
| """Convert PyTorch3D vertex color `Meshes` to `PointClouds`. | |
| Args: | |
| meshes (Meshes): input meshes. | |
| include_textures (bool, optional): Whether include colors. | |
| Require the texture of input meshes is vertex color. | |
| Defaults to True. | |
| alpha (float, optional): transparency. | |
| Defaults to 1.0. | |
| Returns: | |
| Pointclouds: output pointclouds. | |
| """ | |
| assert isinstance( | |
| meshes.textures, | |
| TexturesVertex), 'textures of input meshes should be `TexturesVertex`' | |
| vertices = meshes.verts_padded() | |
| if include_textures: | |
| verts_rgb = meshes.textures.verts_features_padded() | |
| verts_rgba = torch.cat( | |
| [verts_rgb, | |
| torch.ones_like(verts_rgb)[..., 0:1] * alpha], dim=-1) | |
| else: | |
| verts_rgba = None | |
| pointclouds = Pointclouds(points=vertices, features=verts_rgba) | |
| return pointclouds | |
| def texture_uv2vc(meshes: Meshes) -> Meshes: | |
| """Convert a Pytorch3D meshes's textures from TexturesUV to TexturesVertex. | |
| Args: | |
| meshes (Meshes): input Meshes. | |
| Returns: | |
| Meshes: converted Meshes. | |
| """ | |
| assert isinstance(meshes.textures, TexturesUV) | |
| device = meshes.device | |
| vert_uv = meshes.textures.verts_uvs_padded() | |
| batch_size = vert_uv.shape[0] | |
| verts_features = [] | |
| num_verts = meshes.verts_padded().shape[1] | |
| for index in range(batch_size): | |
| face_uv = vert_uv[index][meshes.textures.faces_uvs_padded() | |
| [index].view(-1)] | |
| img = meshes.textures._maps_padded[index] | |
| width, height, _ = img.shape | |
| face_uv = face_uv * torch.Tensor([width - 1, height - 1 | |
| ]).long().to(device) | |
| face_uv[:, 0] = torch.clip(face_uv[:, 0], 0, width - 1) | |
| face_uv[:, 1] = torch.clip(face_uv[:, 1], 0, height - 1) | |
| face_uv = face_uv.long() | |
| faces = meshes.faces_padded() | |
| verts_rgb = torch.zeros(1, num_verts, 3).to(device) | |
| verts_rgb[:, faces.view(-1)] = img[height - 1 - face_uv[:, 1], | |
| face_uv[:, 0]] | |
| verts_features.append(verts_rgb) | |
| verts_features = torch.cat(verts_features) | |
| meshes = meshes.clone() | |
| meshes.textures = TexturesVertex(verts_features) | |
| return meshes | |
| def load_objs_as_meshes(files: List[str], | |
| device: Optional[Union[torch.device, str]] = None, | |
| load_textures: bool = True, | |
| **kwargs) -> Meshes: | |
| if not isinstance(files, list): | |
| files = [files] | |
| return _load_objs_as_meshes(files=files, | |
| device=device, | |
| load_textures=load_textures, | |
| **kwargs) | |
| def load_plys_as_meshes( | |
| files: List[str], | |
| device: Optional[Union[torch.device, str]] = None, | |
| load_textures: bool = True, | |
| ) -> Meshes: | |
| writer = IO() | |
| meshes = [] | |
| if not isinstance(files, list): | |
| files = [files] | |
| for idx in range(len(files)): | |
| assert files[idx].endswith('.ply'), 'Please input .ply files.' | |
| mesh = writer.load_mesh(path=files[idx], | |
| include_textures=load_textures, | |
| device=device) | |
| meshes.append(mesh) | |
| meshes = join_meshes_as_batch(meshes, include_textures=load_textures) | |
| return meshes | |
| def save_meshes_as_plys(files: List[str], | |
| meshes: Meshes = None, | |
| verts: torch.Tensor = None, | |
| faces: torch.Tensor = None, | |
| verts_rgb: torch.Tensor = None) -> None: | |
| """Save meshes as .ply files. Mainly for vertex color meshes. | |
| Args: | |
| files (List[str]): Output .ply file list. | |
| meshes (Meshes, optional): higher priority than | |
| (verts & faces & verts_rgb). Defaults to None. | |
| verts (torch.Tensor, optional): lower priority than meshes. | |
| Defaults to None. | |
| faces (torch.Tensor, optional): lower priority than meshes. | |
| Defaults to None. | |
| verts_rgb (torch.Tensor, optional): lower priority than meshes. | |
| Defaults to None. | |
| """ | |
| if meshes is None: | |
| assert verts is not None and faces is not None, 'Not mesh input.' | |
| meshes = Meshes( | |
| verts=verts, | |
| faces=faces, | |
| textures=TexturesVertex( | |
| verts_features=verts_rgb) if verts_rgb is not None else None) | |
| else: | |
| if verts is not None or faces is not None or verts_rgb is not None: | |
| warnings.warn('Redundant input, will use meshes only.') | |
| assert files is not None | |
| if not isinstance(files, list): | |
| files = [files] | |
| assert len(files) >= len(meshes), 'Not enough output files.' | |
| writer = IO() | |
| for idx in range(len(meshes)): | |
| assert files[idx].endswith('.ply'), 'Please save as .ply files.' | |
| writer.save_mesh(meshes[idx], | |
| files[idx], | |
| colors_as_uint8=True, | |
| binary=False) | |
| def save_meshes_as_objs(files: List[str], meshes: Meshes = None) -> None: | |
| """Save meshes as .obj files. Pytorch3D will not save vertex color for. | |
| .obj, please use `save_meshes_as_plys`. | |
| Args: | |
| files (List[str]): Output .obj file list. | |
| meshes (Meshes, optional): | |
| Defaults to None. | |
| """ | |
| if not isinstance(files, list): | |
| files = [files] | |
| assert len(files) >= len(meshes), 'Not enough output files.' | |
| for idx in range(len(meshes)): | |
| prepare_output_path(files[idx], | |
| allowed_suffix=['.obj'], | |
| path_type='file'), 'Please save as .obj files.' | |
| if isinstance(meshes.textures, TexturesUV): | |
| verts_uvs = meshes.textures.verts_uvs_padded()[idx] | |
| faces_uvs = meshes.textures.faces_uvs_padded()[idx] | |
| texture_map = meshes.textures.maps_padded()[idx] | |
| else: | |
| verts_uvs = None | |
| faces_uvs = None | |
| texture_map = None | |
| save_obj(f=files[idx], | |
| verts=meshes.verts_padded()[idx], | |
| faces=meshes.faces_padded()[idx], | |
| verts_uvs=verts_uvs, | |
| faces_uvs=faces_uvs, | |
| texture_map=texture_map) | |