X-GAO commited on
Commit
3cfe155
·
unverified ·
1 Parent(s): 6df7750

add dynamic point cloud visulization

Browse files
Files changed (1) hide show
  1. visualization_pcd.py +166 -0
visualization_pcd.py ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Record3D visualizer
2
+ """
3
+ import os
4
+ import time
5
+ from pathlib import Path
6
+ from decord import VideoReader, cpu
7
+
8
+ import numpy as np
9
+ import tyro
10
+ import viser
11
+ import viser.extras
12
+ import viser.transforms as tf
13
+ from tqdm.auto import tqdm
14
+
15
+
16
+ def main(
17
+ data_path: str = "/apdcephfs_cq10/share_1290939/vg_share/reynli/cache/video_demo/video_depth",
18
+ vid_name: str = "01_dog",
19
+ downsample_factor: int = 8,
20
+ max_frames: int = 100,
21
+ share: bool = False,
22
+ point_size = 0.01
23
+ ) -> None:
24
+
25
+ server = viser.ViserServer()
26
+ if share:
27
+ server.request_share_url()
28
+
29
+ print("Loading frames!")
30
+ dis_path = data_path + '/' + vid_name + '.npz'
31
+ vid_path = data_path + '/' + vid_name + '_rgb.mp4'
32
+ # vid_path = data_path + '/' + vid_name + '.mp4'
33
+
34
+ disp_map = np.load(dis_path)['depth'][:, :, :]
35
+ T = disp_map.shape[0]
36
+ H = disp_map.shape[1]
37
+ W = disp_map.shape[2]
38
+
39
+ disp_max = disp_map.max()
40
+ disp_min = disp_map.min()
41
+ disp_map = (disp_map - disp_min) / (disp_max - disp_min)
42
+
43
+ vr = VideoReader(vid_path, ctx=cpu(0))
44
+ vid = vr[:].asnumpy()[:, 0:H, 0:W]
45
+ fps = vr.get_avg_fps()
46
+ num_frames = min(max_frames, T)
47
+
48
+ # Add playback UI.
49
+ with server.gui.add_folder("Playback"):
50
+ gui_timestep = server.gui.add_slider(
51
+ "Timestep",
52
+ min=0,
53
+ max=num_frames - 1,
54
+ step=1,
55
+ initial_value=0,
56
+ disabled=True,
57
+ )
58
+ gui_next_frame = server.gui.add_button("Next Frame", disabled=True)
59
+ gui_prev_frame = server.gui.add_button("Prev Frame", disabled=True)
60
+ gui_playing = server.gui.add_checkbox("Playing", True)
61
+ gui_framerate = server.gui.add_slider(
62
+ "FPS", min=1, max=60, step=0.1, initial_value=fps
63
+ )
64
+ gui_framerate_options = server.gui.add_button_group(
65
+ "FPS options", ("10", "20", "30", "60")
66
+ )
67
+
68
+ # Frame step buttons.
69
+ @gui_next_frame.on_click
70
+ def _(_) -> None:
71
+ gui_timestep.value = (gui_timestep.value + 1) % num_frames
72
+
73
+ @gui_prev_frame.on_click
74
+ def _(_) -> None:
75
+ gui_timestep.value = (gui_timestep.value - 1) % num_frames
76
+
77
+ # Disable frame controls when we're playing.
78
+ @gui_playing.on_update
79
+ def _(_) -> None:
80
+ gui_timestep.disabled = gui_playing.value
81
+ gui_next_frame.disabled = gui_playing.value
82
+ gui_prev_frame.disabled = gui_playing.value
83
+
84
+ # Set the framerate when we click one of the options.
85
+ @gui_framerate_options.on_click
86
+ def _(_) -> None:
87
+ gui_framerate.value = int(gui_framerate_options.value)
88
+
89
+ prev_timestep = gui_timestep.value
90
+
91
+ # Toggle frame visibility when the timestep slider changes.
92
+ @gui_timestep.on_update
93
+ def _(_) -> None:
94
+ nonlocal prev_timestep
95
+ current_timestep = gui_timestep.value
96
+ with server.atomic():
97
+ frame_nodes[current_timestep].visible = True
98
+ frame_nodes[prev_timestep].visible = False
99
+ prev_timestep = current_timestep
100
+ server.flush() # Optional!
101
+
102
+ # Load in frames.
103
+ server.scene.add_frame(
104
+ "/frames",
105
+ wxyz=tf.SO3.exp(np.array([0.0, 0.0, 0.0])).wxyz,
106
+ position=(0, 0, 0),
107
+ show_axes=False,
108
+ )
109
+ frame_nodes: list[viser.FrameHandle] = []
110
+ for i in tqdm(range(num_frames)):
111
+
112
+ # Add base frame.
113
+ frame_nodes.append(server.scene.add_frame(f"/frames/t{i}", show_axes=False))
114
+
115
+ position_image = np.where(np.zeros([H, W]) == 0)
116
+ v = np.array(position_image[0])
117
+ u = np.array(position_image[1])
118
+ d = disp_map[i, v, u]
119
+
120
+ zc = 1.0 / (d + 0.1)
121
+ # zc = 1.0 / (d + 1e-8)
122
+
123
+ xc = zc * (u - (W / 2.0)) / (W/2.)
124
+ yc = zc * (v - (H / 2.0)) / (H/2.)
125
+
126
+ zc -= 4 # disp_max * 0.2
127
+
128
+ points = np.stack((xc, yc, zc), axis=1)
129
+ colors = vid[i, v, u]
130
+
131
+ points = points[::downsample_factor]
132
+ colors = colors[::downsample_factor]
133
+
134
+ # Place the point cloud in the frame.
135
+ server.scene.add_point_cloud(
136
+ name=f"/frames/t{i}/point_cloud",
137
+ points=points,
138
+ colors=colors,
139
+ point_size=point_size,#0.007,
140
+ point_shape="rounded",
141
+ )
142
+
143
+ # Hide all but the current frame.
144
+ for i, frame_node in enumerate(frame_nodes):
145
+ frame_node.visible = i == gui_timestep.value
146
+
147
+ # Playback update loop.
148
+ prev_timestep = gui_timestep.value
149
+ while True:
150
+ if gui_playing.value:
151
+ gui_timestep.value = (gui_timestep.value + 1) % num_frames
152
+
153
+ time.sleep(1.0 / gui_framerate.value)
154
+
155
+
156
+ if __name__ == "__main__":
157
+ tyro.cli(main(
158
+ # dir path of saved rgb.mp4 and disp.npz, modify it to your own dir
159
+ data_path="outputs/results_open_world/",
160
+ # sample name, modify it to your own sample name
161
+ vid_name="wukong",
162
+ # downsample factor of dense pcd
163
+ downsample_factor=8,
164
+ # point cloud size
165
+ point_size=0.007
166
+ ))