jarondon82 commited on
Commit
3617555
·
1 Parent(s): 7b0cfb4

Mejorar visibilidad de la detección facial con rectángulos más visibles y colores destacados

Browse files
Files changed (1) hide show
  1. streamlit_app.py +172 -71
streamlit_app.py CHANGED
@@ -114,50 +114,83 @@ def main():
114
  return eye_cascade, smile_cascade
115
 
116
  # Function for detecting faces in an image
117
- def detect_face_dnn(net, frame, conf_threshold=0.5):
118
  """
119
- Detecta rostros usando el modelo DNN y devuelve las detecciones.
 
 
 
 
 
 
 
 
 
120
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  try:
122
- # Verificar que el frame sea válido
123
- if frame is None or frame.size == 0 or frame.shape[0] == 0 or frame.shape[1] == 0:
124
- return []
125
-
126
- # Crear blob a partir del frame (redimensionar a 300x300, escalar, etc.)
127
- blob = cv2.dnn.blobFromImage(frame, 1.0, (300, 300), [104, 117, 123], False, False)
128
-
129
- # Establecer la entrada para la red neuronal
130
- net.setInput(blob)
131
-
132
- # Realizar la detección
133
  detections = net.forward()
 
 
 
 
134
 
135
- # Procesar las detecciones para devolver una lista de bounding boxes
136
- bboxes = []
137
- frame_h = frame.shape[0]
138
- frame_w = frame.shape[1]
 
 
 
 
139
 
140
- for i in range(detections.shape[2]):
141
- confidence = detections[0, 0, i, 2]
142
- if confidence > conf_threshold:
143
- x1 = int(detections[0, 0, i, 3] * frame_w)
144
- y1 = int(detections[0, 0, i, 4] * frame_h)
145
- x2 = int(detections[0, 0, i, 5] * frame_w)
146
- y2 = int(detections[0, 0, i, 6] * frame_h)
147
-
148
- # Asegurarse de que las coordenadas estén dentro de los límites
149
- x1 = max(0, min(x1, frame_w - 1))
150
- y1 = max(0, min(y1, frame_h - 1))
151
- x2 = max(0, min(x2, frame_w - 1))
152
- y2 = max(0, min(y2, frame_h - 1))
153
-
154
- # Añadir el bounding box y la confianza
155
- bboxes.append([x1, y1, x2, y2, confidence])
156
-
157
- return bboxes
158
- except Exception as e:
159
- st.error(f"Error en la detección de rostros: {e}")
160
- return []
 
 
 
 
 
 
 
 
 
 
 
161
 
162
  # Function for processing face detections
163
  def process_face_detections(frame, detections, conf_threshold=0.5, bbox_color=(0, 255, 0)):
@@ -2433,7 +2466,7 @@ def main():
2433
  <div style="margin-bottom: 20px;">
2434
  <video id="webcam" autoplay playsinline width="640" height="480" style="border-radius: 5px; display: none;"></video>
2435
  <canvas id="canvas" width="640" height="480" style="display: none;"></canvas>
2436
- <canvas id="display" width="640" height="480" style="border-radius: 5px; display: block; margin: 0 auto;"></canvas>
2437
  </div>
2438
  <script>
2439
  const video = document.getElementById('webcam');
@@ -2446,6 +2479,17 @@ def main():
2446
  // Para depuración
2447
  console.log('Componente de cámara inicializado');
2448
 
 
 
 
 
 
 
 
 
 
 
 
2449
  // Configuración dinámica del FPS (desde Streamlit)
2450
  const captureDelay = 1000 / %s;
2451
 
@@ -2484,6 +2528,9 @@ def main():
2484
  ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
2485
  displayCtx.drawImage(video, 0, 0, display.width, display.height);
2486
 
 
 
 
2487
  // Convertir a base64
2488
  const imageData = canvas.toDataURL('image/jpeg', 0.8);
2489
 
@@ -2521,22 +2568,46 @@ def main():
2521
  const [x1, y1, x2, y2, confidence] = box;
2522
  console.log(`Dibujando caja: (${x1}, ${y1}, ${x2}, ${y2}, ${confidence})`);
2523
 
2524
- // Dibujar rectángulo
2525
- displayCtx.strokeStyle = '#00FF00';
2526
- displayCtx.lineWidth = 3;
2527
  displayCtx.strokeRect(x1, y1, x2-x1, y2-y1);
2528
 
2529
- // Dibujar etiqueta
2530
- displayCtx.fillStyle = '#00FF00';
2531
- displayCtx.font = '16px Arial';
2532
- displayCtx.fillText(`Rostro: ${confidence.toFixed(2)}`, x1, y1-5);
 
 
 
 
 
 
 
 
2533
  } else {
2534
  console.warn('Formato de caja inválido:', box);
2535
  }
2536
  });
 
 
 
 
 
 
 
2537
  } else {
 
 
 
 
 
 
2538
  console.log('No hay cajas para dibujar o formato inválido');
2539
  }
 
 
 
2540
  }
2541
  } catch (error) {
2542
  console.error('Error al procesar mensaje:', error);
@@ -2545,12 +2616,14 @@ def main():
2545
 
2546
  // Dibujar un rectángulo de prueba para verificar que el canvas funciona
2547
  function drawTestRect() {
2548
- displayCtx.strokeStyle = '#FF0000';
2549
- displayCtx.lineWidth = 3;
2550
  displayCtx.strokeRect(50, 50, 100, 100);
 
 
2551
  displayCtx.fillStyle = '#FF0000';
2552
- displayCtx.font = '16px Arial';
2553
- displayCtx.fillText('Test Rectangle', 50, 40);
2554
  console.log('Rectángulo de prueba dibujado');
2555
  }
2556
 
@@ -2626,30 +2699,58 @@ def main():
2626
 
2627
  # Crear script para enviar datos al componente JavaScript
2628
  face_boxes_js = f"""
2629
- <script>
2630
- (function() {{
2631
- console.log('Enviando cajas al componente: {bbox_list}');
2632
- // Usar postMessage para comunicarse con el componente
2633
- window.postMessage({{
2634
- type: 'faceBoxes',
2635
- boxes: {json.dumps(bbox_list)}
2636
- }}, '*');
2637
 
2638
- // Intentar también con window.parent para casos en iframe
2639
- try {{
2640
- window.parent.postMessage({{
2641
- type: 'faceBoxes',
2642
- boxes: {json.dumps(bbox_list)}
2643
- }}, '*');
2644
- console.log('Mensaje también enviado a window.parent');
2645
- }} catch(e) {{
2646
- console.error('Error enviando a window.parent:', e);
2647
- }}
2648
- }})();
2649
- </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2650
  """
2651
- # Renderizar el script
 
2652
  st.components.v1.html(face_boxes_js, height=0, width=0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2653
  except Exception as e:
2654
  st.error(f"Error processing camera frame: {str(e)}")
2655
  st.info("Camera continues to run. Processing will be attempted on next frame.")
 
114
  return eye_cascade, smile_cascade
115
 
116
  # Function for detecting faces in an image
117
+ def detect_face_dnn(net, frame, conf_threshold=0.3):
118
  """
119
+ Detecta rostros en una imagen utilizando un modelo DNN pre-entrenado.
120
+
121
+ Args:
122
+ net: Modelo DNN cargado
123
+ frame: Imagen en formato BGR
124
+ conf_threshold: Umbral de confianza para la detección (0.0-1.0)
125
+
126
+ Returns:
127
+ Lista de bounding boxes con formato [x1, y1, x2, y2, confidence]
128
+ o None si no se detectan rostros
129
  """
130
+ # Añadir impresión de depuración para el umbral usado
131
+ print(f"Detecting faces with confidence threshold: {conf_threshold}")
132
+
133
+ # Obtener dimensiones de la imagen
134
+ h, w = frame.shape[:2]
135
+
136
+ # Crear un blob de la imagen (redimensionada a 300x300 y normalizada)
137
+ # IMPORTANTE: Los valores de media (104.0, 177.0, 123.0) son específicos
138
+ # para el modelo res10_300x300_ssd_iter_140000.caffemodel entrenado en Caffe
139
+ blob = cv2.dnn.blobFromImage(cv2.resize(frame, (300, 300)), 1.0,
140
+ (300, 300), (104.0, 177.0, 123.0))
141
+
142
+ # Pasar el blob a través de la red
143
+ net.setInput(blob)
144
+
145
+ # Realizar la detección (forward pass)
146
  try:
 
 
 
 
 
 
 
 
 
 
 
147
  detections = net.forward()
148
+ print(f"Shape of detection output: {detections.shape}")
149
+ except Exception as e:
150
+ print(f"Error al procesar la imagen con el modelo DNN: {str(e)}")
151
+ return None
152
 
153
+ # Variable para almacenar las cajas delimitadoras
154
+ bboxes = []
155
+
156
+ # Procesar cada detección
157
+ detection_count = 0
158
+ for i in range(detections.shape[2]):
159
+ # Extraer la confianza (probabilidad) de la detección
160
+ confidence = detections[0, 0, i, 2]
161
 
162
+ # Filtrar detecciones débiles por confianza
163
+ if confidence > conf_threshold:
164
+ detection_count += 1
165
+ # La red da las coordenadas de la caja normalizadas entre 0 y 1
166
+ # Multiplicamos por ancho y alto para obtener coordenadas en píxeles
167
+ box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
168
+
169
+ # Convertir a enteros
170
+ x1, y1, x2, y2 = box.astype("int")
171
+
172
+ # Garantizar que las coordenadas estén dentro de los límites de la imagen
173
+ x1, y1 = max(0, x1), max(0, y1)
174
+ x2, y2 = min(w, x2), min(h, y2)
175
+
176
+ # Imprimir información de depuración
177
+ print(f"Detección #{detection_count}: confianza={confidence:.3f}, bbox=[{x1},{y1},{x2},{y2}]")
178
+
179
+ # Saltar cajas inválidas (por ejemplo, con ancho o alto negativo)
180
+ width, height = x2 - x1, y2 - y1
181
+ if width <= 0 or height <= 0:
182
+ print(f"Saltando caja inválida con dimensiones: {width}x{height}")
183
+ continue
184
+
185
+ # Añadir la caja y la confianza a la lista de resultados
186
+ bboxes.append([x1, y1, x2, y2, confidence])
187
+
188
+ # Dar feedback sobre el número de detecciones
189
+ print(f"Total de detecciones con confianza > {conf_threshold}: {detection_count}")
190
+ print(f"Total de cajas válidas: {len(bboxes)}")
191
+
192
+ # Devolver None si no hay detecciones, o la lista de bboxes en caso contrario
193
+ return bboxes if bboxes else None
194
 
195
  # Function for processing face detections
196
  def process_face_detections(frame, detections, conf_threshold=0.5, bbox_color=(0, 255, 0)):
 
2466
  <div style="margin-bottom: 20px;">
2467
  <video id="webcam" autoplay playsinline width="640" height="480" style="border-radius: 5px; display: none;"></video>
2468
  <canvas id="canvas" width="640" height="480" style="display: none;"></canvas>
2469
+ <canvas id="display" width="640" height="480" style="border-radius: 5px; display: block; margin: 0 auto; border: 4px solid #ff5500; box-shadow: 0 0 15px rgba(255, 85, 0, 0.5);"></canvas>
2470
  </div>
2471
  <script>
2472
  const video = document.getElementById('webcam');
 
2479
  // Para depuración
2480
  console.log('Componente de cámara inicializado');
2481
 
2482
+ // Dibujar un rectángulo de prueba inmediatamente
2483
+ displayCtx.fillStyle = 'rgba(255, 255, 255, 0.5)';
2484
+ displayCtx.fillRect(0, 0, display.width, display.height);
2485
+ displayCtx.strokeStyle = '#FF0000';
2486
+ displayCtx.lineWidth = 8;
2487
+ displayCtx.strokeRect(200, 100, 240, 280);
2488
+ displayCtx.fillStyle = '#FF0000';
2489
+ displayCtx.font = '28px Arial';
2490
+ displayCtx.fillText('Rectángulo de Prueba', 210, 90);
2491
+ console.log('Rectángulo inicial de prueba dibujado');
2492
+
2493
  // Configuración dinámica del FPS (desde Streamlit)
2494
  const captureDelay = 1000 / %s;
2495
 
 
2528
  ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
2529
  displayCtx.drawImage(video, 0, 0, display.width, display.height);
2530
 
2531
+ // Dibujar un rectángulo de prueba en cada captura
2532
+ drawTestRect();
2533
+
2534
  // Convertir a base64
2535
  const imageData = canvas.toDataURL('image/jpeg', 0.8);
2536
 
 
2568
  const [x1, y1, x2, y2, confidence] = box;
2569
  console.log(`Dibujando caja: (${x1}, ${y1}, ${x2}, ${y2}, ${confidence})`);
2570
 
2571
+ // Dibujar rectángulo con colores más brillantes y líneas más gruesas
2572
+ displayCtx.strokeStyle = '#00FF00'; // Verde brillante
2573
+ displayCtx.lineWidth = 6; // Línea más gruesa
2574
  displayCtx.strokeRect(x1, y1, x2-x1, y2-y1);
2575
 
2576
+ // Añadir un relleno semitransparente para mayor visibilidad
2577
+ displayCtx.fillStyle = 'rgba(0, 255, 0, 0.2)';
2578
+ displayCtx.fillRect(x1, y1, x2-x1, y2-y1);
2579
+
2580
+ // Añadir un fondo para el texto
2581
+ displayCtx.fillStyle = 'rgba(0, 0, 0, 0.7)';
2582
+ displayCtx.fillRect(x1, y1-25, 140, 25);
2583
+
2584
+ // Dibujar etiqueta con fuente más grande
2585
+ displayCtx.fillStyle = '#FFFF00'; // Amarillo brillante
2586
+ displayCtx.font = 'bold 18px Arial';
2587
+ displayCtx.fillText(`Rostro: ${confidence.toFixed(2)}`, x1+5, y1-5);
2588
  } else {
2589
  console.warn('Formato de caja inválido:', box);
2590
  }
2591
  });
2592
+
2593
+ // Añadir indicador de cantidad de rostros detectados
2594
+ displayCtx.fillStyle = 'rgba(0, 0, 0, 0.7)';
2595
+ displayCtx.fillRect(10, 10, 200, 30);
2596
+ displayCtx.fillStyle = '#FFFFFF';
2597
+ displayCtx.font = 'bold 18px Arial';
2598
+ displayCtx.fillText(`Rostros: ${boxes.length}`, 20, 30);
2599
  } else {
2600
+ // Mensaje cuando no se detectan rostros
2601
+ displayCtx.fillStyle = 'rgba(0, 0, 0, 0.7)';
2602
+ displayCtx.fillRect(10, 10, 250, 30);
2603
+ displayCtx.fillStyle = '#FF9900';
2604
+ displayCtx.font = 'bold 18px Arial';
2605
+ displayCtx.fillText('No se detectan rostros', 20, 30);
2606
  console.log('No hay cajas para dibujar o formato inválido');
2607
  }
2608
+
2609
+ // Dibuja un rectángulo de prueba siempre, para verificar que el canvas funciona
2610
+ drawTestRect();
2611
  }
2612
  } catch (error) {
2613
  console.error('Error al procesar mensaje:', error);
 
2616
 
2617
  // Dibujar un rectángulo de prueba para verificar que el canvas funciona
2618
  function drawTestRect() {
2619
+ displayCtx.strokeStyle = '#FF0000'; // Rojo brillante
2620
+ displayCtx.lineWidth = 5;
2621
  displayCtx.strokeRect(50, 50, 100, 100);
2622
+ displayCtx.fillStyle = 'rgba(255, 0, 0, 0.3)'; // Relleno semitransparente
2623
+ displayCtx.fillRect(50, 50, 100, 100);
2624
  displayCtx.fillStyle = '#FF0000';
2625
+ displayCtx.font = 'bold 16px Arial';
2626
+ displayCtx.fillText('TEST', 85, 100);
2627
  console.log('Rectángulo de prueba dibujado');
2628
  }
2629
 
 
2699
 
2700
  # Crear script para enviar datos al componente JavaScript
2701
  face_boxes_js = f"""
2702
+ <script>
2703
+ console.log("Enviando cajas de rostros al componente: {bbox_list}");
 
 
 
 
 
 
2704
 
2705
+ // Usar setTimeout para asegurarse de que el componente está inicializado
2706
+ setTimeout(function() {{
2707
+ window.parent.postMessage(
2708
+ {{
2709
+ type: 'faceBoxes',
2710
+ boxes: {json.dumps(bbox_list)}
2711
+ }},
2712
+ '*'
2713
+ );
2714
+
2715
+ // También enviar un evento directo al iframe si existe
2716
+ try {{
2717
+ const frames = window.parent.document.getElementsByTagName('iframe');
2718
+ for(let i = 0; i < frames.length; i++) {{
2719
+ frames[i].contentWindow.postMessage(
2720
+ {{
2721
+ type: 'faceBoxes',
2722
+ boxes: {json.dumps(bbox_list)}
2723
+ }},
2724
+ '*'
2725
+ );
2726
+ }}
2727
+ console.log("Mensaje enviado a todos los iframes");
2728
+ }} catch(e) {{
2729
+ console.error("Error enviando mensaje directo a iframes:", e);
2730
+ }}
2731
+ }}, 200);
2732
+ </script>
2733
  """
2734
+
2735
+ # Inyectar el script en la página
2736
  st.components.v1.html(face_boxes_js, height=0, width=0)
2737
+
2738
+ # Agregar un script para dibujar un rectángulo de prueba,
2739
+ # independientemente de si hay detecciones o no
2740
+ test_rect_js = """
2741
+ <script>
2742
+ console.log("Enviando señal de rectángulo de prueba");
2743
+ setTimeout(function() {
2744
+ window.parent.postMessage(
2745
+ {
2746
+ type: 'testRect'
2747
+ },
2748
+ '*'
2749
+ );
2750
+ }, 100);
2751
+ </script>
2752
+ """
2753
+ st.components.v1.html(test_rect_js, height=0, width=0)
2754
  except Exception as e:
2755
  st.error(f"Error processing camera frame: {str(e)}")
2756
  st.info("Camera continues to run. Processing will be attempted on next frame.")