prithivMLmods commited on
Commit
3d20cca
·
verified ·
1 Parent(s): 6a04fa8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +61 -65
app.py CHANGED
@@ -8,59 +8,63 @@ import torch
8
  import cv2
9
  import tempfile
10
  import shutil
 
11
  from PIL import Image
12
  from typing import Iterable
13
  from gradio.themes import Soft
14
  from gradio.themes.utils import colors, fonts, sizes
15
  from transformers import Sam3Processor, Sam3Model
16
 
 
 
 
 
 
 
17
  # ---------------------------------------------------------
18
  # 1. SETUP & DYNAMIC IMPORTS
19
  # ---------------------------------------------------------
20
 
21
- # Define repo details
22
  REPO_URL = "https://github.com/facebookresearch/sam-3d-body.git"
23
  REPO_DIR = "sam-3d-body"
24
 
25
  def setup_environment():
26
- """
27
- Clones the repo if missing and sets up paths.
28
- """
29
  print("--- Checking Environment for SAM 3D Body ---")
30
 
31
- # 1. Clone Repository if not present
32
  if not os.path.exists(REPO_DIR):
33
  print(f"Cloning {REPO_URL}...")
34
  try:
35
  subprocess.run(["git", "clone", REPO_URL], check=True)
36
  print("Repository cloned.")
37
-
38
- # Optional: Install the package in editable mode to ensure internal imports work
39
- print("Installing sam-3d-body package...")
40
  subprocess.run([sys.executable, "-m", "pip", "install", "-e", f"./{REPO_DIR}"], check=True)
41
  except Exception as e:
42
- print(f"Error during setup: {e}")
43
 
44
  # 2. Add paths to sys.path
45
- # Add the root of the repo
46
  repo_abs = os.path.abspath(REPO_DIR)
47
- if repo_abs not in sys.path:
48
- sys.path.append(repo_abs)
49
-
50
- # Add the notebook folder (where utils.py lives)
51
  notebook_abs = os.path.abspath(os.path.join(REPO_DIR, "notebook"))
 
 
 
52
  if notebook_abs not in sys.path:
53
- sys.path.append(notebook_abs)
54
-
55
- print(f"Paths added: {repo_abs}, {notebook_abs}")
56
 
57
- # Run setup
58
  setup_environment()
59
 
60
- # 3. Attempt Imports
 
 
 
 
 
61
  try:
62
- # utils.py is in sam-3d-body/notebook/utils.py
63
- # We added 'sam-3d-body/notebook' to path, so we can import directly from utils
64
  from utils import (
65
  setup_sam_3d_body,
66
  setup_visualizer,
@@ -68,11 +72,18 @@ try:
68
  visualize_3d_mesh,
69
  save_mesh_results
70
  )
 
 
 
 
 
71
  SAM3D_AVAILABLE = True
72
- print("SAM 3D Body utilities imported successfully.")
73
- except ImportError as e:
74
- print(f"CRITICAL WARNING: SAM 3D Body utils not found: {e}")
75
- print("Ensure dependencies (mmhuman3d, detectron2, etc.) are installed in requirements.txt")
 
 
76
  SAM3D_AVAILABLE = False
77
 
78
  # ---------------------------------------------------------
@@ -144,12 +155,10 @@ device = "cuda" if torch.cuda.is_available() else "cpu"
144
  print(f"Using device: {device}")
145
 
146
  # ---------------------------------------------------------
147
- # 3. MODEL LOADING
148
  # ---------------------------------------------------------
149
-
150
- # --- Load SAM3 (Segmentation) ---
151
  try:
152
- print("Loading SAM3 Model and Processor...")
153
  sam3_model = Sam3Model.from_pretrained("facebook/sam3").to(device)
154
  sam3_processor = Sam3Processor.from_pretrained("facebook/sam3")
155
  print("SAM3 Model loaded successfully.")
@@ -158,22 +167,6 @@ except Exception as e:
158
  sam3_model = None
159
  sam3_processor = None
160
 
161
- # --- Load SAM 3D Body ---
162
- sam3d_estimator = None
163
- sam3d_visualizer = None
164
-
165
- if SAM3D_AVAILABLE:
166
- try:
167
- print("Loading SAM 3D Body Estimator...")
168
- # Note: The utils function usually expects the HF repo ID
169
- sam3d_estimator = setup_sam_3d_body(hf_repo_id="facebook/sam-3d-body-dinov3")
170
- sam3d_visualizer = setup_visualizer()
171
- print("SAM 3D Body Model loaded successfully.")
172
- except Exception as e:
173
- print(f"Error loading SAM 3D Body model: {e}")
174
- # Mark as unavailable if loading fails despite imports working
175
- SAM3D_AVAILABLE = False
176
-
177
  # ---------------------------------------------------------
178
  # 4. INFERENCE FUNCTIONS
179
  # ---------------------------------------------------------
@@ -217,59 +210,53 @@ def process_3d_body(input_image):
217
  if input_image is None:
218
  raise gr.Error("Please upload an image.")
219
 
 
220
  if not SAM3D_AVAILABLE or sam3d_estimator is None:
221
- raise gr.Error("SAM 3D Body model not available. Check server logs for import errors.")
 
 
222
 
223
  # Convert PIL to CV2 BGR
224
  img_np = np.array(input_image.convert("RGB"))
225
  img_cv2 = cv2.cvtColor(img_np, cv2.COLOR_RGB2BGR)
226
 
227
- # Helper requires a physical file path for inference
228
  with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp_file:
229
  tmp_path = tmp_file.name
230
  cv2.imwrite(tmp_path, img_cv2)
231
 
232
  try:
233
- # Run Inference
234
- print(f"Processing 3D Body on {tmp_path}...")
235
  outputs = sam3d_estimator.process_one_image(tmp_path)
236
 
237
  if not outputs:
238
  return None, None, None, "No people detected."
239
 
240
- # 1. Generate 2D Visualization
241
  vis_results_2d = visualize_2d_results(img_cv2, outputs, sam3d_visualizer)
242
- # Handle list of results
243
  res_2d_rgb = cv2.cvtColor(vis_results_2d[0], cv2.COLOR_BGR2RGB) if vis_results_2d else img_np
244
 
245
- # 2. Generate 3D Visualization (Overlay Image)
246
  mesh_results_img = visualize_3d_mesh(img_cv2, outputs, sam3d_estimator.faces)
247
  res_3d_overlay_rgb = cv2.cvtColor(mesh_results_img[0], cv2.COLOR_BGR2RGB) if mesh_results_img else img_np
248
 
249
- # 3. Save PLY Mesh to temp directory for Gradio Model3D
250
  output_dir = tempfile.mkdtemp()
251
  image_name = "gradio_mesh_result"
252
-
253
- # utils.save_mesh_results returns a list of paths to .ply files
254
  ply_files = save_mesh_results(img_cv2, outputs, sam3d_estimator.faces, output_dir, image_name)
255
 
256
- ply_path = None
257
- if ply_files and len(ply_files) > 0:
258
- ply_path = ply_files[0] # Return the first person's mesh
259
 
260
  status = f"Success! Detected {len(outputs)} person(s)."
261
 
262
  return res_2d_rgb, res_3d_overlay_rgb, ply_path, status
263
 
264
  except Exception as e:
265
- raise gr.Error(f"Inference failed: {str(e)}")
 
266
  finally:
267
- # Cleanup input temp file
268
  if os.path.exists(tmp_path):
269
- try:
270
- os.remove(tmp_path)
271
- except:
272
- pass
273
 
274
  # ---------------------------------------------------------
275
  # 5. GRADIO UI LAYOUT
@@ -317,6 +304,15 @@ with gr.Blocks(css=css, theme=steel_blue_theme) as demo:
317
  t2_input_image = gr.Image(label="Input Image", type="pil", height=350)
318
  t2_run_btn = gr.Button("Generate 3D Body", variant="primary")
319
  t2_status = gr.Textbox(label="Status", interactive=False)
 
 
 
 
 
 
 
 
 
320
 
321
  with gr.Column(scale=2):
322
  with gr.Row():
@@ -335,7 +331,7 @@ with gr.Blocks(css=css, theme=steel_blue_theme) as demo:
335
  outputs=[t2_output_2d, t2_output_overlay, t2_output_3d, t2_status]
336
  )
337
 
338
- # Check if example files exist before creating component to avoid errors
339
  ex_files = []
340
  if os.path.exists("examples/player.jpg"): ex_files.append(["examples/player.jpg"])
341
  if os.path.exists("examples/dancing.jpg"): ex_files.append(["examples/dancing.jpg"])
 
8
  import cv2
9
  import tempfile
10
  import shutil
11
+ import traceback
12
  from PIL import Image
13
  from typing import Iterable
14
  from gradio.themes import Soft
15
  from gradio.themes.utils import colors, fonts, sizes
16
  from transformers import Sam3Processor, Sam3Model
17
 
18
+ # ---------------------------------------------------------
19
+ # 0. HEADLESS RENDERING SETUP
20
+ # ---------------------------------------------------------
21
+ # Essential for running 3D visualizers (pyrender) in cloud environments
22
+ os.environ["PYOPENGL_PLATFORM"] = "egl"
23
+
24
  # ---------------------------------------------------------
25
  # 1. SETUP & DYNAMIC IMPORTS
26
  # ---------------------------------------------------------
27
 
 
28
  REPO_URL = "https://github.com/facebookresearch/sam-3d-body.git"
29
  REPO_DIR = "sam-3d-body"
30
 
31
  def setup_environment():
32
+ """Clones repo and sets up Python paths."""
 
 
33
  print("--- Checking Environment for SAM 3D Body ---")
34
 
35
+ # 1. Clone Repository
36
  if not os.path.exists(REPO_DIR):
37
  print(f"Cloning {REPO_URL}...")
38
  try:
39
  subprocess.run(["git", "clone", REPO_URL], check=True)
40
  print("Repository cloned.")
41
+ # Install in editable mode to ensure package discovery works
 
 
42
  subprocess.run([sys.executable, "-m", "pip", "install", "-e", f"./{REPO_DIR}"], check=True)
43
  except Exception as e:
44
+ print(f"Git clone/Install failed: {e}")
45
 
46
  # 2. Add paths to sys.path
 
47
  repo_abs = os.path.abspath(REPO_DIR)
 
 
 
 
48
  notebook_abs = os.path.abspath(os.path.join(REPO_DIR, "notebook"))
49
+
50
+ if repo_abs not in sys.path:
51
+ sys.path.insert(0, repo_abs)
52
  if notebook_abs not in sys.path:
53
+ sys.path.insert(0, notebook_abs)
54
+
55
+ print(f"Python Paths: {sys.path[:2]}...")
56
 
 
57
  setup_environment()
58
 
59
+ # Global variables for models and error tracking
60
+ sam3d_estimator = None
61
+ sam3d_visualizer = None
62
+ sam3d_load_error = None
63
+ SAM3D_AVAILABLE = False
64
+
65
  try:
66
+ # Try importing from the utils file in the cloned repo
67
+ # This expects 'notebook/utils.py' to exist
68
  from utils import (
69
  setup_sam_3d_body,
70
  setup_visualizer,
 
72
  visualize_3d_mesh,
73
  save_mesh_results
74
  )
75
+
76
+ print("Loading SAM 3D Body Estimator (this may take time)...")
77
+ # Initialize the model immediately to catch errors early
78
+ sam3d_estimator = setup_sam_3d_body(hf_repo_id="facebook/sam-3d-body-dinov3")
79
+ sam3d_visualizer = setup_visualizer()
80
  SAM3D_AVAILABLE = True
81
+ print("SAM 3D Body Model loaded successfully.")
82
+
83
+ except Exception as e:
84
+ # Capture the exact error (e.g., missing mmhuman3d)
85
+ sam3d_load_error = f"{type(e).__name__}: {str(e)}\n{traceback.format_exc()}"
86
+ print(f"CRITICAL ERROR loading SAM 3D Body:\n{sam3d_load_error}")
87
  SAM3D_AVAILABLE = False
88
 
89
  # ---------------------------------------------------------
 
155
  print(f"Using device: {device}")
156
 
157
  # ---------------------------------------------------------
158
+ # 3. MODEL LOADING (SAM3)
159
  # ---------------------------------------------------------
 
 
160
  try:
161
+ print("Loading SAM3 Model...")
162
  sam3_model = Sam3Model.from_pretrained("facebook/sam3").to(device)
163
  sam3_processor = Sam3Processor.from_pretrained("facebook/sam3")
164
  print("SAM3 Model loaded successfully.")
 
167
  sam3_model = None
168
  sam3_processor = None
169
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  # ---------------------------------------------------------
171
  # 4. INFERENCE FUNCTIONS
172
  # ---------------------------------------------------------
 
210
  if input_image is None:
211
  raise gr.Error("Please upload an image.")
212
 
213
+ # Check if initialization failed
214
  if not SAM3D_AVAILABLE or sam3d_estimator is None:
215
+ # Raise the specific error captured during startup
216
+ error_msg = sam3d_load_error if sam3d_load_error else "Unknown initialization error."
217
+ raise gr.Error(f"Model Setup Failed. Logs:\n{error_msg}")
218
 
219
  # Convert PIL to CV2 BGR
220
  img_np = np.array(input_image.convert("RGB"))
221
  img_cv2 = cv2.cvtColor(img_np, cv2.COLOR_RGB2BGR)
222
 
223
+ # Helper requires a physical file path
224
  with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp_file:
225
  tmp_path = tmp_file.name
226
  cv2.imwrite(tmp_path, img_cv2)
227
 
228
  try:
229
+ print(f"Running inference on {tmp_path}...")
 
230
  outputs = sam3d_estimator.process_one_image(tmp_path)
231
 
232
  if not outputs:
233
  return None, None, None, "No people detected."
234
 
235
+ # 1. 2D Vis
236
  vis_results_2d = visualize_2d_results(img_cv2, outputs, sam3d_visualizer)
 
237
  res_2d_rgb = cv2.cvtColor(vis_results_2d[0], cv2.COLOR_BGR2RGB) if vis_results_2d else img_np
238
 
239
+ # 2. 3D Overlay
240
  mesh_results_img = visualize_3d_mesh(img_cv2, outputs, sam3d_estimator.faces)
241
  res_3d_overlay_rgb = cv2.cvtColor(mesh_results_img[0], cv2.COLOR_BGR2RGB) if mesh_results_img else img_np
242
 
243
+ # 3. Save PLY
244
  output_dir = tempfile.mkdtemp()
245
  image_name = "gradio_mesh_result"
 
 
246
  ply_files = save_mesh_results(img_cv2, outputs, sam3d_estimator.faces, output_dir, image_name)
247
 
248
+ ply_path = ply_files[0] if ply_files else None
 
 
249
 
250
  status = f"Success! Detected {len(outputs)} person(s)."
251
 
252
  return res_2d_rgb, res_3d_overlay_rgb, ply_path, status
253
 
254
  except Exception as e:
255
+ traceback.print_exc()
256
+ raise gr.Error(f"Inference Runtime Error: {str(e)}")
257
  finally:
 
258
  if os.path.exists(tmp_path):
259
+ os.remove(tmp_path)
 
 
 
260
 
261
  # ---------------------------------------------------------
262
  # 5. GRADIO UI LAYOUT
 
304
  t2_input_image = gr.Image(label="Input Image", type="pil", height=350)
305
  t2_run_btn = gr.Button("Generate 3D Body", variant="primary")
306
  t2_status = gr.Textbox(label="Status", interactive=False)
307
+
308
+ # Warning box if initialization failed
309
+ if not SAM3D_AVAILABLE:
310
+ gr.Markdown(
311
+ "⚠️ **Warning: SAM 3D Body failed to load.**\n"
312
+ f"Error: {sam3d_load_error}\n"
313
+ "Please check `mmhuman3d` and `mmcv` dependencies.",
314
+ elem_classes=["error-box"]
315
+ )
316
 
317
  with gr.Column(scale=2):
318
  with gr.Row():
 
331
  outputs=[t2_output_2d, t2_output_overlay, t2_output_3d, t2_status]
332
  )
333
 
334
+ # Dynamic examples
335
  ex_files = []
336
  if os.path.exists("examples/player.jpg"): ex_files.append(["examples/player.jpg"])
337
  if os.path.exists("examples/dancing.jpg"): ex_files.append(["examples/dancing.jpg"])