Spaces:
Paused
Paused
Upload app.py with huggingface_hub
Browse files
app.py
CHANGED
|
@@ -266,6 +266,87 @@ def reconstruct_objects(image: np.ndarray):
|
|
| 266 |
print(tb)
|
| 267 |
return None, None, f"Error:\n{tb[-1500:]}"
|
| 268 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 269 |
# --- UI ---
|
| 270 |
with gr.Blocks(title="SAM 3D Objects") as demo:
|
| 271 |
gr.Markdown("# SAM 3D Objects\nImage → 3D (GLB). SAM2 detection + SAM3D reconstruction.")
|
|
@@ -282,6 +363,17 @@ with gr.Blocks(title="SAM 3D Objects") as demo:
|
|
| 282 |
dl = gr.File(label="Download GLB")
|
| 283 |
btn.click(reconstruct_objects, inputs=[inp], outputs=[m3d, prev, stat])
|
| 284 |
m3d.change(lambda x: x, inputs=[m3d], outputs=[dl])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 285 |
with gr.Tab("Diagnose"):
|
| 286 |
dbtn = gr.Button("Diagnose GPU & Modules")
|
| 287 |
dout = gr.Textbox(lines=15)
|
|
|
|
| 266 |
print(tb)
|
| 267 |
return None, None, f"Error:\n{tb[-1500:]}"
|
| 268 |
|
| 269 |
+
|
| 270 |
+
@spaces.GPU(duration=240)
|
| 271 |
+
def test_sam3d_only(image: np.ndarray):
|
| 272 |
+
"""Test SAM3D reconstruction with center-crop mask (no SAM2)."""
|
| 273 |
+
if image is None:
|
| 274 |
+
return None, None, "No image"
|
| 275 |
+
try:
|
| 276 |
+
import torch, time, gc
|
| 277 |
+
t0 = time.time()
|
| 278 |
+
print(f"GPU: {torch.cuda.get_device_name()}, VRAM: {torch.cuda.memory_allocated()/1e9:.1f}GB")
|
| 279 |
+
|
| 280 |
+
image_np = np.array(image) if not isinstance(image, np.ndarray) else image
|
| 281 |
+
h, w = image_np.shape[:2]
|
| 282 |
+
|
| 283 |
+
# Create a center mask (middle 60% of image)
|
| 284 |
+
mask = np.zeros((h, w), dtype=bool)
|
| 285 |
+
y1, y2 = int(h * 0.2), int(h * 0.8)
|
| 286 |
+
x1, x2 = int(w * 0.2), int(w * 0.8)
|
| 287 |
+
mask[y1:y2, x1:x2] = True
|
| 288 |
+
|
| 289 |
+
preview = image_np.copy()
|
| 290 |
+
preview[mask] = (preview[mask] * 0.5 + np.array([0, 255, 0]) * 0.5).astype(np.uint8)
|
| 291 |
+
print(f" Mask created: {mask.sum()} pixels ({time.time()-t0:.0f}s)")
|
| 292 |
+
|
| 293 |
+
from inference import Inference
|
| 294 |
+
print(f" Loading SAM3D... VRAM: {torch.cuda.memory_allocated()/1e9:.1f}GB")
|
| 295 |
+
sam3d = Inference(CONFIG_PATH, compile=False)
|
| 296 |
+
print(f" SAM3D loaded ({time.time()-t0:.0f}s, VRAM: {torch.cuda.memory_allocated()/1e9:.1f}GB)")
|
| 297 |
+
|
| 298 |
+
print(f" Running reconstruction...")
|
| 299 |
+
result = sam3d(image=image_np, mask=mask, seed=42)
|
| 300 |
+
print(f" Done ({time.time()-t0:.0f}s, VRAM: {torch.cuda.memory_allocated()/1e9:.1f}GB)")
|
| 301 |
+
|
| 302 |
+
if result is None:
|
| 303 |
+
return None, preview, "Reconstruction returned None"
|
| 304 |
+
|
| 305 |
+
import tempfile
|
| 306 |
+
od = tempfile.mkdtemp()
|
| 307 |
+
glb = f"{od}/object.glb"
|
| 308 |
+
|
| 309 |
+
gs = None
|
| 310 |
+
if isinstance(result, dict):
|
| 311 |
+
for k in ("gs", "gaussian", "gaussians", "scene"):
|
| 312 |
+
v = result.get(k)
|
| 313 |
+
if v is not None:
|
| 314 |
+
gs = v[0] if isinstance(v, (list, tuple)) else v
|
| 315 |
+
break
|
| 316 |
+
|
| 317 |
+
if gs is not None and hasattr(gs, "save_ply"):
|
| 318 |
+
ply = f"{od}/temp.ply"
|
| 319 |
+
gs.save_ply(ply)
|
| 320 |
+
import open3d as o3d
|
| 321 |
+
pcd = o3d.io.read_point_cloud(ply)
|
| 322 |
+
pcd.estimate_normals()
|
| 323 |
+
mesh, _ = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(pcd, depth=8)
|
| 324 |
+
o3d.io.write_triangle_mesh(glb, mesh)
|
| 325 |
+
elif gs is not None and hasattr(gs, "_xyz"):
|
| 326 |
+
import open3d as o3d
|
| 327 |
+
pcd = o3d.geometry.PointCloud()
|
| 328 |
+
pcd.points = o3d.utility.Vector3dVector(gs._xyz.detach().cpu().numpy())
|
| 329 |
+
pcd.estimate_normals()
|
| 330 |
+
mesh, _ = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(pcd, depth=8)
|
| 331 |
+
o3d.io.write_triangle_mesh(glb, mesh)
|
| 332 |
+
else:
|
| 333 |
+
keys = list(result.keys()) if isinstance(result, dict) else dir(result)
|
| 334 |
+
return None, preview, f"Cannot extract 3D. Keys: {keys}"
|
| 335 |
+
|
| 336 |
+
import trimesh
|
| 337 |
+
n = 0
|
| 338 |
+
try:
|
| 339 |
+
n = len(trimesh.load(glb, force="mesh").faces)
|
| 340 |
+
except: pass
|
| 341 |
+
elapsed = int(time.time() - t0)
|
| 342 |
+
return glb, preview, f"OK: {n:,} faces ({elapsed}s)"
|
| 343 |
+
except Exception as e:
|
| 344 |
+
import traceback
|
| 345 |
+
tb = traceback.format_exc()
|
| 346 |
+
print(tb)
|
| 347 |
+
return None, None, f"Error:\n{tb[-1500:]}"
|
| 348 |
+
|
| 349 |
+
|
| 350 |
# --- UI ---
|
| 351 |
with gr.Blocks(title="SAM 3D Objects") as demo:
|
| 352 |
gr.Markdown("# SAM 3D Objects\nImage → 3D (GLB). SAM2 detection + SAM3D reconstruction.")
|
|
|
|
| 363 |
dl = gr.File(label="Download GLB")
|
| 364 |
btn.click(reconstruct_objects, inputs=[inp], outputs=[m3d, prev, stat])
|
| 365 |
m3d.change(lambda x: x, inputs=[m3d], outputs=[dl])
|
| 366 |
+
with gr.Tab("Test SAM3D Only"):
|
| 367 |
+
with gr.Row():
|
| 368 |
+
with gr.Column():
|
| 369 |
+
tinp = gr.Image(label="Input", type="numpy")
|
| 370 |
+
tbtn = gr.Button("Test SAM3D (no SAM2)", variant="primary")
|
| 371 |
+
with gr.Column():
|
| 372 |
+
tprev = gr.Image(label="Mask Preview", type="numpy", interactive=False)
|
| 373 |
+
tstat = gr.Textbox(label="Status")
|
| 374 |
+
with gr.Row():
|
| 375 |
+
tm3d = gr.Model3D(label="3D Preview")
|
| 376 |
+
tbtn.click(test_sam3d_only, inputs=[tinp], outputs=[tm3d, tprev, tstat])
|
| 377 |
with gr.Tab("Diagnose"):
|
| 378 |
dbtn = gr.Button("Diagnose GPU & Modules")
|
| 379 |
dout = gr.Textbox(lines=15)
|