Spaces:
Build error
Build error
Commit
·
8d03de6
1
Parent(s):
4ec605a
Añadir diagnóstico detallado para verificar funcionamiento del modelo de detección facial
Browse files- streamlit_app.py +148 -20
streamlit_app.py
CHANGED
|
@@ -127,32 +127,57 @@ def main():
|
|
| 127 |
Lista de bounding boxes con formato [x1, y1, x2, y2, confidence]
|
| 128 |
o None si no se detectan rostros
|
| 129 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 130 |
# Forzar un umbral muy bajo para aumentar la sensibilidad
|
| 131 |
internal_threshold = 0.1 # Usar este umbral internamente para mayor sensibilidad
|
| 132 |
|
| 133 |
# Añadir impresión de depuración para el umbral usado
|
| 134 |
print(f"Detecting faces with original threshold: {conf_threshold}, using internal threshold: {internal_threshold}")
|
|
|
|
| 135 |
|
| 136 |
# Obtener dimensiones de la imagen
|
| 137 |
h, w = frame.shape[:2]
|
|
|
|
| 138 |
|
| 139 |
# Crear un blob de la imagen (redimensionada a 300x300 y normalizada)
|
| 140 |
# IMPORTANTE: Los valores de media (104.0, 177.0, 123.0) son específicos
|
| 141 |
# para el modelo res10_300x300_ssd_iter_140000.caffemodel entrenado en Caffe
|
| 142 |
-
|
| 143 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 144 |
|
| 145 |
# Pasar el blob a través de la red
|
| 146 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 147 |
|
| 148 |
# Realizar la detección (forward pass)
|
| 149 |
try:
|
| 150 |
detections = net.forward()
|
| 151 |
-
|
| 152 |
except Exception as e:
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
|
|
|
| 156 |
# Intentar con Haar cascade como respaldo
|
| 157 |
print("Intentando detección con Haar cascade como respaldo...")
|
| 158 |
return detect_face_haar(frame, conf_threshold)
|
|
@@ -162,9 +187,12 @@ def main():
|
|
| 162 |
|
| 163 |
# Procesar cada detección
|
| 164 |
detection_count = 0
|
|
|
|
|
|
|
| 165 |
for i in range(detections.shape[2]):
|
| 166 |
# Extraer la confianza (probabilidad) de la detección
|
| 167 |
confidence = detections[0, 0, i, 2]
|
|
|
|
| 168 |
|
| 169 |
# Filtrar detecciones débiles por confianza (usando el umbral interno más bajo)
|
| 170 |
if confidence > internal_threshold:
|
|
@@ -182,32 +210,33 @@ def main():
|
|
| 182 |
|
| 183 |
# Imprimir información de depuración
|
| 184 |
print(f"Detección #{detection_count}: confianza={confidence:.3f}, bbox=[{x1},{y1},{x2},{y2}]")
|
|
|
|
| 185 |
|
| 186 |
# Saltar cajas inválidas (por ejemplo, con ancho o alto negativo)
|
| 187 |
width, height = x2 - x1, y2 - y1
|
| 188 |
if width <= 0 or height <= 0:
|
| 189 |
print(f"Saltando caja inválida con dimensiones: {width}x{height}")
|
|
|
|
| 190 |
continue
|
| 191 |
|
| 192 |
# Añadir la caja y la confianza a la lista de resultados
|
| 193 |
bboxes.append([x1, y1, x2, y2, confidence])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 194 |
|
| 195 |
# Dar feedback sobre el número de detecciones
|
| 196 |
-
|
| 197 |
-
|
| 198 |
|
| 199 |
# Si no se encontraron rostros, intentar con Haar cascade
|
| 200 |
if not bboxes:
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
haar_bboxes = detect_face_haar(frame, conf_threshold)
|
| 204 |
-
if haar_bboxes and len(haar_bboxes) > 0:
|
| 205 |
-
print(f"Haar cascade encontró {len(haar_bboxes)} rostro(s)")
|
| 206 |
-
return haar_bboxes
|
| 207 |
-
print("Sugerencias para mejorar la detección:")
|
| 208 |
-
print("1. Ajustar la iluminación - evitar contraluces")
|
| 209 |
-
print("2. Mirar directamente a la cámara")
|
| 210 |
-
print("3. Verificar que la cámara esté enfocada")
|
| 211 |
|
| 212 |
# Verificar si hay detecciones con umbral más bajo para depuración
|
| 213 |
for i in range(detections.shape[2]):
|
|
@@ -215,10 +244,37 @@ def main():
|
|
| 215 |
if confidence > 0.05: # Umbral muy bajo para depuración
|
| 216 |
box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
|
| 217 |
x1, y1, x2, y2 = box.astype("int")
|
| 218 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 219 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 220 |
return []
|
| 221 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 222 |
# Devolver las cajas detectadas
|
| 223 |
return bboxes
|
| 224 |
|
|
@@ -3162,6 +3218,78 @@ def main():
|
|
| 3162 |
st.markdown("---")
|
| 3163 |
st.markdown("**Privacy Note**: Video is processed in your browser and on the server. No video data is stored permanently.")
|
| 3164 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3165 |
# Si se ejecuta este archivo directamente, llamar a la función main
|
| 3166 |
if __name__ == "__main__":
|
| 3167 |
main()
|
|
|
|
| 127 |
Lista de bounding boxes con formato [x1, y1, x2, y2, confidence]
|
| 128 |
o None si no se detectan rostros
|
| 129 |
"""
|
| 130 |
+
# Crear un diagnóstico más detallado
|
| 131 |
+
log_info = f"===== DIAGNÓSTICO DE DETECCIÓN FACIAL =====\n"
|
| 132 |
+
log_info += f"Timestamp: {time.strftime('%Y-%m-%d %H:%M:%S')}\n"
|
| 133 |
+
log_info += f"Tipo de modelo: {type(net)}\n"
|
| 134 |
+
log_info += f"Forma de la imagen: {frame.shape}\n"
|
| 135 |
+
|
| 136 |
# Forzar un umbral muy bajo para aumentar la sensibilidad
|
| 137 |
internal_threshold = 0.1 # Usar este umbral internamente para mayor sensibilidad
|
| 138 |
|
| 139 |
# Añadir impresión de depuración para el umbral usado
|
| 140 |
print(f"Detecting faces with original threshold: {conf_threshold}, using internal threshold: {internal_threshold}")
|
| 141 |
+
log_info += f"Umbral original: {conf_threshold}, umbral interno: {internal_threshold}\n"
|
| 142 |
|
| 143 |
# Obtener dimensiones de la imagen
|
| 144 |
h, w = frame.shape[:2]
|
| 145 |
+
log_info += f"Dimensiones de imagen: {w}x{h}\n"
|
| 146 |
|
| 147 |
# Crear un blob de la imagen (redimensionada a 300x300 y normalizada)
|
| 148 |
# IMPORTANTE: Los valores de media (104.0, 177.0, 123.0) son específicos
|
| 149 |
# para el modelo res10_300x300_ssd_iter_140000.caffemodel entrenado en Caffe
|
| 150 |
+
try:
|
| 151 |
+
blob = cv2.dnn.blobFromImage(cv2.resize(frame, (300, 300)), 1.0,
|
| 152 |
+
(300, 300), (104.0, 177.0, 123.0))
|
| 153 |
+
log_info += f"Blob creado correctamente. Forma: {blob.shape}\n"
|
| 154 |
+
except Exception as e:
|
| 155 |
+
log_info += f"ERROR al crear blob: {str(e)}\n"
|
| 156 |
+
with open("diagnostico_deteccion.txt", "a") as f:
|
| 157 |
+
f.write(log_info)
|
| 158 |
+
print(log_info)
|
| 159 |
+
return []
|
| 160 |
|
| 161 |
# Pasar el blob a través de la red
|
| 162 |
+
try:
|
| 163 |
+
net.setInput(blob)
|
| 164 |
+
log_info += "Input establecido correctamente en la red\n"
|
| 165 |
+
except Exception as e:
|
| 166 |
+
log_info += f"ERROR al establecer input: {str(e)}\n"
|
| 167 |
+
with open("diagnostico_deteccion.txt", "a") as f:
|
| 168 |
+
f.write(log_info)
|
| 169 |
+
print(log_info)
|
| 170 |
+
return []
|
| 171 |
|
| 172 |
# Realizar la detección (forward pass)
|
| 173 |
try:
|
| 174 |
detections = net.forward()
|
| 175 |
+
log_info += f"Forward pass exitoso. Forma de las detecciones: {detections.shape}\n"
|
| 176 |
except Exception as e:
|
| 177 |
+
log_info += f"ERROR en forward pass: {str(e)}\n"
|
| 178 |
+
with open("diagnostico_deteccion.txt", "a") as f:
|
| 179 |
+
f.write(log_info)
|
| 180 |
+
print(log_info)
|
| 181 |
# Intentar con Haar cascade como respaldo
|
| 182 |
print("Intentando detección con Haar cascade como respaldo...")
|
| 183 |
return detect_face_haar(frame, conf_threshold)
|
|
|
|
| 187 |
|
| 188 |
# Procesar cada detección
|
| 189 |
detection_count = 0
|
| 190 |
+
detection_info = []
|
| 191 |
+
|
| 192 |
for i in range(detections.shape[2]):
|
| 193 |
# Extraer la confianza (probabilidad) de la detección
|
| 194 |
confidence = detections[0, 0, i, 2]
|
| 195 |
+
detection_info.append(f" {i}: confianza={confidence:.3f}")
|
| 196 |
|
| 197 |
# Filtrar detecciones débiles por confianza (usando el umbral interno más bajo)
|
| 198 |
if confidence > internal_threshold:
|
|
|
|
| 210 |
|
| 211 |
# Imprimir información de depuración
|
| 212 |
print(f"Detección #{detection_count}: confianza={confidence:.3f}, bbox=[{x1},{y1},{x2},{y2}]")
|
| 213 |
+
detection_info[i] += f", bbox=[{x1},{y1},{x2},{y2}]"
|
| 214 |
|
| 215 |
# Saltar cajas inválidas (por ejemplo, con ancho o alto negativo)
|
| 216 |
width, height = x2 - x1, y2 - y1
|
| 217 |
if width <= 0 or height <= 0:
|
| 218 |
print(f"Saltando caja inválida con dimensiones: {width}x{height}")
|
| 219 |
+
detection_info[i] += f" - INVÁLIDA: dimensiones {width}x{height}"
|
| 220 |
continue
|
| 221 |
|
| 222 |
# Añadir la caja y la confianza a la lista de resultados
|
| 223 |
bboxes.append([x1, y1, x2, y2, confidence])
|
| 224 |
+
detection_info[i] += " - AÑADIDA"
|
| 225 |
+
|
| 226 |
+
# Añadir información de detecciones al log
|
| 227 |
+
log_info += f"Detecciones totales analizadas: {detections.shape[2]}\n"
|
| 228 |
+
log_info += "Detalles de detecciones:\n"
|
| 229 |
+
for info in detection_info:
|
| 230 |
+
log_info += f"{info}\n"
|
| 231 |
|
| 232 |
# Dar feedback sobre el número de detecciones
|
| 233 |
+
log_info += f"Total de detecciones con confianza > {internal_threshold}: {detection_count}\n"
|
| 234 |
+
log_info += f"Total de cajas válidas: {len(bboxes)}\n"
|
| 235 |
|
| 236 |
# Si no se encontraron rostros, intentar con Haar cascade
|
| 237 |
if not bboxes:
|
| 238 |
+
log_info += "NO SE DETECTARON ROSTROS CON DNN\n"
|
| 239 |
+
log_info += "Intentando detección con Haar cascade como respaldo...\n"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 240 |
|
| 241 |
# Verificar si hay detecciones con umbral más bajo para depuración
|
| 242 |
for i in range(detections.shape[2]):
|
|
|
|
| 244 |
if confidence > 0.05: # Umbral muy bajo para depuración
|
| 245 |
box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
|
| 246 |
x1, y1, x2, y2 = box.astype("int")
|
| 247 |
+
log_info += f"Detección de baja confianza: {confidence:.3f} en [{x1},{y1},{x2},{y2}]\n"
|
| 248 |
+
|
| 249 |
+
# Intentar detección Haar
|
| 250 |
+
haar_bboxes = detect_face_haar(frame, conf_threshold)
|
| 251 |
+
if haar_bboxes and len(haar_bboxes) > 0:
|
| 252 |
+
log_info += f"Haar cascade encontró {len(haar_bboxes)} rostro(s)\n"
|
| 253 |
+
log_info += f"Haar bboxes: {haar_bboxes}\n"
|
| 254 |
+
|
| 255 |
+
# Guardar diagnóstico en archivo
|
| 256 |
+
with open("diagnostico_deteccion.txt", "a") as f:
|
| 257 |
+
f.write(log_info)
|
| 258 |
+
print(log_info)
|
| 259 |
+
return haar_bboxes
|
| 260 |
+
|
| 261 |
+
log_info += "Haar cascade NO detectó rostros\n"
|
| 262 |
|
| 263 |
+
# Guardar diagnóstico en archivo cuando no hay detecciones
|
| 264 |
+
with open("diagnostico_deteccion.txt", "a") as f:
|
| 265 |
+
f.write(log_info)
|
| 266 |
+
print(log_info)
|
| 267 |
return []
|
| 268 |
|
| 269 |
+
# Si llegamos aquí, hay detecciones exitosas
|
| 270 |
+
log_info += f"Detección exitosa. Retornando {len(bboxes)} bounding boxes.\n"
|
| 271 |
+
log_info += f"Bounding boxes: {bboxes}\n"
|
| 272 |
+
|
| 273 |
+
# Guardar diagnóstico en archivo
|
| 274 |
+
with open("diagnostico_deteccion.txt", "a") as f:
|
| 275 |
+
f.write(log_info)
|
| 276 |
+
print(log_info)
|
| 277 |
+
|
| 278 |
# Devolver las cajas detectadas
|
| 279 |
return bboxes
|
| 280 |
|
|
|
|
| 3218 |
st.markdown("---")
|
| 3219 |
st.markdown("**Privacy Note**: Video is processed in your browser and on the server. No video data is stored permanently.")
|
| 3220 |
|
| 3221 |
+
# Agregar opción para cargar imagen desde URL
|
| 3222 |
+
use_url = st.checkbox("Load image from URL")
|
| 3223 |
+
|
| 3224 |
+
# Diagnóstico para verificar modelos
|
| 3225 |
+
with st.expander("🔍 Diagnóstico de detección", expanded=False):
|
| 3226 |
+
st.warning("Si los rectángulos no aparecen, usa esta herramienta para verificar que los modelos de detección están funcionando correctamente.")
|
| 3227 |
+
col1, col2 = st.columns(2)
|
| 3228 |
+
|
| 3229 |
+
if col1.button("Ver diagnóstico de detección"):
|
| 3230 |
+
try:
|
| 3231 |
+
with open("diagnostico_deteccion.txt", "r") as f:
|
| 3232 |
+
diagnostico = f.read()
|
| 3233 |
+
st.code(diagnostico, language="text")
|
| 3234 |
+
except FileNotFoundError:
|
| 3235 |
+
st.info("Aún no hay información de diagnóstico disponible. Procesa una imagen primero.")
|
| 3236 |
+
|
| 3237 |
+
if col2.button("Verificar modelo"):
|
| 3238 |
+
st.info("Verificando modelo de detección facial...")
|
| 3239 |
+
|
| 3240 |
+
# Verificar si el modelo está cargado correctamente
|
| 3241 |
+
try:
|
| 3242 |
+
if 'face_net' in locals():
|
| 3243 |
+
st.success(f"Modelo cargado: {type(face_net)}")
|
| 3244 |
+
st.json({"Modelo": str(type(face_net)),
|
| 3245 |
+
"Estado": "Cargado correctamente",
|
| 3246 |
+
"Archivo del modelo": "res10_300x300_ssd_iter_140000.caffemodel",
|
| 3247 |
+
"Archivo de configuración": "deploy.prototxt.txt"})
|
| 3248 |
+
else:
|
| 3249 |
+
face_net = load_face_model()
|
| 3250 |
+
st.success(f"Modelo cargado durante verificación: {type(face_net)}")
|
| 3251 |
+
except Exception as e:
|
| 3252 |
+
st.error(f"Error al verificar modelo: {str(e)}")
|
| 3253 |
+
|
| 3254 |
+
if use_url:
|
| 3255 |
+
# Agregar campo de URL
|
| 3256 |
+
url = st.text_input("Enter image URL")
|
| 3257 |
+
|
| 3258 |
+
if st.button("Load Image from URL"):
|
| 3259 |
+
try:
|
| 3260 |
+
# Cargar imagen desde URL
|
| 3261 |
+
response = urllib.request.urlopen(url)
|
| 3262 |
+
image_data = response.read()
|
| 3263 |
+
image = cv2.imdecode(np.frombuffer(image_data, np.uint8), cv2.IMREAD_COLOR)
|
| 3264 |
+
|
| 3265 |
+
if image is not None and image.size > 0:
|
| 3266 |
+
# Detectar rostros
|
| 3267 |
+
bboxes = detect_face_dnn(face_net, image, conf_threshold)
|
| 3268 |
+
|
| 3269 |
+
if bboxes:
|
| 3270 |
+
# Mostrar imagen con rostros detectados
|
| 3271 |
+
st.image(image, channels='BGR', caption="Detected faces")
|
| 3272 |
+
|
| 3273 |
+
# Mostrar estadísticas
|
| 3274 |
+
st.subheader("Detection Summary")
|
| 3275 |
+
summary_col1, summary_col2, summary_col3 = st.columns(3)
|
| 3276 |
+
summary_col1.metric("Faces Detected", len(bboxes))
|
| 3277 |
+
summary_col2.metric("Eyes Detected", 0)
|
| 3278 |
+
summary_col3.metric("Smiles Detected", 0)
|
| 3279 |
+
|
| 3280 |
+
# Mostrar cajas detectadas
|
| 3281 |
+
st.subheader("Detected Faces")
|
| 3282 |
+
for i, bbox in enumerate(bboxes):
|
| 3283 |
+
x1, y1, x2, y2, _ = bbox
|
| 3284 |
+
cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), 2)
|
| 3285 |
+
cv2.putText(image, f"Face {i+1}", (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
|
| 3286 |
+
else:
|
| 3287 |
+
st.warning("No faces detected. Please try a different URL.")
|
| 3288 |
+
else:
|
| 3289 |
+
st.warning("Failed to load image. Please check the URL.")
|
| 3290 |
+
except Exception as e:
|
| 3291 |
+
st.error(f"Error loading image from URL: {str(e)}")
|
| 3292 |
+
|
| 3293 |
# Si se ejecuta este archivo directamente, llamar a la función main
|
| 3294 |
if __name__ == "__main__":
|
| 3295 |
main()
|