Integrate scene#

The final step of the system is to integrate all RGBD images into a single TSDF volume and extract a mesh as the result.

Input arguments#

The script runs with python run_system.py [config] --integrate. In [config], ["path_dataset"] should have subfolders image and depth in which frames are synchronized and aligned. In [config], the optional argument ["path_intrinsic"] specifies path to a json file that has a camera intrinsic matrix (See Read camera intrinsic for details). If it is not given, the PrimeSense factory setting is used instead.

Integrate RGBD frames#

21def scalable_integrate_rgb_frames(path_dataset, intrinsic, config):
22    poses = []
23    [color_files, depth_files] = get_rgbd_file_lists(path_dataset)
24    n_files = len(color_files)
25    n_fragments = int(math.ceil(float(n_files) / \
26            config['n_frames_per_fragment']))
27    volume = o3d.pipelines.integration.ScalableTSDFVolume(
28        voxel_length=config["tsdf_cubic_size"] / 512.0,
29        sdf_trunc=0.04,
30        color_type=o3d.pipelines.integration.TSDFVolumeColorType.RGB8)
31
32    pose_graph_fragment = o3d.io.read_pose_graph(
33        join(path_dataset, config["template_refined_posegraph_optimized"]))
34
35    for fragment_id in range(len(pose_graph_fragment.nodes)):
36        pose_graph_rgbd = o3d.io.read_pose_graph(
37            join(path_dataset,
38                 config["template_fragment_posegraph_optimized"] % fragment_id))
39
40        for frame_id in range(len(pose_graph_rgbd.nodes)):
41            frame_id_abs = fragment_id * \
42                    config['n_frames_per_fragment'] + frame_id
43            print(
44                "Fragment %03d / %03d :: integrate rgbd frame %d (%d of %d)." %
45                (fragment_id, n_fragments - 1, frame_id_abs, frame_id + 1,
46                 len(pose_graph_rgbd.nodes)))
47            rgbd = read_rgbd_image(color_files[frame_id_abs],
48                                   depth_files[frame_id_abs], False, config)
49            pose = np.dot(pose_graph_fragment.nodes[fragment_id].pose,
50                          pose_graph_rgbd.nodes[frame_id].pose)
51            volume.integrate(rgbd, intrinsic, np.linalg.inv(pose))
52            poses.append(pose)
53
54    mesh = volume.extract_triangle_mesh()
55    mesh.compute_vertex_normals()
56    if config["debug_mode"]:
57        o3d.visualization.draw_geometries([mesh])

This function first reads the alignment results from both Make fragments and Register fragments, then computes the pose of each RGBD image in the global space. After that, RGBD images are integrated using RGBD integration.

Results#

This is a printed log from the volume integration script.

Fragment 000 / 013 :: integrate rgbd frame 0 (1 of 100).
Fragment 000 / 013 :: integrate rgbd frame 1 (2 of 100).
Fragment 000 / 013 :: integrate rgbd frame 2 (3 of 100).
Fragment 000 / 013 :: integrate rgbd frame 3 (4 of 100).
:
Fragment 013 / 013 :: integrate rgbd frame 1360 (61 of 64).
Fragment 013 / 013 :: integrate rgbd frame 1361 (62 of 64).
Fragment 013 / 013 :: integrate rgbd frame 1362 (63 of 64).
Fragment 013 / 013 :: integrate rgbd frame 1363 (64 of 64).
Writing PLY: [========================================] 100%

The following image shows the final scene reconstruction.

../../_images/scene.png