EnginDev commited on
Commit
be43d39
·
verified ·
1 Parent(s): d78a30b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +123 -125
app.py CHANGED
@@ -4,7 +4,7 @@ import numpy as np
4
  from PIL import Image
5
  import cv2
6
 
7
- print("🚀 Starting SAM2 App v2.1 - OPTIMIZED...")
8
 
9
  device = "cuda" if torch.cuda.is_available() else "cpu"
10
  print(f"📱 Using device: {device}")
@@ -61,16 +61,16 @@ def refine_mask(mask, kernel_size=5):
61
  mask_refined = cv2.morphologyEx(mask_closed, cv2.MORPH_OPEN, kernel)
62
  return mask_refined > 0
63
 
64
- def segment_automatic(image, quality="high", merge_parts=True):
65
  """
66
- OPTIMIERTE Automatische Segmentierung
67
- Schnell & präzise - kombiniert mehrere Masken
68
  """
69
  if image is None:
70
  return None, {"error": "Kein Bild hochgeladen"}
71
 
72
  try:
73
- print(f"🔄 Starting segmentation (quality: {quality}, merge: {merge_parts})...")
74
  model, processor = load_model()
75
 
76
  image_pil, image_np = prepare_image(image)
@@ -78,7 +78,6 @@ def segment_automatic(image, quality="high", merge_parts=True):
78
 
79
  center_x, center_y = w // 2, h // 2
80
 
81
- # Single point inference mit multimask_output
82
  inputs = processor(
83
  image_pil,
84
  input_points=[[[center_x, center_y]]],
@@ -102,56 +101,62 @@ def segment_automatic(image, quality="high", merge_parts=True):
102
 
103
  print(f"✅ Got {len(scores)} masks with scores: {scores}")
104
 
105
- # SMART MERGING: Kombiniere alle guten Masken
106
- if merge_parts:
107
- combined_mask = np.zeros((h, w), dtype=bool)
108
- masks_used = 0
109
-
110
- for idx, score in enumerate(scores):
111
- if score > 0.5: # Nur Masken mit gutem Score
112
- if masks.ndim == 4:
113
- mask = masks[0, idx].numpy()
114
- else:
115
- mask = masks[idx].numpy()
116
-
117
- # OR-Kombination (super schnell!)
118
- combined_mask = combined_mask | (mask > 0)
119
- masks_used += 1
120
- print(f" ✅ Added mask {idx} (score: {score:.3f})")
121
-
122
- final_mask = combined_mask
123
- print(f"🔗 Combined {masks_used} masks into one!")
124
  else:
125
- # Nur beste Maske
126
  best_idx = np.argmax(scores)
127
- if masks.ndim == 4:
128
- final_mask = masks[0, best_idx].numpy() > 0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  else:
130
- final_mask = masks[best_idx].numpy() > 0
131
- masks_used = 1
132
- print(f"✅ Using best mask (score: {scores[best_idx]:.3f})")
133
 
134
- # Refinement für glatte Kanten
135
  if quality == "high":
136
- print("🎨 Refining mask...")
137
  final_mask = refine_mask(final_mask, kernel_size=7)
138
 
139
- # Overlay erstellen
140
  overlay = image_np.copy()
141
- color = np.array([255, 80, 180]) # Rosa/Pink
142
 
143
  mask_float = final_mask.astype(float)
144
  if quality == "high":
145
  mask_float = cv2.GaussianBlur(mask_float, (5, 5), 0)
146
 
147
- # Farbiges Overlay
148
  for c in range(3):
149
  overlay[:, :, c] = (
150
  overlay[:, :, c] * (1 - mask_float * 0.65) +
151
  color[c] * mask_float * 0.65
152
  )
153
 
154
- # Gelbe Kontur zeichnen
155
  contours, _ = cv2.findContours(
156
  final_mask.astype(np.uint8),
157
  cv2.RETR_EXTERNAL,
@@ -161,9 +166,10 @@ def segment_automatic(image, quality="high", merge_parts=True):
161
 
162
  metadata = {
163
  "success": True,
164
- "mode": "automatic_plus" if merge_parts else "automatic",
165
  "quality": quality,
166
- "masks_combined": masks_used,
 
167
  "all_scores": scores.tolist(),
168
  "image_size": [w, h],
169
  "mask_area": int(np.sum(final_mask)),
@@ -172,7 +178,7 @@ def segment_automatic(image, quality="high", merge_parts=True):
172
  "device": device
173
  }
174
 
175
- print("✅ Segmentation complete!")
176
  return Image.fromarray(overlay.astype(np.uint8)), metadata
177
 
178
  except Exception as e:
@@ -180,26 +186,28 @@ def segment_automatic(image, quality="high", merge_parts=True):
180
  print(f"❌ ERROR:\n{traceback.format_exc()}")
181
  return image, {"error": str(e)}
182
 
183
- def segment_multi_dense(image, density="medium"):
184
- """Multi-Object Segmentierung mit Grid"""
 
 
 
185
  if image is None:
186
  return None, {"error": "Kein Bild"}
187
 
188
  try:
189
- print(f"🎯 Starting multi-region segmentation (density: {density})...")
190
  model, processor = load_model()
191
  image_pil, image_np = prepare_image(image)
192
  h, w = image_np.shape[:2]
193
 
194
- # Grid-Größe basierend auf Density
195
  if density == "high":
196
- grid_size = 5
197
  elif density == "medium":
198
- grid_size = 4
199
  else:
200
- grid_size = 3
201
 
202
- # Grid-Punkte generieren
203
  points = []
204
  for i in range(1, grid_size + 1):
205
  for j in range(1, grid_size + 1):
@@ -207,13 +215,17 @@ def segment_multi_dense(image, density="medium"):
207
  y = int(h * j / (grid_size + 1))
208
  points.append([x, y])
209
 
210
- print(f"📍 Using {len(points)} grid points ({grid_size}x{grid_size})...")
 
 
 
211
 
212
  all_masks = []
213
  all_scores = []
214
 
215
- # Segmentiere jeden Punkt
216
  for idx, point in enumerate(points):
 
 
217
  inputs = processor(
218
  image_pil,
219
  input_points=[[point]],
@@ -222,7 +234,7 @@ def segment_multi_dense(image, density="medium"):
222
  ).to(device)
223
 
224
  with torch.no_grad():
225
- outputs = model(**inputs, multimask_output=True)
226
 
227
  masks = processor.image_processor.post_process_masks(
228
  outputs.pred_masks.cpu(),
@@ -231,24 +243,24 @@ def segment_multi_dense(image, density="medium"):
231
  )[0]
232
 
233
  scores = outputs.iou_scores.cpu().numpy().flatten()
234
- best_idx = np.argmax(scores)
235
 
236
  if masks.ndim == 4:
237
  mask = masks[0, best_idx].numpy()
238
- else:
239
  mask = masks[best_idx].numpy()
 
 
240
 
241
- # Nur Masken mit gutem Score
242
  if scores[best_idx] > 0.7:
243
- all_masks.append(refine_mask(mask))
244
  all_scores.append(scores[best_idx])
245
 
246
  print(f"✅ Got {len(all_masks)} quality masks")
247
 
248
- # Overlay mit verschiedenen Farben
249
  overlay = image_np.copy()
250
 
251
- # HSV-basierte Farbgenerierung
252
  colors = []
253
  for i in range(len(all_masks)):
254
  hue = int(180 * i / max(len(all_masks), 1))
@@ -256,15 +268,13 @@ def segment_multi_dense(image, density="medium"):
256
  color_rgb = cv2.cvtColor(color_hsv, cv2.COLOR_HSV2RGB)[0][0]
257
  colors.append(color_rgb)
258
 
259
- # Masken anwenden
260
  for mask, color, score in zip(all_masks, colors, all_scores):
261
- alpha = 0.4 + (score - 0.7) * 0.2 # Höherer Score = stärkere Farbe
262
  overlay[mask] = (
263
  overlay[mask] * (1 - alpha) +
264
  np.array(color) * alpha
265
  ).astype(np.uint8)
266
 
267
- # Kontur
268
  contours, _ = cv2.findContours(
269
  mask.astype(np.uint8),
270
  cv2.RETR_EXTERNAL,
@@ -274,10 +284,10 @@ def segment_multi_dense(image, density="medium"):
274
 
275
  metadata = {
276
  "success": True,
277
- "mode": "multi_object_dense",
278
  "density": density,
279
  "grid_size": f"{grid_size}x{grid_size}",
280
- "total_points": len(points),
281
  "quality_masks": len(all_masks),
282
  "avg_score": float(np.mean(all_scores)) if all_scores else 0,
283
  "scores": [float(s) for s in all_scores]
@@ -296,10 +306,10 @@ demo = gr.Blocks(title="SAM2 Boostly", theme=gr.themes.Soft())
296
 
297
  with demo:
298
  gr.Markdown("# 🎨 SAM2 Segmentierung - Boostly Edition")
299
- gr.Markdown("### ⚡ Optimierte Zero-Shot Object Segmentation")
300
 
301
- with gr.Tab("🤖 Automatisch PLUS"):
302
- gr.Markdown("**Smart Multi-Mask Combining** - Kombiniert automatisch alle Objektteile!")
303
 
304
  with gr.Row():
305
  with gr.Column():
@@ -309,23 +319,25 @@ with demo:
309
  choices=["high", "fast"],
310
  value="high",
311
  label="⚙️ Qualität",
312
- info="High = präzisere Kanten, Fast = schneller"
313
  )
314
 
315
- merge_checkbox = gr.Checkbox(
316
  value=True,
317
- label="🔗 Teile zusammenfügen",
318
- info="Kombiniert alle erkannten Bereiche (Fisch + Flosse = 1 Objekt)"
319
  )
320
 
321
  btn_auto = gr.Button("🚀 Segmentieren", variant="primary", size="lg")
322
 
323
  gr.Markdown("""
324
- **✨ Funktionsweise:**
325
- - SAM generiert 3 verschiedene Masken
326
- - Wenn "Teile zusammenfügen" AN: Alle kombiniert → vollständiges Objekt
327
- - Wenn AUS: Nur präziseste Maske
328
- - ⚡ Optimiert: ~10-30 Sekunden statt 25 Minuten!
 
 
329
  """)
330
 
331
  with gr.Column():
@@ -334,18 +346,12 @@ with demo:
334
 
335
  btn_auto.click(
336
  fn=segment_automatic,
337
- inputs=[input_auto, quality_radio, merge_checkbox],
338
  outputs=[output_auto, json_auto]
339
  )
340
-
341
- gr.Examples(
342
- examples=[],
343
- inputs=input_auto,
344
- label="💡 Tipp: Objekt sollte zentral im Bild sein"
345
- )
346
 
347
- with gr.Tab("🎯 Multi-Region"):
348
- gr.Markdown("**Grid-basierte Segmentierung** - Für mehrere separate Objekte")
349
 
350
  with gr.Row():
351
  with gr.Column():
@@ -353,20 +359,22 @@ with demo:
353
 
354
  density_radio = gr.Radio(
355
  choices=["high", "medium", "low"],
356
- value="medium",
357
  label="📊 Punkt-Dichte",
358
- info="Mehr Punkte = mehr Details, aber langsamer"
359
  )
360
 
361
- btn_multi = gr.Button("🎯 Alle Bereiche segmentieren", variant="primary", size="lg")
362
 
363
  gr.Markdown("""
364
- **Grid-Größen:**
365
- - 🔥 High: 5x5 = 25 Erkennungspunkte
366
- - ⚡ Medium: 4x4 = 16 Punkte (empfohlen)
367
- - 💨 Low: 3x3 = 9 Punkte
368
 
369
- Jedes Objekt bekommt eigene Farbe!
 
 
370
  """)
371
 
372
  with gr.Column():
@@ -381,18 +389,15 @@ with demo:
381
 
382
  with gr.Tab("📡 API Dokumentation"):
383
  gr.Markdown("### 🔗 API Endpoint")
384
- gr.Code(
385
- "https://EnginDev-Boostly.hf.space/api/predict",
386
- label="Base URL"
387
- )
388
 
389
- gr.Markdown("### 📝 JavaScript Integration (für Lovable)")
390
  gr.Code('''
391
- // Segmentation Service
392
- const HUGGINGFACE_API = 'https://EnginDev-Boostly.hf.space';
393
 
394
  async function segmentImage(imageFile, mode = 'automatic') {
395
- // File zu Base64 konvertieren
396
  const base64 = await new Promise((resolve) => {
397
  const reader = new FileReader();
398
  reader.onloadend = () => resolve(reader.result);
@@ -400,11 +405,11 @@ async function segmentImage(imageFile, mode = 'automatic') {
400
  });
401
 
402
  // API Call
403
- const response = await fetch(`${HUGGINGFACE_API}/api/predict`, {
404
  method: 'POST',
405
  headers: {'Content-Type': 'application/json'},
406
  body: JSON.stringify({
407
- data: [base64, "high", true], // [image, quality, merge]
408
  fn_index: mode === 'automatic' ? 0 : 1
409
  })
410
  });
@@ -412,53 +417,46 @@ async function segmentImage(imageFile, mode = 'automatic') {
412
  const result = await response.json();
413
 
414
  return {
415
- segmentedImage: result.data[0], // Base64 segmentiertes Bild
416
- metadata: result.data[1] // JSON mit Details
417
  };
418
  }
419
 
420
- // Verwendung:
421
- const result = await segmentImage(myImageFile, 'automatic');
422
- console.log('Mask covers:', result.metadata.mask_percentage + '%');
423
  ''', language="javascript")
424
 
425
  gr.Markdown("### ⚙️ Parameter")
426
  gr.Markdown("""
427
  **fn_index:**
428
- - `0` = Automatisch PLUS (empfohlen für einzelne Objekte)
429
- - `1` = Multi-Region (für mehrere Objekte)
430
 
431
- **quality:**
432
- - `"high"` = Präzise Kanten, Gaussian Blur, Refinement (~20-30s)
433
- - `"fast"` = Schneller, weniger Nachbearbeitung (~10-15s)
434
 
435
- **merge (nur fn_index=0):**
436
- - `true` = Kombiniert alle Masken → vollständiges Objekt
437
- - `false` = Nur beste Maske → nur Hauptteil
438
 
439
- **density (nur fn_index=1):**
440
- - `"high"` = 5x5 Grid = 25 Punkte
441
- - `"medium"` = 4x4 Grid = 16 Punkte
442
- - `"low"` = 3x3 Grid = 9 Punkte
443
  """)
444
 
445
- gr.Markdown("### 📊 Response Format")
446
  gr.Code('''
447
  {
448
  "data": [
449
- "data:image/png;base64,iVBORw0KGgo...", // Segmentiertes Bild
450
  {
451
  "success": true,
452
- "mode": "automatic_plus",
453
- "masks_combined": 3,
454
- "mask_percentage": 12.5,
455
  "num_contours": 1,
456
- "all_scores": [0.998, 0.583, 0.864]
457
  }
458
  ]
459
  }
460
  ''', language="json")
461
 
462
  if __name__ == "__main__":
463
- print("🌐 Launching Boostly SAM2 v2.1...")
464
  demo.launch(server_name="0.0.0.0", server_port=7860, show_error=True)
 
4
  from PIL import Image
5
  import cv2
6
 
7
+ print("🚀 Starting SAM2 App v2.2 - SMART & FAST...")
8
 
9
  device = "cuda" if torch.cuda.is_available() else "cpu"
10
  print(f"📱 Using device: {device}")
 
61
  mask_refined = cv2.morphologyEx(mask_closed, cv2.MORPH_OPEN, kernel)
62
  return mask_refined > 0
63
 
64
+ def segment_automatic(image, quality="high", filter_largest=True):
65
  """
66
+ SMART Segmentierung - Filtert nur Hauptobjekt
67
+ Keine Jacke, kein Hintergrund!
68
  """
69
  if image is None:
70
  return None, {"error": "Kein Bild hochgeladen"}
71
 
72
  try:
73
+ print(f"🔄 Starting SMART segmentation...")
74
  model, processor = load_model()
75
 
76
  image_pil, image_np = prepare_image(image)
 
78
 
79
  center_x, center_y = w // 2, h // 2
80
 
 
81
  inputs = processor(
82
  image_pil,
83
  input_points=[[[center_x, center_y]]],
 
101
 
102
  print(f"✅ Got {len(scores)} masks with scores: {scores}")
103
 
104
+ # SMART: Nimm mittlere Maske (nicht höchste = zu weit)
105
+ if len(scores) >= 3:
106
+ sorted_indices = np.argsort(scores)
107
+ best_idx = sorted_indices[1] # Mittlere
108
+ print(f"📊 Using MIDDLE mask (score: {scores[best_idx]:.3f})")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  else:
 
110
  best_idx = np.argmax(scores)
111
+
112
+ if masks.ndim == 4:
113
+ selected_mask = masks[0, best_idx].numpy() > 0
114
+ else:
115
+ selected_mask = masks[best_idx].numpy() > 0
116
+
117
+ # FILTER: Nur größte zusammenhängende Komponente
118
+ if filter_largest:
119
+ print("🔍 Filtering: Keeping only LARGEST component...")
120
+
121
+ num_labels, labels = cv2.connectedComponents(selected_mask.astype(np.uint8))
122
+
123
+ if num_labels > 1:
124
+ largest_component = 0
125
+ largest_size = 0
126
+
127
+ for i in range(1, num_labels):
128
+ size = np.sum(labels == i)
129
+ if size > largest_size:
130
+ largest_size = size
131
+ largest_component = i
132
+
133
+ final_mask = (labels == largest_component)
134
+ print(f" ✅ Removed {num_labels - 2} small parts (Jacke, etc.)")
135
  else:
136
+ final_mask = selected_mask
137
+ else:
138
+ final_mask = selected_mask
139
 
140
+ # Refinement
141
  if quality == "high":
142
+ print("🎨 Refining edges...")
143
  final_mask = refine_mask(final_mask, kernel_size=7)
144
 
145
+ # Overlay
146
  overlay = image_np.copy()
147
+ color = np.array([255, 80, 180])
148
 
149
  mask_float = final_mask.astype(float)
150
  if quality == "high":
151
  mask_float = cv2.GaussianBlur(mask_float, (5, 5), 0)
152
 
 
153
  for c in range(3):
154
  overlay[:, :, c] = (
155
  overlay[:, :, c] * (1 - mask_float * 0.65) +
156
  color[c] * mask_float * 0.65
157
  )
158
 
159
+ # Kontur
160
  contours, _ = cv2.findContours(
161
  final_mask.astype(np.uint8),
162
  cv2.RETR_EXTERNAL,
 
166
 
167
  metadata = {
168
  "success": True,
169
+ "mode": "automatic_smart",
170
  "quality": quality,
171
+ "filtered": filter_largest,
172
+ "selected_mask_score": float(scores[best_idx]),
173
  "all_scores": scores.tolist(),
174
  "image_size": [w, h],
175
  "mask_area": int(np.sum(final_mask)),
 
178
  "device": device
179
  }
180
 
181
+ print(f"✅ Done! Contours: {len(contours)}")
182
  return Image.fromarray(overlay.astype(np.uint8)), metadata
183
 
184
  except Exception as e:
 
186
  print(f"❌ ERROR:\n{traceback.format_exc()}")
187
  return image, {"error": str(e)}
188
 
189
+ def segment_multi_dense(image, density="low"):
190
+ """
191
+ Multi-Region OPTIMIERT für CPU
192
+ Reduzierte Punktanzahl = schneller!
193
+ """
194
  if image is None:
195
  return None, {"error": "Kein Bild"}
196
 
197
  try:
198
+ print(f"🎯 Starting multi-region (density: {density})...")
199
  model, processor = load_model()
200
  image_pil, image_np = prepare_image(image)
201
  h, w = image_np.shape[:2]
202
 
203
+ # OPTIMIERTE Grid-Größen für CPU
204
  if density == "high":
205
+ grid_size = 4 # 4x4 = 16
206
  elif density == "medium":
207
+ grid_size = 3 # 3x3 = 9
208
  else:
209
+ grid_size = 2 # 2x2 = 4
210
 
 
211
  points = []
212
  for i in range(1, grid_size + 1):
213
  for j in range(1, grid_size + 1):
 
215
  y = int(h * j / (grid_size + 1))
216
  points.append([x, y])
217
 
218
+ total_points = len(points)
219
+ estimated_time = total_points * 10
220
+ print(f"📍 Using {total_points} points ({grid_size}x{grid_size})")
221
+ print(f"⏱️ Estimated time: ~{estimated_time}s")
222
 
223
  all_masks = []
224
  all_scores = []
225
 
 
226
  for idx, point in enumerate(points):
227
+ print(f" Point {idx+1}/{total_points}...")
228
+
229
  inputs = processor(
230
  image_pil,
231
  input_points=[[point]],
 
234
  ).to(device)
235
 
236
  with torch.no_grad():
237
+ outputs = model(**inputs, multimask_output=False)
238
 
239
  masks = processor.image_processor.post_process_masks(
240
  outputs.pred_masks.cpu(),
 
243
  )[0]
244
 
245
  scores = outputs.iou_scores.cpu().numpy().flatten()
246
+ best_idx = 0 if len(scores) == 1 else np.argmax(scores)
247
 
248
  if masks.ndim == 4:
249
  mask = masks[0, best_idx].numpy()
250
+ elif masks.ndim == 3:
251
  mask = masks[best_idx].numpy()
252
+ else:
253
+ mask = masks.numpy()
254
 
 
255
  if scores[best_idx] > 0.7:
256
+ all_masks.append(mask > 0)
257
  all_scores.append(scores[best_idx])
258
 
259
  print(f"✅ Got {len(all_masks)} quality masks")
260
 
 
261
  overlay = image_np.copy()
262
 
263
+ # Farben
264
  colors = []
265
  for i in range(len(all_masks)):
266
  hue = int(180 * i / max(len(all_masks), 1))
 
268
  color_rgb = cv2.cvtColor(color_hsv, cv2.COLOR_HSV2RGB)[0][0]
269
  colors.append(color_rgb)
270
 
 
271
  for mask, color, score in zip(all_masks, colors, all_scores):
272
+ alpha = 0.5
273
  overlay[mask] = (
274
  overlay[mask] * (1 - alpha) +
275
  np.array(color) * alpha
276
  ).astype(np.uint8)
277
 
 
278
  contours, _ = cv2.findContours(
279
  mask.astype(np.uint8),
280
  cv2.RETR_EXTERNAL,
 
284
 
285
  metadata = {
286
  "success": True,
287
+ "mode": "multi_object_fast",
288
  "density": density,
289
  "grid_size": f"{grid_size}x{grid_size}",
290
+ "total_points": total_points,
291
  "quality_masks": len(all_masks),
292
  "avg_score": float(np.mean(all_scores)) if all_scores else 0,
293
  "scores": [float(s) for s in all_scores]
 
306
 
307
  with demo:
308
  gr.Markdown("# 🎨 SAM2 Segmentierung - Boostly Edition")
309
+ gr.Markdown("### ⚡ Smart Filtering & CPU Optimized")
310
 
311
+ with gr.Tab("🤖 Automatisch SMART"):
312
+ gr.Markdown("**Intelligente Filterung** - Nur das Hauptobjekt, keine Jacke/Hintergrund!")
313
 
314
  with gr.Row():
315
  with gr.Column():
 
319
  choices=["high", "fast"],
320
  value="high",
321
  label="⚙️ Qualität",
322
+ info="High = glattere Kanten"
323
  )
324
 
325
+ filter_checkbox = gr.Checkbox(
326
  value=True,
327
+ label="🔍 Nur größtes Objekt",
328
+ info="Filtert Jacke, Hintergrund, kleine Teile"
329
  )
330
 
331
  btn_auto = gr.Button("🚀 Segmentieren", variant="primary", size="lg")
332
 
333
  gr.Markdown("""
334
+ **✨ Smart Features:**
335
+ - Nimmt MITTLERE Maske (vermeidet Over-Segmentation)
336
+ - Connected Components Filtering
337
+ - Entfernt automatisch Jacke/Hintergrund
338
+ - ⚡ Schnell: ~10-20 Sekunden
339
+
340
+ **Perfekt für:** Einzelne Objekte (Fische, Tiere, Menschen)
341
  """)
342
 
343
  with gr.Column():
 
346
 
347
  btn_auto.click(
348
  fn=segment_automatic,
349
+ inputs=[input_auto, quality_radio, filter_checkbox],
350
  outputs=[output_auto, json_auto]
351
  )
 
 
 
 
 
 
352
 
353
+ with gr.Tab("🎯 Multi-Region (Schnell)"):
354
+ gr.Markdown("**CPU-Optimiert** - Reduzierte Punkte für schnellere Verarbeitung")
355
 
356
  with gr.Row():
357
  with gr.Column():
 
359
 
360
  density_radio = gr.Radio(
361
  choices=["high", "medium", "low"],
362
+ value="low",
363
  label="📊 Punkt-Dichte",
364
+ info="Start mit LOW für Tests!"
365
  )
366
 
367
+ btn_multi = gr.Button("🎯 Segmentieren", variant="primary", size="lg")
368
 
369
  gr.Markdown("""
370
+ **⚡ Optimierte Grid-Größen:**
371
+ - 💨 Low: 2x2 = 4 Punkte (~40s) ← Empfohlen für Tests!
372
+ - ⚡ Medium: 3x3 = 9 Punkte (~90s)
373
+ - 🔥 High: 4x4 = 16 Punkte (~160s = 2.5 Min)
374
 
375
+ **Perfekt für:** Mehrere separate Objekte
376
+
377
+ **Tipp:** Jedes erkannte Objekt bekommt eigene Farbe!
378
  """)
379
 
380
  with gr.Column():
 
389
 
390
  with gr.Tab("📡 API Dokumentation"):
391
  gr.Markdown("### 🔗 API Endpoint")
392
+ gr.Code("https://EnginDev-Boostly.hf.space/api/predict", label="Base URL")
 
 
 
393
 
394
+ gr.Markdown("### 📝 JavaScript Integration")
395
  gr.Code('''
396
+ // Segmentation Service für Lovable
397
+ const API_URL = 'https://EnginDev-Boostly.hf.space';
398
 
399
  async function segmentImage(imageFile, mode = 'automatic') {
400
+ // File zu Base64
401
  const base64 = await new Promise((resolve) => {
402
  const reader = new FileReader();
403
  reader.onloadend = () => resolve(reader.result);
 
405
  });
406
 
407
  // API Call
408
+ const response = await fetch(`${API_URL}/api/predict`, {
409
  method: 'POST',
410
  headers: {'Content-Type': 'application/json'},
411
  body: JSON.stringify({
412
+ data: [base64, "high", true],
413
  fn_index: mode === 'automatic' ? 0 : 1
414
  })
415
  });
 
417
  const result = await response.json();
418
 
419
  return {
420
+ image: result.data[0], // Base64 segmentiertes Bild
421
+ metadata: result.data[1] // JSON Details
422
  };
423
  }
424
 
425
+ // Verwendung
426
+ const result = await segmentImage(myFile, 'automatic');
427
+ console.log('Objekt erkannt:', result.metadata.mask_percentage + '%');
428
  ''', language="javascript")
429
 
430
  gr.Markdown("### ⚙️ Parameter")
431
  gr.Markdown("""
432
  **fn_index:**
433
+ - `0` = Automatisch SMART (einzelnes Objekt, gefiltert)
434
+ - `1` = Multi-Region (mehrere Objekte, bunte Farben)
435
 
436
+ **quality:** `"high"` oder `"fast"`
 
 
437
 
438
+ **filter_largest (fn_index=0):** `true` = Nur Hauptobjekt, `false` = Alles
 
 
439
 
440
+ **density (fn_index=1):** `"low"`, `"medium"`, `"high"`
 
 
 
441
  """)
442
 
443
+ gr.Markdown("### 📊 Response Beispiel")
444
  gr.Code('''
445
  {
446
  "data": [
447
+ "data:image/png;base64,iVBORw...",
448
  {
449
  "success": true,
450
+ "mode": "automatic_smart",
451
+ "selected_mask_score": 0.864,
452
+ "mask_percentage": 7.2,
453
  "num_contours": 1,
454
+ "filtered": true
455
  }
456
  ]
457
  }
458
  ''', language="json")
459
 
460
  if __name__ == "__main__":
461
+ print("🌐 Launching Boostly SAM2 v2.2...")
462
  demo.launch(server_name="0.0.0.0", server_port=7860, show_error=True)