Stable-X commited on
Commit
fe87d83
1 Parent(s): 803e3ed

feat: Add featureless visualization utils

Browse files
Files changed (2) hide show
  1. app.py +1 -1
  2. vis_utils.py +171 -0
app.py CHANGED
@@ -16,7 +16,7 @@ from transformers import AutoModelForImageSegmentation
16
  from torchvision import transforms
17
  from PIL import Image
18
  import open3d as o3d
19
- from spann3r.tools.vis import render_frames
20
  from backend_utils import improved_multiway_registration, pts2normal, point2mesh, combine_and_clean_point_clouds
21
  from gs_utils import point2gs
22
  from pose_utils import solve_cemara
 
16
  from torchvision import transforms
17
  from PIL import Image
18
  import open3d as o3d
19
+ from vis_utils import render_frames
20
  from backend_utils import improved_multiway_registration, pts2normal, point2mesh, combine_and_clean_point_clouds
21
  from gs_utils import point2gs
22
  from pose_utils import solve_cemara
vis_utils.py ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import cv2
3
+ import imageio
4
+ import numpy as np
5
+ import open3d as o3d
6
+ import os.path as osp
7
+ import matplotlib.pyplot as plt
8
+ import matplotlib.colors as mcolors
9
+
10
+ def render_frames(o3d_geometry, camera_all, output_dir, save_video=True, save_camera=True):
11
+ # Create off-screen renderer
12
+ render = o3d.visualization.rendering.OffscreenRenderer(
13
+ width=camera_all[0].intrinsic.width,
14
+ height=camera_all[0].intrinsic.height
15
+ )
16
+
17
+ render_frame_path = os.path.join(output_dir, 'render_frames')
18
+ render_camera_path = os.path.join(output_dir, 'render_cameras')
19
+ os.makedirs(render_frame_path, exist_ok=True)
20
+ os.makedirs(render_camera_path, exist_ok=True)
21
+
22
+ video_path = os.path.join(output_dir, 'render_frame.mp4')
23
+ if save_video:
24
+ writer = imageio.get_writer(video_path, fps=10)
25
+
26
+ material = o3d.visualization.rendering.MaterialRecord()
27
+ material.shader = 'defaultUnlit' # Use unlit shader for point clouds
28
+ material.point_size = 1.0 # Match original point size
29
+ material.base_color = [1.0, 1.0, 1.0, 1.0]
30
+
31
+ for i, camera_params in enumerate(camera_all):
32
+ if camera_params is None:
33
+ continue
34
+
35
+ # Set camera view
36
+ render.setup_camera(
37
+ camera_params.intrinsic.intrinsic_matrix,
38
+ camera_params.extrinsic,
39
+ camera_params.intrinsic.width,
40
+ camera_params.intrinsic.height
41
+ )
42
+
43
+ if save_camera:
44
+ o3d.io.write_pinhole_camera_parameters(
45
+ os.path.join(render_camera_path, f'camera_{i:03d}.json'),
46
+ camera_params
47
+ )
48
+
49
+ # Render
50
+ render.scene.add_geometry("points", o3d_geometry, material)
51
+ img = render.render_to_image()
52
+ render.scene.remove_geometry("points")
53
+
54
+ # Save frame
55
+ image_uint8 = (np.asarray(img) * 255).astype(np.uint8)
56
+ frame_filename = f'frame_{i:03d}.png'
57
+ imageio.imwrite(osp.join(render_frame_path, frame_filename), image_uint8)
58
+
59
+ if save_video:
60
+ writer.append_data(image_uint8)
61
+
62
+ if save_video:
63
+ writer.close()
64
+
65
+ return video_path
66
+
67
+ def find_render_cam(pcd, width=1920, height=1080):
68
+ # For headless servers, we'll need to pre-define camera parameters
69
+ # This creates a default viewing angle looking at the center of the point cloud
70
+
71
+ # Calculate point cloud center and scale
72
+ center = pcd.get_center()
73
+ scale = np.max(pcd.get_max_bound() - pcd.get_min_bound())
74
+
75
+ # Create default camera parameters
76
+ camera_params = o3d.camera.PinholeCameraParameters()
77
+
78
+ # Set intrinsic parameters
79
+ intrinsic = o3d.camera.PinholeCameraIntrinsic()
80
+ intrinsic.set_intrinsics(
81
+ width=width,
82
+ height=height,
83
+ fx=width,
84
+ fy=width,
85
+ cx=width/2,
86
+ cy=height/2
87
+ )
88
+ camera_params.intrinsic = intrinsic
89
+
90
+ # Set extrinsic parameters (looking at center from a 45-degree angle)
91
+ camera_params.extrinsic = np.array([
92
+ [1, 0, 0, 0],
93
+ [0, np.cos(np.pi/4), -np.sin(np.pi/4), 0],
94
+ [0, np.sin(np.pi/4), np.cos(np.pi/4), 2*scale],
95
+ [0, 0, 0, 1]
96
+ ])
97
+
98
+ return camera_params
99
+
100
+ def vis_pred_and_imgs(pts_all, save_path, images_all=None, conf_all=None, save_video=True):
101
+ # Set matplotlib backend to non-interactive
102
+ plt.switch_backend('Agg')
103
+
104
+ # Normalization
105
+ min_val = pts_all.min(axis=(0, 1, 2), keepdims=True)
106
+ max_val = pts_all.max(axis=(0, 1, 2), keepdims=True)
107
+ pts_all = (pts_all - min_val) / (max_val - min_val)
108
+
109
+ pts_save_path = osp.join(save_path, 'pts')
110
+ os.makedirs(pts_save_path, exist_ok=True)
111
+
112
+ if images_all is not None:
113
+ images_save_path = osp.join(save_path, 'imgs')
114
+ os.makedirs(images_save_path, exist_ok=True)
115
+
116
+ if conf_all is not None:
117
+ conf_save_path = osp.join(save_path, 'confs')
118
+ os.makedirs(conf_save_path, exist_ok=True)
119
+
120
+ if save_video:
121
+ pts_video_path = osp.join(save_path, 'pts.mp4')
122
+ pts_writer = imageio.get_writer(pts_video_path, fps=10)
123
+
124
+ if images_all is not None:
125
+ imgs_video_path = osp.join(save_path, 'imgs.mp4')
126
+ imgs_writer = imageio.get_writer(imgs_video_path, fps=10)
127
+
128
+ if conf_all is not None:
129
+ conf_video_path = osp.join(save_path, 'confs.mp4')
130
+ conf_writer = imageio.get_writer(conf_video_path, fps=10)
131
+
132
+ for frame_id in range(pts_all.shape[0]):
133
+ # Points visualization
134
+ pt_vis = pts_all[frame_id].astype(np.float32)
135
+ pt_vis_rgb = mcolors.hsv_to_rgb(1-pt_vis)
136
+ pt_vis_rgb_uint8 = (pt_vis_rgb * 255).astype(np.uint8)
137
+
138
+ # Use matplotlib in non-interactive mode
139
+ fig, ax = plt.subplots()
140
+ ax.imshow(pt_vis_rgb_uint8)
141
+ plt.savefig(osp.join(pts_save_path, f'pts_{frame_id:04d}.png'))
142
+ plt.close(fig)
143
+
144
+ if save_video:
145
+ pts_writer.append_data(pt_vis_rgb_uint8)
146
+
147
+ if images_all is not None:
148
+ image = images_all[frame_id]
149
+ image_uint8 = (image * 255).astype(np.uint8)
150
+ imageio.imwrite(osp.join(images_save_path, f'img_{frame_id:04d}.png'), image_uint8)
151
+
152
+ if save_video:
153
+ imgs_writer.append_data(image_uint8)
154
+
155
+ if conf_all is not None:
156
+ fig, ax = plt.subplots()
157
+ conf_image = plt.cm.jet(conf_all[frame_id])
158
+ ax.imshow(conf_image)
159
+ plt.savefig(osp.join(conf_save_path, f'conf_{frame_id:04d}.png'))
160
+ plt.close(fig)
161
+
162
+ conf_image_uint8 = (conf_image * 255).astype(np.uint8)
163
+ if save_video:
164
+ conf_writer.append_data(conf_image_uint8)
165
+
166
+ if save_video:
167
+ pts_writer.close()
168
+ if images_all is not None:
169
+ imgs_writer.close()
170
+ if conf_all is not None:
171
+ conf_writer.close()