1010meshes and point clouds as PLY files.
1111"""
1212import itertools
13+ import os
1314import struct
1415import sys
1516import warnings
2122import numpy as np
2223import torch
2324from iopath .common .file_io import PathManager
24- from pytorch3d .io .utils import _check_faces_indices , _make_tensor , _open_file , PathOrStr
25- from pytorch3d .renderer import TexturesVertex
25+ from pytorch3d .io .utils import (
26+ _check_faces_indices ,
27+ _make_tensor ,
28+ _open_file ,
29+ _read_image ,
30+ PathOrStr ,
31+ )
32+ from pytorch3d .renderer import TexturesUV , TexturesVertex
2633from pytorch3d .structures import Meshes , Pointclouds
2734
2835from .pluggable_formats import (
@@ -804,6 +811,7 @@ class _VertsColumnIndices:
804811 color_idxs : Optional [List [int ]]
805812 color_scale : float
806813 normal_idxs : Optional [List [int ]]
814+ texture_uv_idxs : Optional [List [int ]]
807815
808816
809817def _get_verts_column_indices (
@@ -827,6 +835,8 @@ def _get_verts_column_indices(
827835 property uchar red
828836 property uchar green
829837 property uchar blue
838+ property double texture_u
839+ property double texture_v
830840
831841 then the return value will be ([0,1,2], [6,7,8], 1.0/255, [3,4,5])
832842
@@ -839,6 +849,7 @@ def _get_verts_column_indices(
839849 point_idxs : List [Optional [int ]] = [None , None , None ]
840850 color_idxs : List [Optional [int ]] = [None , None , None ]
841851 normal_idxs : List [Optional [int ]] = [None , None , None ]
852+ texture_uv_idxs : List [Optional [int ]] = [None , None ]
842853 for i , prop in enumerate (vertex_head .properties ):
843854 if prop .list_size_type is not None :
844855 raise ValueError ("Invalid vertices in file: did not expect list." )
@@ -851,6 +862,9 @@ def _get_verts_column_indices(
851862 for j , name in enumerate (["nx" , "ny" , "nz" ]):
852863 if prop .name == name :
853864 normal_idxs [j ] = i
865+ for j , name in enumerate (["texture_u" , "texture_v" ]):
866+ if prop .name == name :
867+ texture_uv_idxs [j ] = i
854868 if None in point_idxs :
855869 raise ValueError ("Invalid vertices in file." )
856870 color_scale = 1.0
@@ -864,6 +878,7 @@ def _get_verts_column_indices(
864878 color_idxs = None if None in color_idxs else color_idxs ,
865879 color_scale = color_scale ,
866880 normal_idxs = None if None in normal_idxs else normal_idxs ,
881+ texture_uv_idxs = None if None in texture_uv_idxs else texture_uv_idxs ,
867882 )
868883
869884
@@ -880,6 +895,7 @@ class _VertsData:
880895 verts : torch .Tensor
881896 verts_colors : Optional [torch .Tensor ] = None
882897 verts_normals : Optional [torch .Tensor ] = None
898+ verts_texture_uvs : Optional [torch .Tensor ] = None
883899
884900
885901def _get_verts (header : _PlyHeader , elements : dict ) -> _VertsData :
@@ -922,6 +938,7 @@ def _get_verts(header: _PlyHeader, elements: dict) -> _VertsData:
922938
923939 vertex_colors = None
924940 vertex_normals = None
941+ vertex_texture_uvs = None
925942
926943 if len (vertex ) == 1 :
927944 # This is the case where the whole vertex element has one type,
@@ -935,6 +952,10 @@ def _get_verts(header: _PlyHeader, elements: dict) -> _VertsData:
935952 vertex_normals = torch .tensor (
936953 vertex [0 ][:, column_idxs .normal_idxs ], dtype = torch .float32
937954 )
955+ if column_idxs .texture_uv_idxs is not None :
956+ vertex_texture_uvs = torch .tensor (
957+ vertex [0 ][:, column_idxs .texture_uv_idxs ], dtype = torch .float32
958+ )
938959 else :
939960 # The vertex element is heterogeneous. It was read as several arrays,
940961 # part by part, where a part is a set of properties with the same type.
@@ -973,11 +994,19 @@ def _get_verts(header: _PlyHeader, elements: dict) -> _VertsData:
973994 for axis in range (3 ):
974995 partnum , col = prop_to_partnum_col [column_idxs .normal_idxs [axis ]]
975996 vertex_normals .numpy ()[:, axis ] = vertex [partnum ][:, col ]
976-
997+ if column_idxs .texture_uv_idxs is not None :
998+ vertex_texture_uvs = torch .empty (
999+ size = (vertex_head .count , 2 ),
1000+ dtype = torch .float32 ,
1001+ )
1002+ for axis in range (2 ):
1003+ partnum , col = prop_to_partnum_col [column_idxs .texture_uv_idxs [axis ]]
1004+ vertex_texture_uvs .numpy ()[:, axis ] = vertex [partnum ][:, col ]
9771005 return _VertsData (
9781006 verts = verts ,
9791007 verts_colors = vertex_colors ,
9801008 verts_normals = vertex_normals ,
1009+ verts_texture_uvs = vertex_texture_uvs ,
9811010 )
9821011
9831012
@@ -998,6 +1027,7 @@ class _PlyData:
9981027 faces : Optional [torch .Tensor ]
9991028 verts_colors : Optional [torch .Tensor ]
10001029 verts_normals : Optional [torch .Tensor ]
1030+ verts_texture_uvs : Optional [torch .Tensor ]
10011031
10021032
10031033def _load_ply (f , * , path_manager : PathManager ) -> _PlyData :
@@ -1358,8 +1388,27 @@ def read(
13581388 faces = torch .zeros (0 , 3 , dtype = torch .int64 )
13591389
13601390 texture = None
1361- if include_textures and data .verts_colors is not None :
1362- texture = TexturesVertex ([data .verts_colors .to (device )])
1391+ if include_textures :
1392+ if data .verts_colors is not None :
1393+ texture = TexturesVertex ([data .verts_colors .to (device )])
1394+ elif data .verts_texture_uvs is not None :
1395+ texture_file_path = None
1396+ for comment in data .header .comments :
1397+ if "TextureFile" in comment :
1398+ given_texture_file = comment .split (" " )[- 1 ]
1399+ texture_file_path = os .path .join (
1400+ os .path .dirname (str (path )), given_texture_file
1401+ )
1402+ if texture_file_path is not None :
1403+ texture_map = _read_image (
1404+ texture_file_path , path_manager , format = "RGB"
1405+ )
1406+ texture_map = torch .tensor (texture_map , dtype = torch .float32 ) / 255.0
1407+ texture = TexturesUV (
1408+ [texture_map .to (device )],
1409+ [faces .to (device )],
1410+ [data .verts_texture_uvs .to (device )],
1411+ )
13631412
13641413 verts_normals = None
13651414 if data .verts_normals is not None :
0 commit comments