Skip to content

process_shapenet

Script to preprocess shapenet like dataset.

This script allows to interactively go through a ShapeNet dataset and decide whether to keep or remove a mesh. All textures are removed, only the obj file and a converted SDF volume are stored in the output folder.

Object3D

Representation of a 3D object.

Source code in sdfest/vae/scripts/process_shapenet.py
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
class Object3D:
    """Representation of a 3D object."""

    def __init__(self, mesh_path: str):
        """Initialize the 3D object.

        Args:
            mesh_path: the full file path of the mesh
        """
        self.mesh_path = mesh_path
        self.simplified_mesh = None
        self.sdf_volume = None
        self.reconstructed_mesh = None

    def convert_to_sdf(self, cells_per_dim, padding):
        self.sdf_volume = sdf_utils.mesh_to_sdf(
            self.simplified_mesh, cells_per_dim, padding
        )
        return self

    def load_mesh(self):
        loaded_obj = trimesh.load(self.mesh_path, process=False)
        if isinstance(loaded_obj, Trimesh):
            self.simplified_mesh = Trimesh(
                loaded_obj.vertices,
                loaded_obj.faces,
                vertex_normals=loaded_obj.vertex_normals,
                visual=trimesh.visual.TextureVisuals(material=SimpleMaterial()),
            )
        elif isinstance(loaded_obj, Scene):
            mesh = trimesh.util.concatenate(
                tuple(
                    trimesh.Trimesh(
                        vertices=g.vertices,
                        faces=g.faces,
                        vertex_normals=g.vertex_normals,
                    )
                    for g in loaded_obj.geometry.values()
                )
            )
            self.simplified_mesh = Trimesh(
                mesh.vertices,
                mesh.faces,
                vertex_normals=mesh.vertex_normals,
                visual=trimesh.visual.TextureVisuals(material=SimpleMaterial()),
            )
        else:
            print(f"Not supported: {type(loaded_obj)}")
            return False
        return True

    def reconstruct_from_sdf(self):
        level = 1.0 / self.sdf_volume.shape[-1]
        self.reconstructed_mesh = sdf_utils.mesh_from_sdf(self.sdf_volume, level)
        return self

__init__(mesh_path)

Initialize the 3D object.

Parameters:

Name Type Description Default
mesh_path str

the full file path of the mesh

required
Source code in sdfest/vae/scripts/process_shapenet.py
28
29
30
31
32
33
34
35
36
37
def __init__(self, mesh_path: str):
    """Initialize the 3D object.

    Args:
        mesh_path: the full file path of the mesh
    """
    self.mesh_path = mesh_path
    self.simplified_mesh = None
    self.sdf_volume = None
    self.reconstructed_mesh = None

trimesh_decision_viewer(mesh, return_dict)

View a trimesh with pyrender adding support to press left and right.

Source code in sdfest/vae/scripts/process_shapenet.py
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
def trimesh_decision_viewer(mesh, return_dict):
    """View a trimesh with pyrender adding support to press left and right."""

    def on_press(key):
        nonlocal inp
        try:
            inp = key.char  # single-char keys
        except AttributeError:
            inp = key.name

    pyrender_mesh = pyrender.Mesh.from_trimesh(mesh)
    scene = pyrender.Scene(ambient_light=[0.3, 0.3, 0.3, 1.0])
    scene.add(pyrender_mesh)
    v = pyrender.Viewer(scene, run_in_thread=True, use_raymond_lighting=True)
    inp = None
    from pynput import keyboard

    decision = None

    listener = keyboard.Listener(on_press=on_press)
    listener.start()  # start to listen on a separate thread
    while True:
        time.sleep(0.1)
        if inp == "left":
            decision = "remove"
            break
        elif inp == "right":
            decision = "keep"
            break
        elif inp == "down":
            decision = "stop"
            break
    # TODO: listener.stop() hangs randomly (especially under load)
    v.close_external()
    return_dict["decision"] = decision
    return decision