eduardo4547 commited on
Commit
ab7d075
Β·
verified Β·
1 Parent(s): 39ce9f1

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +67 -86
app.py CHANGED
@@ -10,28 +10,18 @@ import cv2
10
  from PIL import Image
11
  from transformers import pipeline as hf_pipeline
12
 
13
- # ── ZeroGPU shim ─────────────────────────────────────────────────────────────
14
- try:
15
- import spaces
16
- except ImportError:
17
- class _DummySpaces:
18
- def GPU(self, fn):
19
- return fn
20
- spaces = _DummySpaces()
21
-
22
- DEVICE = 0 if torch.cuda.is_available() else -1
23
  sam_vit_pipeline = None
24
 
25
  # ── Parametros sincronizados entre UI y backend ───────────────────────────────
26
- # Estos valores se actualizan cada vez que el usuario corre "Segmentar" en la UI.
27
- # segment_for_backend los lee para usar exactamente los mismos.
28
  PARAMS = {
29
  "pred_iou_thresh": 0.95,
30
  "stability_score_thresh": 0.5,
31
- "points_per_batch": 32,
32
  "min_mask_region_area": 4500,
33
  "box_nms_thresh": 0.8,
34
- "crops_n_layers": 1,
35
  }
36
 
37
 
@@ -50,17 +40,15 @@ def _render_masks(imagen_rgb: Image.Image, masks: list) -> Image.Image:
50
  def _load_pipeline():
51
  global sam_vit_pipeline
52
  if sam_vit_pipeline is None:
53
- print("Cargando SAM ViT-Huge...")
54
  sam_vit_pipeline = hf_pipeline(
55
  "mask-generation",
56
  model="facebook/sam-vit-huge",
57
- device=DEVICE,
58
  )
59
 
60
 
61
  # ── Segmentacion UI ───────────────────────────────────────────────────────────
62
- @spaces.GPU
63
- @torch.no_grad()
64
  def segmentar(
65
  imagen: Image.Image,
66
  pred_iou_thresh: float,
@@ -68,20 +56,17 @@ def segmentar(
68
  points_per_batch: int,
69
  min_mask_region_area: int,
70
  box_nms_thresh: float,
71
- crops_n_layers: int,
72
  ):
73
  global PARAMS
74
  if imagen is None:
75
  return None, "Sube una imagen para comenzar."
76
 
77
- # Sincronizar PARAMS con los sliders actuales
78
  PARAMS.update({
79
  "pred_iou_thresh": float(pred_iou_thresh),
80
  "stability_score_thresh": float(stability_score_thresh),
81
  "points_per_batch": int(points_per_batch),
82
  "min_mask_region_area": int(min_mask_region_area),
83
  "box_nms_thresh": float(box_nms_thresh),
84
- "crops_n_layers": int(crops_n_layers),
85
  })
86
 
87
  _load_pipeline()
@@ -93,7 +78,6 @@ def segmentar(
93
  stability_score_thresh=PARAMS["stability_score_thresh"],
94
  min_mask_region_area=PARAMS["min_mask_region_area"],
95
  box_nms_thresh=PARAMS["box_nms_thresh"],
96
- crops_n_layers=PARAMS["crops_n_layers"],
97
  )
98
  if isinstance(resultado, list):
99
  resultado = resultado[0]
@@ -105,15 +89,13 @@ def segmentar(
105
  info = (
106
  f"UI: {len(masks)} zonas | "
107
  f"iou={PARAMS['pred_iou_thresh']} stab={PARAMS['stability_score_thresh']} "
108
- f"crops={PARAMS['crops_n_layers']} min_area={PARAMS['min_mask_region_area']} "
109
  f"nms={PARAMS['box_nms_thresh']} batch={PARAMS['points_per_batch']}"
110
  )
111
  return _render_masks(imagen_rgb, masks), info
112
 
113
 
114
  # ── Endpoint para el backend Docker ──────────────────────────────────────────
115
- @spaces.GPU
116
- @torch.no_grad()
117
  def segment_for_backend(image_np: np.ndarray):
118
  """
119
  Llamado por el backend via gradio_client (api_name='/segment').
@@ -137,7 +119,6 @@ def segment_for_backend(image_np: np.ndarray):
137
  stability_score_thresh=PARAMS["stability_score_thresh"],
138
  min_mask_region_area=PARAMS["min_mask_region_area"],
139
  box_nms_thresh=PARAMS["box_nms_thresh"],
140
- crops_n_layers=PARAMS["crops_n_layers"],
141
  )
142
  if isinstance(resultado, list):
143
  resultado = resultado[0]
@@ -145,7 +126,6 @@ def segment_for_backend(image_np: np.ndarray):
145
  all_masks_raw = resultado.get("masks", [])
146
  masks_bool = [np.array(m).astype(bool) for m in all_masks_raw]
147
 
148
- # Label map: cada pixel contiene el indice de la mascara (1-based, max 254)
149
  label_map = np.zeros((h, w), dtype=np.uint8)
150
  masks_out = []
151
  for i, mask in enumerate(masks_bool[:254], start=1):
@@ -174,8 +154,8 @@ def segment_for_backend(image_np: np.ndarray):
174
  combined = {
175
  "masks": masks_out,
176
  "label_map_b64": label_map_b64,
177
- "entorno": "gpu",
178
- "motor": "SAM Auto (GPU - ZeroGPU)",
179
  "params_used": dict(PARAMS),
180
  }
181
  return overlay_np, json.dumps(combined, ensure_ascii=False)
@@ -187,68 +167,69 @@ def segment_for_backend(image_np: np.ndarray):
187
 
188
 
189
  # ── UI ────────────────────────────────────────────────────────────────────────
190
- with gr.Blocks(title="SAM Auto - Segmentacion") as demo:
191
- gr.Markdown("# Segmentacion Automatica - SAM ViT-Huge")
192
- gr.Markdown(
193
- "SAM detecta todos los elementos de la imagen de forma automatica, "
194
- "sin necesidad de seleccionar zonas ni escribir prompts."
195
- )
196
-
197
- with gr.Row():
198
- imagen_entrada = gr.Image(type="pil", label="Foto del Espacio")
199
- imagen_salida = gr.Image(label="Resultado")
200
-
201
- estado = gr.Markdown()
202
- boton = gr.Button("Segmentar", variant="primary")
203
-
204
- with gr.Accordion("Parametros de segmentacion (sincronizados con el backend)", open=True):
205
  gr.Markdown(
206
- "> Los parametros que configures aqui se aplican tanto a la UI como al backend Docker. "
207
- "Haz clic en **Segmentar** para que el backend adopte los nuevos valores."
208
  )
 
209
  with gr.Row():
210
- sl_pred_iou = gr.Slider(
211
- minimum=0.0, maximum=1.0, step=0.01, value=PARAMS["pred_iou_thresh"],
212
- label="pred_iou_thresh (↑ menos mascaras, mas limpias | HF default: 0.88)"
213
- )
214
- sl_stability = gr.Slider(
215
- minimum=0.0, maximum=1.0, step=0.01, value=PARAMS["stability_score_thresh"],
216
- label="stability_score_thresh (↑ descarta zonas inestables | HF default: 0.95)"
217
- )
218
- with gr.Row():
219
- sl_batch = gr.Slider(
220
- minimum=16, maximum=128, step=16, value=PARAMS["points_per_batch"],
221
- label="points_per_batch (no afecta calidad, solo velocidad)"
222
- )
223
- sl_min_area = gr.Slider(
224
- minimum=0, maximum=5000, step=100, value=PARAMS["min_mask_region_area"],
225
- label="min_mask_region_area px (↑ filtra zonas pequenas)"
226
- )
227
- with gr.Row():
228
- sl_nms = gr.Slider(
229
- minimum=0.0, maximum=1.0, step=0.05, value=PARAMS["box_nms_thresh"],
230
- label="box_nms_thresh (↑ permite mas solapamiento entre mascaras)"
231
- )
232
- sl_crops = gr.Slider(
233
- minimum=0, maximum=2, step=1, value=PARAMS["crops_n_layers"],
234
- label="crops_n_layers (0=imagen completa Β· 1=+4 recortes Β· 2=+16 recortes, lento)"
235
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
 
237
- all_inputs = [imagen_entrada, sl_pred_iou, sl_stability, sl_batch, sl_min_area, sl_nms, sl_crops]
238
- boton.click(fn=segmentar, inputs=all_inputs, outputs=[imagen_salida, estado])
239
- imagen_entrada.upload(fn=segmentar, inputs=all_inputs, outputs=[imagen_salida, estado])
240
-
241
- # Endpoint oculto para el backend Docker
242
- _api_in = gr.Image(type="numpy", label="backend_input", visible=False)
243
- _api_over = gr.Image(type="numpy", label="backend_overlay", visible=False)
244
- _api_json = gr.Textbox(label="backend_json", visible=False)
245
- _api_btn = gr.Button(visible=False)
246
- _api_btn.click(
247
- fn=segment_for_backend,
248
- inputs=[_api_in],
249
- outputs=[_api_over, _api_json],
250
- api_name="segment",
251
- )
252
 
 
253
  if __name__ == "__main__":
254
  demo.launch()
 
10
  from PIL import Image
11
  from transformers import pipeline as hf_pipeline
12
 
13
+ # CPU-only: use more threads for better throughput
14
+ torch.set_num_threads(4)
15
+
 
 
 
 
 
 
 
16
  sam_vit_pipeline = None
17
 
18
  # ── Parametros sincronizados entre UI y backend ───────────────────────────────
 
 
19
  PARAMS = {
20
  "pred_iou_thresh": 0.95,
21
  "stability_score_thresh": 0.5,
22
+ "points_per_batch": 16,
23
  "min_mask_region_area": 4500,
24
  "box_nms_thresh": 0.8,
 
25
  }
26
 
27
 
 
40
  def _load_pipeline():
41
  global sam_vit_pipeline
42
  if sam_vit_pipeline is None:
43
+ print("Cargando SAM ViT-Huge (CPU)...")
44
  sam_vit_pipeline = hf_pipeline(
45
  "mask-generation",
46
  model="facebook/sam-vit-huge",
47
+ device=-1,
48
  )
49
 
50
 
51
  # ── Segmentacion UI ───────────────────────────────────────────────────────────
 
 
52
  def segmentar(
53
  imagen: Image.Image,
54
  pred_iou_thresh: float,
 
56
  points_per_batch: int,
57
  min_mask_region_area: int,
58
  box_nms_thresh: float,
 
59
  ):
60
  global PARAMS
61
  if imagen is None:
62
  return None, "Sube una imagen para comenzar."
63
 
 
64
  PARAMS.update({
65
  "pred_iou_thresh": float(pred_iou_thresh),
66
  "stability_score_thresh": float(stability_score_thresh),
67
  "points_per_batch": int(points_per_batch),
68
  "min_mask_region_area": int(min_mask_region_area),
69
  "box_nms_thresh": float(box_nms_thresh),
 
70
  })
71
 
72
  _load_pipeline()
 
78
  stability_score_thresh=PARAMS["stability_score_thresh"],
79
  min_mask_region_area=PARAMS["min_mask_region_area"],
80
  box_nms_thresh=PARAMS["box_nms_thresh"],
 
81
  )
82
  if isinstance(resultado, list):
83
  resultado = resultado[0]
 
89
  info = (
90
  f"UI: {len(masks)} zonas | "
91
  f"iou={PARAMS['pred_iou_thresh']} stab={PARAMS['stability_score_thresh']} "
92
+ f"min_area={PARAMS['min_mask_region_area']} "
93
  f"nms={PARAMS['box_nms_thresh']} batch={PARAMS['points_per_batch']}"
94
  )
95
  return _render_masks(imagen_rgb, masks), info
96
 
97
 
98
  # ── Endpoint para el backend Docker ──────────────────────────────────────────
 
 
99
  def segment_for_backend(image_np: np.ndarray):
100
  """
101
  Llamado por el backend via gradio_client (api_name='/segment').
 
119
  stability_score_thresh=PARAMS["stability_score_thresh"],
120
  min_mask_region_area=PARAMS["min_mask_region_area"],
121
  box_nms_thresh=PARAMS["box_nms_thresh"],
 
122
  )
123
  if isinstance(resultado, list):
124
  resultado = resultado[0]
 
126
  all_masks_raw = resultado.get("masks", [])
127
  masks_bool = [np.array(m).astype(bool) for m in all_masks_raw]
128
 
 
129
  label_map = np.zeros((h, w), dtype=np.uint8)
130
  masks_out = []
131
  for i, mask in enumerate(masks_bool[:254], start=1):
 
154
  combined = {
155
  "masks": masks_out,
156
  "label_map_b64": label_map_b64,
157
+ "entorno": "cpu",
158
+ "motor": "SAM Auto (CPU)",
159
  "params_used": dict(PARAMS),
160
  }
161
  return overlay_np, json.dumps(combined, ensure_ascii=False)
 
167
 
168
 
169
  # ── UI ────────────────────────────────────────────────────────────────────────
170
+ def crear_app():
171
+ with gr.Blocks(title="SAM Auto - CPU") as demo:
172
+ gr.Markdown("# Segmentacion Automatica - SAM ViT-Huge (CPU)")
 
 
 
 
 
 
 
 
 
 
 
 
173
  gr.Markdown(
174
+ "SAM detecta todos los elementos de la imagen de forma automatica, "
175
+ "sin necesidad de seleccionar zonas ni escribir prompts."
176
  )
177
+
178
  with gr.Row():
179
+ imagen_entrada = gr.Image(type="pil", label="Foto del Espacio")
180
+ imagen_salida = gr.Image(label="Resultado")
181
+
182
+ estado = gr.Markdown()
183
+ boton = gr.Button("Segmentar", variant="primary")
184
+
185
+ with gr.Accordion("Parametros de segmentacion (sincronizados con el backend)", open=True):
186
+ gr.Markdown(
187
+ "> Los parametros que configures aqui se aplican tanto a la UI como al backend Docker. "
188
+ "Haz clic en **Segmentar** para que el backend adopte los nuevos valores."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
  )
190
+ with gr.Row():
191
+ sl_pred_iou = gr.Slider(
192
+ minimum=0.0, maximum=1.0, step=0.01, value=PARAMS["pred_iou_thresh"],
193
+ label="pred_iou_thresh (↑ menos mascaras, mas limpias | HF default: 0.88)"
194
+ )
195
+ sl_stability = gr.Slider(
196
+ minimum=0.0, maximum=1.0, step=0.01, value=PARAMS["stability_score_thresh"],
197
+ label="stability_score_thresh (↑ descarta zonas inestables | HF default: 0.95)"
198
+ )
199
+ with gr.Row():
200
+ sl_batch = gr.Slider(
201
+ minimum=8, maximum=64, step=8, value=PARAMS["points_per_batch"],
202
+ label="points_per_batch (en CPU mantener bajo, max recomendado: 16)"
203
+ )
204
+ sl_min_area = gr.Slider(
205
+ minimum=0, maximum=5000, step=100, value=PARAMS["min_mask_region_area"],
206
+ label="min_mask_region_area px (↑ filtra zonas pequenas)"
207
+ )
208
+ with gr.Row():
209
+ sl_nms = gr.Slider(
210
+ minimum=0.0, maximum=1.0, step=0.05, value=PARAMS["box_nms_thresh"],
211
+ label="box_nms_thresh (↑ permite mas solapamiento entre mascaras)"
212
+ )
213
+
214
+ all_inputs = [imagen_entrada, sl_pred_iou, sl_stability, sl_batch, sl_min_area, sl_nms]
215
+ boton.click(fn=segmentar, inputs=all_inputs, outputs=[imagen_salida, estado])
216
+ imagen_entrada.upload(fn=segmentar, inputs=all_inputs, outputs=[imagen_salida, estado])
217
+
218
+ # Endpoint oculto para el backend Docker
219
+ _api_in = gr.Image(type="numpy", label="backend_input", visible=False)
220
+ _api_over = gr.Image(type="numpy", label="backend_overlay", visible=False)
221
+ _api_json = gr.Textbox(label="backend_json", visible=False)
222
+ _api_btn = gr.Button(visible=False)
223
+ _api_btn.click(
224
+ fn=segment_for_backend,
225
+ inputs=[_api_in],
226
+ outputs=[_api_over, _api_json],
227
+ api_name="segment",
228
+ )
229
+
230
+ return demo
231
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232
 
233
+ demo = crear_app()
234
  if __name__ == "__main__":
235
  demo.launch()