Sign In Start Free Trial
Account

Add to playlist

Create a Playlist

Modal Close icon
You need to login to use this feature.
  • Book Overview & Buying 3D Deep Learning with Python
  • Table Of Contents Toc
3D Deep Learning with Python

3D Deep Learning with Python

By : Xudong Ma, David Farrugia, Vishakh Hegde, Lilit Yolyan
4.4 (5)
close
close
3D Deep Learning with Python

3D Deep Learning with Python

4.4 (5)
By: Xudong Ma, David Farrugia, Vishakh Hegde, Lilit Yolyan

Overview of this book

With this hands-on guide to 3D deep learning, developers working with 3D computer vision will be able to put their knowledge to work and get up and running in no time. Complete with step-by-step explanations of essential concepts and practical examples, this book lets you explore and gain a thorough understanding of state-of-the-art 3D deep learning. You’ll see how to use PyTorch3D for basic 3D mesh and point cloud data processing, including loading and saving ply and obj files, projecting 3D points into camera coordination using perspective camera models or orthographic camera models, rendering point clouds and meshes to images, and much more. As you implement some of the latest 3D deep learning algorithms, such as differential rendering, Nerf, synsin, and mesh RCNN, you’ll realize how coding for these deep learning models becomes easier using the PyTorch3D library. By the end of this deep learning book, you’ll be ready to implement your own 3D deep learning models confidently.
Table of Contents (16 chapters)
close
close
1
PART 1: 3D Data Processing Basics
4
PART 2: 3D Deep Learning Using PyTorch3D
9
PART 3: State-of-the-art 3D Deep Learning Using PyTorch3D

3D data file format – OBJ files

In this section, we are going to discuss another widely used 3D data file format, the OBJ file format. The OBJ file format was first developed by Wavefront Technologies Inc. Like the PLY file format, the OBJ format also has both an ASCII version and a binary version. The binary version is proprietary and undocumented. So, we are going to discuss the ASCII version in this section.

Like the previous section, here we are going to learn the file format by looking at examples. The first example, cube.obj, is shown as follows. As you can guess, the OBJ file defines a mesh of a cube.

The first line, mtlib ./cube.mtl, declares the companion Material Template Library (MTL) file. The MTL file describes surface shading properties, which will be explained in the next code snippet.

For the o cube line, the starting letter, o, indicates that the line defines an object, where the name of the object is cube. Any line starting with # is a comment line – that is, the rest of the line will be ignored by a computer. Each line starts with v, which indicates that each line defines a vertex. For example, v -0.5 -0.5 0.5 defines a vertex with an x coordinate of 0.5, a y coordinate of 0.5, and a z coordination of 0.5. For each line starting with f, f indicates that each line contains a definition for one face. For example, the f 1 2 3 line defines a face, with its three vertices being the vertices with indices 1, 2, and 3.

The usemtl Door line declares that the surfaces declared after this line should be shaded using a material property defined in the MTL file, named Door:

mtllib ./cube.mtl
o cube
# Vertex list
v -0.5 -0.5 0.5
v -0.5 -0.5 -0.5
v -0.5 0.5 -0.5
v -0.5 0.5 0.5
v 0.5 -0.5 0.5
v 0.5 -0.5 -0.5
v 0.5 0.5 -0.5
v 0.5 0.5 0.5
# Point/Line/Face list
usemtl Door
f 1 2 3
f 6 5 8
f 7 3 2
f 4 8 5
f 8 4 3
f 6 2 1
f 1 3 4
f 6 8 7
f 7 2 6
f 4 5 1
f 8 3 7
f 6 1 5

The cube.mtl companion MTL file is shown as follows. The file defines a material property called Door:

newmtl Door
Ka  0.8 0.6 0.4
Kd  0.8 0.6 0.4
Ks  0.9 0.9 0.9
d  1.0
Ns  0.0
illum 2

We will not discuss these material properties in detail except for map_Kd. If you are curious, you can refer to a standard computer graphics textbook such as Computer Graphics: Principles and Practice. We will list some rough descriptions of these properties as follows, just for the sake of completeness:

  • Ka: Specifies an ambient color
  • Kd: Specifies a diffuse color
  • Ks: Specifies a specular color
  • Ns: Defines the focus of specular highlights
  • Ni: Defines the optical density (a.k.a index of refraction)
  • d: Specifies a factor for dissolve
  • illum: Specifies an illumination model
  • map_Kd: Specifies a color texture file to be applied to the diffuse reflectivity of the material

The cube.obj file can be opened by both Open3D and PyTorch3D. The following code snippet, obj_example1.py, can be downloaded from our GitHub repository:

import open3d
from pytorch3d.io import load_obj
mesh_file = "cube.obj"
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, aux = load_obj(mesh_file)
print('Type of vertices = ', type(vertices))
print("Type of faces = ", type(faces))
print("Type of aux = ", type(aux))
print('vertices = ', vertices)
print('faces = ', faces)
print('aux = ', aux)

In the preceding code snippet, the defined mesh of a cube can be interactively visualized by using the Open3D draw_geometries function. The mesh will be shown in a window, and you can rotate, zoom into, and zoom out of the mesh using your mouse. The mesh can also be loaded using the PyTorch3D load_obj function. The load_obj function will return the vertices, faces, and aux variables, either in the format of a PyTorch tensor or tuples of PyTorch tensors.

An example output of the obj_example1.py code snippet is shown as follows:

visualizing the mesh using open3D
Loading the same file with PyTorch3D
Type of vertices =  <class 'torch.Tensor'>
Type of faces =  <class 'pytorch3d.io.obj_io.Faces'>
Type of aux =  <class 'pytorch3d.io.obj_io.Properties'>
vertices =  tensor([[-0.5000, -0.5000,  0.5000],
        [-0.5000, -0.5000, -0.5000],
        [-0.5000,  0.5000, -0.5000],
        [-0.5000,  0.5000,  0.5000],
        [ 0.5000, -0.5000,  0.5000],
        [ 0.5000, -0.5000, -0.5000],
        [ 0.5000,  0.5000, -0.5000],
        [ 0.5000,  0.5000,  0.5000]])
faces =  Faces(verts_idx=tensor([[0, 1, 2],
        [5, 4, 7],
        [6, 2, 1],
        ...
        [3, 4, 0],
        [7, 2, 6],
        [5, 0, 4]]), normals_idx=tensor([[-1, -1, -1],
        [-1, -1, -1],
        [-1, -1, -1],
        [-1, -1, -1],
        ...
        [-1, -1, -1],
        [-1, -1, -1]]), textures_idx=tensor([[-1, -1, -1],
        [-1, -1, -1],
        [-1, -1, -1],
        ...
        [-1, -1, -1],
        [-1, -1, -1]]), materials_idx=tensor([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]))
aux =  Properties(normals=None, verts_uvs=None, material_colors={'Door': {'ambient_color': tensor([0.8000, 0.6000, 0.4000]), 'diffuse_color': tensor([0.8000, 0.6000, 0.4000]), 'specular_color': tensor([0.9000, 0.9000, 0.9000]), 'shininess': tensor([0.])}}, texture_images={}, texture_atlas=None)

From the code snippet output here, we know that the returned vertices variable is a PyTorch tensor with a shape of 8 x 3, where each row is a vertex with the x, y, and z coordinates. The returned variable, faces, is a named tuple of three PyTorch tensors, verts_idx, normals_idx, and textures_idx. In the preceding example, all the normals_idx and textures_idx tensors are invalid because cube.obj does not include definitions for normal and textures. We will see in the next example how normals and textures can be defined in the OBJ file format. verts_idx is the vertex indices for each face. Note that the vertex indices are 0-indexed here in PyTorch3D, where the indices start from 0. However, the vertex indices in OBJ files are 1-indexed, where the indices start from 1. PyTorch3D has already made the conversion between the two ways of vertex indexing for us.

The return variable, aux, contains some extra mesh information. Note that the texture_image field of the aux variable is empty. The texture images are used in MTL files to define colors on vertices and faces. Again, we will show how to use this feature in our next example.

In the second example, we will use an example cube_texture.obj file to highlight more OBJ file features. The file is shown as follows.

The cube_texture.obj file is like the cube.obj file, except for the following differences:

  • There are some additional lines starting with vt. Each such line declares a texture vertex with x and y coordinates. Each texture vertex defines a color. The color is the pixel color at a so-called texture image, where the pixel location is the x coordinate of the texture vertex x width, and the y coordinate of the texture vertex x height. The texture image would be defined in the cube_texture.mtl companion.
  • There are additional lines starting with vn. Each such line declares a normal vector – for example, the vn 0.000000 -1.000000 0.000000 line declares a normal vector pointing to the negative z axis.
  • Each face definition line now contains more information about each vertex. For example, the f 2/1/1 3/2/1 4/3/1 line contains the definitions for the three vertices. The first triple, 2/1/1, defines the first vertex, the second triple, 3/2/1, defines the second vertex, and the third triple, 4/3/1, defines the third vertex. Each such triplet is the vertex index, texture vertex index, and normal vector index. For example, 2/1/1 defines a vertex, where the vertex geometric location is defined in the second line starting with v, the color is defined in the first line starting with vt, and the normal vector is defined in the first line starting with vn:
mtllib cube_texture.mtl
v 1.000000 -1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v -1.000000 -1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -0.999999
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
vt 1.000000 0.333333
vt 1.000000 0.666667
vt 0.666667 0.666667
vt 0.666667 0.333333
vt 0.666667 0.000000
vt 0.000000 0.333333
vt 0.000000 0.000000
vt 0.333333 0.000000
vt 0.333333 1.000000
vt 0.000000 1.000000
vt 0.000000 0.666667
vt 0.333333 0.333333
vt 0.333333 0.666667
vt 1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 1.000000 0.000000 0.000000
vn -0.000000 0.000000 1.000000
vn -1.000000 -0.000000 -0.000000
vn 0.000000 0.000000 -1.000000
g main
usemtl Skin
s 1
f 2/1/1 3/2/1 4/3/1
f 8/1/2 7/4/2 6/5/2
f 5/6/3 6/7/3 2/8/3
f 6/8/4 7/5/4 3/4/4
f 3/9/5 7/10/5 8/11/5
f 1/12/6 4/13/6 8/11/6
f 1/4/1 2/1/1 4/3/1
f 5/14/2 8/1/2 6/5/2
f 1/12/3 5/6/3 2/8/3
f 2/12/4 6/8/4 3/4/4
f 4/13/5 3/9/5 8/11/5
f 5/6/6 1/12/6 8/11/6

The cube_texture.mtl companion is as follows, where the line starting with map_Kd declares the texture image. Here, wal67ar_small.jpg is a 250 x 250 RGB image file in the same folder as the MTL file:

newmtl Skin
Ka 0.200000 0.200000 0.200000
Kd 0.827451 0.792157 0.772549
Ks 0.000000 0.000000 0.000000
Ns 0.000000
map_Kd ./wal67ar_small.jpg

Again, we can use Open3D and PyTorch3D to load the mesh in the cube_texture.obj file – for example, by using the following obj_example2.py file:

import open3d
from pytorch3d.io import load_obj
import torch
mesh_file = "cube_texture.obj"
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, aux = load_obj(mesh_file)
print('Type of vertices = ', type(vertices))
print("Type of faces = ", type(faces))
print("Type of aux = ", type(aux))
print('vertices = ', vertices)
print('faces = ', faces)
print('aux = ', aux)
texture_images = getattr(aux, 'texture_images')
print('texture_images type = ', type(texture_images))
print(texture_images['Skin'].shape)

The output of the obj_example2.py code snippet should be as follows:

visualizing the mesh using open3D
Loading the same file with PyTorch3D
Type of vertices =  <class 'torch.Tensor'>
Type of faces =  <class 'pytorch3d.io.obj_io.Faces'>
Type of aux =  <class 'pytorch3d.io.obj_io.Properties'>
vertices =  tensor([[ 1.0000, -1.0000, -1.0000],
        [ 1.0000, -1.0000,  1.0000],
        [-1.0000, -1.0000,  1.0000],
        [-1.0000, -1.0000, -1.0000],
        [ 1.0000,  1.0000, -1.0000],
        [ 1.0000,  1.0000,  1.0000],
        [-1.0000,  1.0000,  1.0000],
        [-1.0000,  1.0000, -1.0000]])
faces =  Faces(verts_idx=tensor([[1, 2, 3],
        [7, 6, 5],
        [4, 5, 1],
        [5, 6, 2],
        [2, 6, 7],
        [0, 3, 7],
        [0, 1, 3],
        ...
        [3, 3, 3],
        [4, 4, 4],
        [5, 5, 5]]), textures_idx=tensor([[ 0,  1,  2],
        [ 0,  3,  4],
        [ 5,  6,  7],
        [ 7,  4,  3],
        [ 8,  9, 10],
        [11, 12, 10],
        ...
        [12,  8, 10],
        [ 5, 11, 10]]), materials_idx=tensor([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]))
aux =  Properties(normals=tensor([[ 0., -1.,  0.],
        [ 0.,  1.,  0.],
        [ 1.,  0.,  0.],
        [-0.,  0.,  1.],
        [-1., -0., -0.],
        [ 0.,  0., -1.]]), verts_uvs=tensor([[1.0000, 0.3333],
        ...
        [0.3333, 0.6667],
        [1.0000, 0.0000]]), material_colors={'Skin': {'ambient_color': tensor([0.2000, 0.2000, 0.2000]), 'diffuse_color': tensor([0.8275, 0.7922, 0.7725]), 'specular_color': tensor([0., 0., 0.]), 'shininess': tensor([0.])}}, texture_images={'Skin': tensor([[[0.2078, 0.1765, 0.1020],
         [0.2039, 0.1725, 0.0980],
         [0.1961, 0.1647, 0.0902],
         ...,
          [0.2235, 0.1882, 0.1294]]])}, texture_atlas=None)
texture_images type =  <class 'dict'>
Skin
torch.Size([250, 250, 3])

Note

This is not the complete output; please check this while you run the code.

Compared with the output of the obj_example1.py code snippet, the preceding output has the following differences.

  • The normals_idx and textures_idx fields of the faces variable all contain valid indices now instead of taking a -1 value.
  • The normals field of the aux variable is a PyTorch tensor now, instead of being None.
  • The verts_uvs field of the aux variable is a PyTorch tensor now, instead of being None.
  • The texture_images field of the aux variable is not an empty dictionary any longer. The texture_images dictionary contains one entry with a key, Skin, and a PyTorch tensor with a shape of (250, 250, 3). This tensor is exactly the same as the image contained in the wal67ar_small.jpg file, as defined in the mtl_texture.mtl file.

We have learned how to use basic 3D data file formats and PLY and OBJ files. In the next section, we will learn the basic concepts of 3D coordination systems.

CONTINUE READING
83
Tech Concepts
36
Programming languages
73
Tech Tools
Icon Unlimited access to the largest independent learning library in tech of over 8,000 expert-authored tech books and videos.
Icon Innovative learning tools, including AI book assistants, code context explainers, and text-to-speech.
Icon 50+ new titles added per month and exclusive early access to books as they are being written.
3D Deep Learning with Python
notes
bookmark Notes and Bookmarks search Search in title playlist Add to playlist download Download options font-size Font size

Change the font size

margin-width Margin width

Change margin width

day-mode Day/Sepia/Night Modes

Change background colour

Close icon Search
Country selected

Close icon Your notes and bookmarks

Confirmation

Modal Close icon
claim successful

Buy this book with your credits?

Modal Close icon
Are you sure you want to buy this book with one of your credits?
Close
YES, BUY

Submit Your Feedback

Modal Close icon
Modal Close icon
Modal Close icon