vuer-cli 0.0.3__py3-none-any.whl → 0.0.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vuer_cli/add.py +69 -84
- vuer_cli/envs_publish.py +335 -309
- vuer_cli/envs_pull.py +177 -170
- vuer_cli/login.py +459 -0
- vuer_cli/main.py +52 -88
- vuer_cli/mcap_extractor.py +866 -0
- vuer_cli/remove.py +87 -95
- vuer_cli/scripts/demcap.py +171 -0
- vuer_cli/scripts/mcap_playback.py +661 -0
- vuer_cli/scripts/minimap.py +365 -0
- vuer_cli/scripts/ptc_utils.py +434 -0
- vuer_cli/scripts/viz_ptc_cams.py +613 -0
- vuer_cli/scripts/viz_ptc_proxie.py +483 -0
- vuer_cli/sync.py +314 -308
- vuer_cli/upgrade.py +121 -136
- vuer_cli/utils.py +11 -38
- {vuer_cli-0.0.3.dist-info → vuer_cli-0.0.5.dist-info}/METADATA +59 -6
- vuer_cli-0.0.5.dist-info/RECORD +22 -0
- vuer_cli-0.0.3.dist-info/RECORD +0 -14
- {vuer_cli-0.0.3.dist-info → vuer_cli-0.0.5.dist-info}/WHEEL +0 -0
- {vuer_cli-0.0.3.dist-info → vuer_cli-0.0.5.dist-info}/entry_points.txt +0 -0
- {vuer_cli-0.0.3.dist-info → vuer_cli-0.0.5.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
"""Visualize GLB model with camera frustums and optional point cloud."""
|
|
2
|
+
|
|
3
|
+
import warnings
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import List, Optional
|
|
7
|
+
|
|
8
|
+
from ..utils import print_error
|
|
9
|
+
|
|
10
|
+
# Suppress numpy warnings for matrix operations
|
|
11
|
+
warnings.filterwarnings("ignore", category=RuntimeWarning)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def create_camera_positions_around_center(radius=1.0, height=0.0):
|
|
15
|
+
"""Create four camera positions around a center point at 90-degree intervals."""
|
|
16
|
+
import numpy as np
|
|
17
|
+
|
|
18
|
+
positions = []
|
|
19
|
+
for angle in [0, np.pi / 2, np.pi, 3 * np.pi / 2]:
|
|
20
|
+
x = radius * np.cos(angle)
|
|
21
|
+
y = radius * np.sin(angle)
|
|
22
|
+
z = height
|
|
23
|
+
positions.append([x, y, z])
|
|
24
|
+
return positions
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def create_camera_rotations_looking_at_center():
|
|
28
|
+
"""Create rotations for cameras to look at the center point."""
|
|
29
|
+
import numpy as np
|
|
30
|
+
|
|
31
|
+
rotations = [
|
|
32
|
+
[0, -np.pi / 2, np.pi / 2],
|
|
33
|
+
[np.pi / 2, 0, 0],
|
|
34
|
+
[-np.pi / 2, np.pi / 2, 0],
|
|
35
|
+
[np.pi / 2, -np.pi, np.pi],
|
|
36
|
+
]
|
|
37
|
+
return rotations
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def load_scene_pointcloud(
|
|
41
|
+
data_dir: str = "demcap_data",
|
|
42
|
+
camera_names: Optional[List[str]] = None,
|
|
43
|
+
max_frames: Optional[int] = None,
|
|
44
|
+
frame_step: int = 5,
|
|
45
|
+
pixel_step: int = 5,
|
|
46
|
+
max_depth: float = 10.0,
|
|
47
|
+
color_by_camera: bool = False,
|
|
48
|
+
):
|
|
49
|
+
"""Load and merge point clouds from multiple cameras into a single scene point cloud."""
|
|
50
|
+
import cv2
|
|
51
|
+
import numpy as np
|
|
52
|
+
|
|
53
|
+
from .ptc_utils import PointCloudGenerator, load_robot_poses, load_static_transforms
|
|
54
|
+
|
|
55
|
+
data_path = Path(data_dir)
|
|
56
|
+
|
|
57
|
+
if not data_path.exists():
|
|
58
|
+
return None, None
|
|
59
|
+
|
|
60
|
+
if camera_names is None:
|
|
61
|
+
camera_names = ["nav_front_d455", "nav_right_d455"]
|
|
62
|
+
|
|
63
|
+
try:
|
|
64
|
+
robot_pose_interpolator = load_robot_poses(data_path)
|
|
65
|
+
pose_time_min = robot_pose_interpolator.times[0]
|
|
66
|
+
pose_time_max = robot_pose_interpolator.times[-1]
|
|
67
|
+
except Exception:
|
|
68
|
+
return None, None
|
|
69
|
+
|
|
70
|
+
camera_color_map = {
|
|
71
|
+
"nav_front_d455": np.array([0.0, 0.0, 1.0], dtype=np.float32),
|
|
72
|
+
"nav_right_d455": np.array([1.0, 0.0, 0.0], dtype=np.float32),
|
|
73
|
+
"nav_left_d455": np.array([0.0, 1.0, 0.0], dtype=np.float32),
|
|
74
|
+
"nav_rear_d455": np.array([1.0, 1.0, 0.0], dtype=np.float32),
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
all_points = []
|
|
78
|
+
all_colors = []
|
|
79
|
+
|
|
80
|
+
reference_camera = camera_names[0]
|
|
81
|
+
first_camera_transform = np.eye(4)
|
|
82
|
+
|
|
83
|
+
for cam_name in camera_names:
|
|
84
|
+
try:
|
|
85
|
+
static_transform = load_static_transforms(data_path, cam_name)
|
|
86
|
+
generator = PointCloudGenerator(data_dir=str(data_path), camera_name=cam_name)
|
|
87
|
+
|
|
88
|
+
pairs = generator._find_rgb_depth_pairs()
|
|
89
|
+
pairs = [p for p in pairs if pose_time_min <= p["timestamp_s"] <= pose_time_max]
|
|
90
|
+
|
|
91
|
+
if max_frames:
|
|
92
|
+
pairs = pairs[:max_frames:frame_step]
|
|
93
|
+
else:
|
|
94
|
+
pairs = pairs[::frame_step]
|
|
95
|
+
|
|
96
|
+
if cam_name == reference_camera and len(pairs) > 0:
|
|
97
|
+
first_pair = pairs[0]
|
|
98
|
+
t_world_to_base = robot_pose_interpolator.interpolate_pose(
|
|
99
|
+
first_pair["timestamp_s"]
|
|
100
|
+
)
|
|
101
|
+
if t_world_to_base is not None:
|
|
102
|
+
t_base_to_camera = static_transform.get_transform()
|
|
103
|
+
first_camera_transform = t_world_to_base @ t_base_to_camera
|
|
104
|
+
|
|
105
|
+
for frame_idx, pair in enumerate(pairs):
|
|
106
|
+
rgb = cv2.imread(str(pair["rgb_file"]))
|
|
107
|
+
rgb = cv2.cvtColor(rgb, cv2.COLOR_BGR2RGB)
|
|
108
|
+
depth = cv2.imread(str(pair["depth_file"]), cv2.IMREAD_UNCHANGED)
|
|
109
|
+
|
|
110
|
+
t_world_to_base = robot_pose_interpolator.interpolate_pose(pair["timestamp_s"])
|
|
111
|
+
if t_world_to_base is None:
|
|
112
|
+
continue
|
|
113
|
+
|
|
114
|
+
t_base_to_camera = static_transform.get_transform()
|
|
115
|
+
t_world_to_camera = t_world_to_base @ t_base_to_camera
|
|
116
|
+
|
|
117
|
+
points_cam, colors = generator.backproject_rgbd(
|
|
118
|
+
rgb, depth, max_depth, pixel_step
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
if len(points_cam) == 0:
|
|
122
|
+
continue
|
|
123
|
+
|
|
124
|
+
if color_by_camera:
|
|
125
|
+
camera_color = camera_color_map.get(
|
|
126
|
+
cam_name, np.array([0.5, 0.5, 0.5], dtype=np.float32)
|
|
127
|
+
)
|
|
128
|
+
colors = np.tile(camera_color, (len(points_cam), 1))
|
|
129
|
+
|
|
130
|
+
points_cam_h = np.hstack([points_cam, np.ones((len(points_cam), 1))])
|
|
131
|
+
points_world_h = (t_world_to_camera @ points_cam_h.T).T
|
|
132
|
+
points_ref_h = (np.linalg.inv(first_camera_transform) @ points_world_h.T).T
|
|
133
|
+
|
|
134
|
+
flip_xy = np.array([[-1, 0, 0, 0], [0, -1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]])
|
|
135
|
+
points_ref_threejs_h = (flip_xy @ points_ref_h.T).T
|
|
136
|
+
points_ref = points_ref_threejs_h[:, :3]
|
|
137
|
+
|
|
138
|
+
all_points.append(points_ref.astype(np.float32))
|
|
139
|
+
all_colors.append(colors.astype(np.float32))
|
|
140
|
+
|
|
141
|
+
except Exception:
|
|
142
|
+
continue
|
|
143
|
+
|
|
144
|
+
if len(all_points) == 0:
|
|
145
|
+
return None, None
|
|
146
|
+
|
|
147
|
+
combined_points = np.vstack(all_points)
|
|
148
|
+
combined_colors = np.vstack(all_colors)
|
|
149
|
+
|
|
150
|
+
total_points_before = len(combined_points)
|
|
151
|
+
|
|
152
|
+
y_values = combined_points[:, 1]
|
|
153
|
+
y_threshold = np.percentile(y_values, 65)
|
|
154
|
+
mask = y_values < y_threshold
|
|
155
|
+
combined_points = combined_points[mask]
|
|
156
|
+
combined_colors = combined_colors[mask]
|
|
157
|
+
|
|
158
|
+
return combined_points, combined_colors
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def create_proxie_group(
|
|
162
|
+
group_id: int,
|
|
163
|
+
initial_position=None,
|
|
164
|
+
initial_rotation=None,
|
|
165
|
+
opacity: float = 1.0,
|
|
166
|
+
glb_url: str = None,
|
|
167
|
+
):
|
|
168
|
+
"""Create a single group containing a GLB model with four camera frustums."""
|
|
169
|
+
from vuer.schemas import Frustum, Glb, Group
|
|
170
|
+
|
|
171
|
+
if initial_position is None:
|
|
172
|
+
initial_position = [0, 0, 0]
|
|
173
|
+
if initial_rotation is None:
|
|
174
|
+
initial_rotation = [0, 0, 0]
|
|
175
|
+
|
|
176
|
+
camera_positions = create_camera_positions_around_center(radius=0.1, height=1.625)
|
|
177
|
+
camera_rotations = create_camera_rotations_looking_at_center()
|
|
178
|
+
|
|
179
|
+
frustums = []
|
|
180
|
+
for i, (pos, rot) in enumerate(zip(camera_positions, camera_rotations, strict=False)):
|
|
181
|
+
if i == 3:
|
|
182
|
+
pos[0] += 0.185
|
|
183
|
+
pos[1] += 0.02
|
|
184
|
+
elif i == 0:
|
|
185
|
+
pos[0] += 0.20
|
|
186
|
+
pos[1] += 0.008
|
|
187
|
+
elif i == 1:
|
|
188
|
+
pos[0] += 0.17
|
|
189
|
+
pos[1] += -0.025
|
|
190
|
+
elif i == 2:
|
|
191
|
+
pos[0] += 0.18
|
|
192
|
+
pos[1] += 0.005
|
|
193
|
+
frustums.append(
|
|
194
|
+
Frustum(
|
|
195
|
+
key=f"frustum-{group_id}-{i}",
|
|
196
|
+
position=pos,
|
|
197
|
+
rotation=rot,
|
|
198
|
+
scale=0.1,
|
|
199
|
+
fov=60,
|
|
200
|
+
aspect=16 / 9,
|
|
201
|
+
near=0.1,
|
|
202
|
+
far=0.2,
|
|
203
|
+
showFrustum=True,
|
|
204
|
+
showImagePlane=True,
|
|
205
|
+
showFocalPlane=False,
|
|
206
|
+
colorFrustum="cyan",
|
|
207
|
+
)
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
initial_position[0] += 0
|
|
211
|
+
initial_position[1] += 2
|
|
212
|
+
initial_position[2] += 0
|
|
213
|
+
initial_rotation[0] += -1.57
|
|
214
|
+
initial_rotation[1] += 0
|
|
215
|
+
initial_rotation[2] += 0
|
|
216
|
+
|
|
217
|
+
return Group(
|
|
218
|
+
Glb(
|
|
219
|
+
src=glb_url,
|
|
220
|
+
position=[0, 0, 0],
|
|
221
|
+
rotation=[1.57, 0, 0],
|
|
222
|
+
scale=0.01,
|
|
223
|
+
opacity=opacity,
|
|
224
|
+
key=f"model-{group_id}",
|
|
225
|
+
),
|
|
226
|
+
*frustums,
|
|
227
|
+
position=initial_position,
|
|
228
|
+
rotation=initial_rotation,
|
|
229
|
+
scale=1.0,
|
|
230
|
+
key=f"group-{group_id}",
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
async def main_viz(
|
|
235
|
+
sess,
|
|
236
|
+
show_pointcloud: bool = True,
|
|
237
|
+
data_dir: str = "demcap_data",
|
|
238
|
+
camera_names: Optional[List[str]] = None,
|
|
239
|
+
max_frames: Optional[int] = None,
|
|
240
|
+
frame_step: int = 5,
|
|
241
|
+
pixel_step: int = 5,
|
|
242
|
+
max_depth: float = 10.0,
|
|
243
|
+
point_size: float = 0.01,
|
|
244
|
+
color_by_camera: bool = False,
|
|
245
|
+
num_groups: int = 3,
|
|
246
|
+
group_spacing: float = 2.0,
|
|
247
|
+
base_position: Optional[List[float]] = None,
|
|
248
|
+
glb_url: str = None,
|
|
249
|
+
):
|
|
250
|
+
"""Main visualization function that creates multiple groups with GLB models and cameras."""
|
|
251
|
+
from vuer.schemas import DefaultScene, PointCloud
|
|
252
|
+
|
|
253
|
+
print("Loading scene...")
|
|
254
|
+
|
|
255
|
+
point_cloud_vertices = None
|
|
256
|
+
point_cloud_colors = None
|
|
257
|
+
if show_pointcloud:
|
|
258
|
+
print("Loading point cloud...")
|
|
259
|
+
point_cloud_vertices, point_cloud_colors = load_scene_pointcloud(
|
|
260
|
+
data_dir=data_dir,
|
|
261
|
+
camera_names=camera_names,
|
|
262
|
+
max_frames=max_frames,
|
|
263
|
+
frame_step=frame_step,
|
|
264
|
+
pixel_step=pixel_step,
|
|
265
|
+
max_depth=max_depth,
|
|
266
|
+
color_by_camera=color_by_camera,
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
if num_groups > 1:
|
|
270
|
+
opacity_values = [1.0 - (0.3 * i / (num_groups - 1)) for i in range(num_groups)]
|
|
271
|
+
else:
|
|
272
|
+
opacity_values = [1.0]
|
|
273
|
+
|
|
274
|
+
group_configs = [
|
|
275
|
+
{
|
|
276
|
+
"id": i,
|
|
277
|
+
"position": [
|
|
278
|
+
base_position[0],
|
|
279
|
+
base_position[1],
|
|
280
|
+
base_position[2] - i * group_spacing,
|
|
281
|
+
],
|
|
282
|
+
"rotation": [0, 0, 0],
|
|
283
|
+
"opacity": opacity_values[i],
|
|
284
|
+
}
|
|
285
|
+
for i in range(num_groups)
|
|
286
|
+
]
|
|
287
|
+
|
|
288
|
+
groups = [
|
|
289
|
+
create_proxie_group(
|
|
290
|
+
config["id"],
|
|
291
|
+
config["position"],
|
|
292
|
+
config.get("rotation"),
|
|
293
|
+
config.get("opacity", 1.0),
|
|
294
|
+
glb_url=glb_url,
|
|
295
|
+
)
|
|
296
|
+
for config in group_configs
|
|
297
|
+
]
|
|
298
|
+
|
|
299
|
+
scene_elements = []
|
|
300
|
+
scene_elements.extend(groups)
|
|
301
|
+
|
|
302
|
+
if point_cloud_vertices is not None and point_cloud_colors is not None:
|
|
303
|
+
print(f"Point cloud: {len(point_cloud_vertices):,} points")
|
|
304
|
+
point_cloud = PointCloud(
|
|
305
|
+
key="scene_pointcloud",
|
|
306
|
+
vertices=point_cloud_vertices,
|
|
307
|
+
colors=point_cloud_colors,
|
|
308
|
+
size=point_size,
|
|
309
|
+
position=[0, 2, 0],
|
|
310
|
+
rotation=[0, 0, 0],
|
|
311
|
+
)
|
|
312
|
+
scene_elements.append(point_cloud)
|
|
313
|
+
|
|
314
|
+
print("Setting up scene...")
|
|
315
|
+
sess.set @ DefaultScene(
|
|
316
|
+
*scene_elements,
|
|
317
|
+
up=[0, 1, 0],
|
|
318
|
+
# show_helper=False,
|
|
319
|
+
# bgChildren=[OrbitControls(key="OrbitControls")],
|
|
320
|
+
)
|
|
321
|
+
|
|
322
|
+
print("Ready! Open browser to view.")
|
|
323
|
+
await sess.forever()
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
@dataclass
|
|
327
|
+
class VizPtcProxie:
|
|
328
|
+
"""Visualize GLB robot model with camera frustums and optional point cloud.
|
|
329
|
+
|
|
330
|
+
DESCRIPTION
|
|
331
|
+
Creates an interactive 3D visualization combining a GLB robot model with
|
|
332
|
+
camera frustums and an optional RGB-D point cloud background. Useful for
|
|
333
|
+
visualizing robot poses within a reconstructed environment.
|
|
334
|
+
|
|
335
|
+
Features:
|
|
336
|
+
- Multiple robot model instances with configurable spacing
|
|
337
|
+
- Four camera frustums per robot showing sensor coverage
|
|
338
|
+
- Optional point cloud background from RGB-D data
|
|
339
|
+
- Opacity gradient for depth perception of robot poses
|
|
340
|
+
|
|
341
|
+
The visualization server runs at http://localhost:8012 by default.
|
|
342
|
+
Open this URL in a browser to view the 3D scene.
|
|
343
|
+
|
|
344
|
+
GLB MODEL
|
|
345
|
+
Place your robot GLB model at: vuer-cli/assets/proxie.glb
|
|
346
|
+
Or specify a custom URL with --glb-url
|
|
347
|
+
|
|
348
|
+
INPUT FORMAT
|
|
349
|
+
Requires extracted MCAP data (use 'vuer demcap' first):
|
|
350
|
+
<data_dir>/
|
|
351
|
+
├── images/<camera>_color_image_*/ # RGB images
|
|
352
|
+
├── depth/<camera>_*/ # Depth images
|
|
353
|
+
├── transforms/transforms.csv # Robot poses
|
|
354
|
+
└── camera_intrinsics.json # Camera calibration
|
|
355
|
+
|
|
356
|
+
EXAMPLES
|
|
357
|
+
# Basic visualization with point cloud
|
|
358
|
+
vuer viz_ptc_proxie --data-dir /path/to/extracted_data
|
|
359
|
+
|
|
360
|
+
# Without point cloud (faster startup)
|
|
361
|
+
vuer viz_ptc_proxie --data-dir /path/to/data --show-pointcloud False
|
|
362
|
+
|
|
363
|
+
# Custom number of robot instances
|
|
364
|
+
vuer viz_ptc_proxie --data-dir /path/to/data --num-groups 5 --group-spacing 1.0
|
|
365
|
+
|
|
366
|
+
# Custom GLB model URL
|
|
367
|
+
vuer viz_ptc_proxie --data-dir /path/to/data --glb-url http://localhost:8012/static/my_robot.glb
|
|
368
|
+
|
|
369
|
+
# Specify cameras for point cloud
|
|
370
|
+
vuer viz_ptc_proxie --data-dir /path/to/data --cameras nav_front_d455,nav_right_d455
|
|
371
|
+
|
|
372
|
+
# Faster point cloud with sparser sampling
|
|
373
|
+
vuer viz_ptc_proxie --data-dir /path/to/data --frame-step 10 --pixel-step 10
|
|
374
|
+
|
|
375
|
+
DEPENDENCIES
|
|
376
|
+
Requires: pip install 'vuer-cli[viz]'
|
|
377
|
+
"""
|
|
378
|
+
|
|
379
|
+
# Required: path to extracted MCAP data directory
|
|
380
|
+
data_dir: str
|
|
381
|
+
|
|
382
|
+
# Point cloud options
|
|
383
|
+
show_pointcloud: bool = True # Enable point cloud visualization
|
|
384
|
+
cameras: str = (
|
|
385
|
+
None # Comma-separated camera names (default: nav_front_d455,nav_right_d455)
|
|
386
|
+
)
|
|
387
|
+
max_frames: int = None # Max frames per camera (default: all)
|
|
388
|
+
frame_step: int = 5 # Process every Nth frame
|
|
389
|
+
pixel_step: int = 10 # Sample every Nth pixel
|
|
390
|
+
max_depth: float = 10.0 # Maximum depth in meters
|
|
391
|
+
point_size: float = 0.01 # Size of points
|
|
392
|
+
|
|
393
|
+
# Model options
|
|
394
|
+
assets_folder: str = (
|
|
395
|
+
None # Static assets folder for GLB model (default: vuer-cli/assets)
|
|
396
|
+
)
|
|
397
|
+
glb_url: str = "proxie.glb" # GLB model URL
|
|
398
|
+
num_groups: int = 10 # Number of proxie groups to create
|
|
399
|
+
group_spacing: float = 0.5 # Spacing between groups along Z-axis
|
|
400
|
+
base_position: str = "-2.0,-2.2,0" # Starting position [x,y,z] for first group
|
|
401
|
+
|
|
402
|
+
# Server options
|
|
403
|
+
host: str = "0.0.0.0" # Server host
|
|
404
|
+
port: int = 8012 # Server port
|
|
405
|
+
|
|
406
|
+
def __call__(self) -> int:
|
|
407
|
+
"""Execute viz_ptc_proxie command."""
|
|
408
|
+
try:
|
|
409
|
+
import cv2
|
|
410
|
+
import numpy as np
|
|
411
|
+
import pandas as pd
|
|
412
|
+
from vuer import Vuer
|
|
413
|
+
except ImportError as e:
|
|
414
|
+
print_error(
|
|
415
|
+
f"Missing dependencies for viz_ptc_proxie command: {e}\n\n"
|
|
416
|
+
"Install with:\n"
|
|
417
|
+
" pip install 'vuer-cli[viz]'\n"
|
|
418
|
+
" # or: uv add 'vuer-cli[viz]'"
|
|
419
|
+
)
|
|
420
|
+
return 1
|
|
421
|
+
|
|
422
|
+
try:
|
|
423
|
+
data_path = Path(self.data_dir)
|
|
424
|
+
if not data_path.exists():
|
|
425
|
+
raise FileNotFoundError(f"Data directory {self.data_dir} does not exist")
|
|
426
|
+
|
|
427
|
+
# Parse camera names
|
|
428
|
+
camera_list = None
|
|
429
|
+
if self.cameras:
|
|
430
|
+
camera_list = [c.strip() for c in self.cameras.split(",")]
|
|
431
|
+
|
|
432
|
+
# Parse base_position
|
|
433
|
+
base_pos_list = [float(x.strip()) for x in self.base_position.split(",")]
|
|
434
|
+
|
|
435
|
+
# Create Vuer app - use default assets folder if not specified
|
|
436
|
+
assets_folder = self.assets_folder
|
|
437
|
+
if not assets_folder:
|
|
438
|
+
# Default to vuer-cli/assets folder
|
|
439
|
+
import vuer_cli
|
|
440
|
+
|
|
441
|
+
assets_folder = Path(vuer_cli.__file__).parent.parent.parent / "assets"
|
|
442
|
+
if not assets_folder.exists():
|
|
443
|
+
assets_folder = None
|
|
444
|
+
|
|
445
|
+
if assets_folder:
|
|
446
|
+
print(f"Using assets folder: {assets_folder}")
|
|
447
|
+
app = Vuer(host=self.host, port=self.port, workspace=assets_folder)
|
|
448
|
+
else:
|
|
449
|
+
app = Vuer(host=self.host, port=self.port)
|
|
450
|
+
|
|
451
|
+
print("Starting visualization server...")
|
|
452
|
+
|
|
453
|
+
@app.spawn(start=True)
|
|
454
|
+
async def main_with_args(sess):
|
|
455
|
+
print("Session started, loading data...")
|
|
456
|
+
await main_viz(
|
|
457
|
+
sess,
|
|
458
|
+
show_pointcloud=self.show_pointcloud,
|
|
459
|
+
data_dir=self.data_dir,
|
|
460
|
+
camera_names=camera_list,
|
|
461
|
+
max_frames=self.max_frames,
|
|
462
|
+
frame_step=self.frame_step,
|
|
463
|
+
pixel_step=self.pixel_step,
|
|
464
|
+
max_depth=self.max_depth,
|
|
465
|
+
point_size=self.point_size,
|
|
466
|
+
color_by_camera=False,
|
|
467
|
+
num_groups=self.num_groups,
|
|
468
|
+
group_spacing=self.group_spacing,
|
|
469
|
+
base_position=base_pos_list,
|
|
470
|
+
glb_url=self.glb_url,
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
return 0
|
|
474
|
+
|
|
475
|
+
except FileNotFoundError as e:
|
|
476
|
+
print_error(str(e))
|
|
477
|
+
return 1
|
|
478
|
+
except Exception as e:
|
|
479
|
+
print_error(f"Unexpected error: {e}")
|
|
480
|
+
import traceback
|
|
481
|
+
|
|
482
|
+
traceback.print_exc()
|
|
483
|
+
return 1
|