3D data file format – Ply files
The PLY file format was developed in the mid-1990s by a group of researchers from Stanford University. It has since evolved into one of the most widely used 3D data file formats. The file format has both an ASCII version and a binary version. The binary version is preferred in cases where file sizes and processing efficiencies are needed. The ASCII version makes it quite easy to debug. Here, we will discuss the basic format of PLY files and how to use both Open3D and PyTorch3D to load and visualize 3D data from PLY files.
In this section, we are going to discuss the two most frequently used data file formats to represent point clouds and meshes, the PLY file format and the OBJ file format. We are going to discuss the formats and how to load and save these file formats using PyTorch3D. PyTorch3D provides excellent utility functions, so loading from and saving to these file formats is efficient and easy using these utility functions.
An example, a cube.ply
file, is shown in the following code snippet:
ply
format ascii 1.0
comment created for the book 3D Deep Learning with Python
element vertex 8
property float32 x
property float32 y
property float32 z
element face 12
property list uint8 int32 vertex_indices
end_header
-1 -1 -1
1 -1 -1
1 1 -1
-1 1 -1
-1 -1 1
1 -1 1
1 1 1
-1 1 1
3 0 1 2
3 5 4 7
3 6 2 1
3 3 7 4
3 7 3 2
3 5 1 0
3 0 2 3
3 5 7 6
3 6 1 5
3 3 4 0
3 7 2 6
3 5 0 4
As seen here, each PLY file contains a header part and a data part. The first line of every ASCII PLY file is always ply
, which indicates that this is a PLY file. The second line, format ascii 1.0
, shows that the file is of the Ascii type with a version number. Any lines starting with comment
will be considered as a comment line, and thus anything following comment
will be ignored when the PLY file is loaded by a computer. The element vertex 8
line means that the first type of data in the PLY file is vertex and we have eight vertices. property float32 x
means that each vertex has a property named x
of the float32 type
. Similarly, each vertex also has y
and z
properties. Here, each vertex is one 3D point. The element face 12 line
means that the second type of data in this PLY file is of the face
type and we have 12 faces. property list unit8 int32 vertex_indices
shows that each face will be a list of vertex indices. The header part of the ply
file always ends with an end_header
line.
The first part of the data part of the PLY file consists of eight lines, where each line is the record for one vertex. The three numbers in each line represent the three x
, y
, and z
properties of the vertex. For example, the three numbers -1, -1, -1 specify that the vertex has an x
coordinate of -1
, y
coordinate of -1
, and z
coordinate of -1
.
The second part of the data part of the ply file consists of 12 lines, where each line is the record for one face. The first number in the sequence of numbers indicates the number of vertices that the face has, and the following numbers are the vertex indices. The vertex indices are determined by the order that the vertices are declared in the PLY file.
We can use both Open3D and PyTorch3D to open the preceding file. Open3D is a Python package that is very handy for visualizing 3D data, and PyTorch3D is handy for using this data for deep learning models. The following is a code snippet, ply_example1.py
, for visualizing the mesh in the cube.ply
file and loading the vertices and meshes as PyTorch tensors:
import open3d
from pytorch3d.io import load_ply
mesh_file = "cube.ply"
print('visualizing the mesh using open3D')
mesh = open3d.io.read_triangle_mesh(mesh_file)
open3d.visualization.draw_geometries([mesh],
       mesh_show_wireframe = True,
       mesh_show_back_face = True)
print("Loading the same file with PyTorch3D")
vertices, faces = load_ply(mesh_file)
print('Type of vertices = ', type(vertices))
print("type of faces = ", type(faces))
print('vertices = ', vertices)
print('faces = ', faces)
In the preceding Python code snippet, a cube.ply
mesh file is first opened by the open3d
package by using the read_triangle_mesh
function and all the 3D data is read into the mesh variable. The mesh can then be visualized using the Open3D library draw_geometries
function. When you run this function, the Open3D library will pop up a window for interactively visualizing the mesh – that is, you can rotate, zoom into, and zoom out of the mesh using your mouse interactively. The cube.ply
file, as you can guess, defines a mesh of a cube with eight vertices and six sides, where each side is covered by two faces.
We can also use the PyTorch3D
library to load the same mesh. However, this time, we are going to obtain several PyTorch tensors – for example, one tensor for vertices and one tensor for faces. These tensors can be input into any PyTorch deep learning model directly. In this example, the load_ply
function returns a tuple of vertices and faces, both of which are conventionally in the format of PyTorch tensors. When you run this ply_example1.py
code snippet, the returned vertices should be a PyTorch tensor with a shape of [8, 3]
– that is, there are eight vertices, and each vertex has three coordinates. Similarly, the returned faces should be a PyTorch tensor with a shape of [12, 3], that is, there are 12 faces, and each face has 3 vertex indices.
In the following code snippet, we show another example of the parallel_plane_mono.ply
file, which can also be downloaded from our GitHub repository. The only difference between the mesh in this example and the mesh in the cube is.ply
file is the number of faces. Instead of the six sides of a cube, here we have only four faces, which form two parallel planes:
ply
format ascii 1.0
comment created for the book 3D Deep Learning with Python
element vertex 8
property float32 x
property float32 y
property float32 z
element face 4
property list uint8 int32 vertex_indices
end_header
-1 -1 -1
1 -1 -1
1 1 -1
-1 1 -1
-1 -1 1
1 -1 1
1 1 1
-1 1 1
3 0 1 2
3 0 2 3
3 5 4 7
3 5 7 6
The mesh can be interactively visualized by the following ply_example2.py
:
- First, we import all the needed Python libraries:
import open3d from pytorch3d.io import load_ply
- We load the mesh using
open3d
:mesh_file = "parallel_plane_mono.ply" print('visualizing the mesh using open3D') mesh = open3d.io.read_triangle_mesh(mesh_file)
- We use
draw_geometries
to open a window for visualizing interactively with the mesh:open3d.visualization.draw_geometries([mesh], Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â mesh_show_wireframe = True, Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â mesh_show_back_face = True)
- We use
pytorch3d
to open the same mesh:print("Loading the same file with PyTorch3D") vertices, faces = load_ply(mesh_file)
- We can print out the information about the loaded vertices and faces. In fact, they are just ordinary PyTorch3D tensors:
print('Type of vertices = ', type(vertices), ", type of faces = ", type(faces)) print('vertices = ', vertices) print('faces = ', faces)
For each vertex, we can also define properties other than the x, y, and z coordinates. For example, we can also define colors for each vertex. An example of parallel_plane_color.ply
is shown here:
ply
format ascii 1.0
comment created for the book 3D Deep Learning with Python
element vertex 8
property float32 x
property float32 y
property float32 z
property uchar red
property uchar green
property uchar blue
element face 4
property list uint8 int32 vertex_indices
end_header
-1 -1 -1 255 0 0
1 -1 -1 255 0 0
1 1 -1 255 0 0
-1 1 -1 255 0 0
-1 -1 1 0 0 255
1 -1 1 0 0 255
1 1 1 0 0 255
-1 1 1 0 0 255
3 0 1 2
3 0 2 3
3 5 4 7
3 5 7 6
Note that in the preceding example, along with x, y, and z, we also define some additional properties for each vertex – that is, the red, green, and blue properties, all in the uchar
data type. Now, each record for one vertex is one line of six numbers. The first three are x, y, and z coordinates. The following three numbers are the RGB values.
The mesh can be visualized by using ply_example3.py
as follows:
import open3d
from pytorch3d.io import load_ply
mesh_file = "parallel_plane_color.ply"
print('visualizing the mesh using open3D')
mesh = open3d.io.read_triangle_mesh(mesh_file)
open3d.visualization.draw_geometries([mesh],
                     mesh_show_wireframe = True,
                     mesh_show_back_face = True)
print("Loading the same file with PyTorch3D")
vertices, faces = load_ply(mesh_file)
print('Type of vertices = ', type(vertices), ", type of faces = ", type(faces))
print('vertices = ', vertices)
print('faces = ', faces)
We also provide cow.ply
, which is a real-world example of a 3D mesh. The readers can visualize the mesh using ply_example4.py
.
By now, we have talked about the basic elements of the PLY file format, such as vertices and faces. Next, we will discuss the OBJ 3D data format.