Spaces:
Build error
Build error
Commit
·
048e62d
1
Parent(s):
b854a11
Mejorar el procesamiento de video en tiempo real y la cámara alternativa
Browse files- streamlit_app.py +184 -81
streamlit_app.py
CHANGED
|
@@ -2213,10 +2213,16 @@ def main():
|
|
| 2213 |
{"iceServers": [
|
| 2214 |
{"urls": ["stun:stun.l.google.com:19302"]},
|
| 2215 |
{"urls": ["stun:stun1.l.google.com:19302"]},
|
| 2216 |
-
{"urls": ["
|
| 2217 |
]}
|
| 2218 |
)
|
| 2219 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2220 |
# Define callback to update session state with frames processed
|
| 2221 |
class VideoProcessor(VideoProcessorBase):
|
| 2222 |
def __init__(self):
|
|
@@ -2224,17 +2230,29 @@ def main():
|
|
| 2224 |
self.face_count = 0
|
| 2225 |
self.start_time = time.time()
|
| 2226 |
self.processing = True
|
| 2227 |
-
self.frame_skip =
|
|
|
|
|
|
|
| 2228 |
|
| 2229 |
def recv(self, frame):
|
| 2230 |
-
img = frame.to_ndarray(format="bgr24")
|
| 2231 |
-
self.frame_count += 1
|
| 2232 |
-
|
| 2233 |
-
# Solo procesar algunos frames para reducir carga
|
| 2234 |
-
if self.frame_count % self.frame_skip != 0:
|
| 2235 |
-
return av.VideoFrame.from_ndarray(img, format="bgr24")
|
| 2236 |
-
|
| 2237 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2238 |
# Verificar que la imagen no sea nula
|
| 2239 |
if img is None or img.size == 0 or img.shape[0] == 0 or img.shape[1] == 0:
|
| 2240 |
# Si la imagen es inválida, devolver un frame en blanco
|
|
@@ -2242,16 +2260,23 @@ def main():
|
|
| 2242 |
cv2.putText(blank_frame, "Error: Invalid frame", (50, 240),
|
| 2243 |
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
|
| 2244 |
return av.VideoFrame.from_ndarray(blank_frame, format="bgr24")
|
| 2245 |
-
|
| 2246 |
# Reducir tamaño del frame para procesamiento más rápido
|
| 2247 |
scale_factor = 0.5
|
| 2248 |
h, w = img.shape[:2]
|
| 2249 |
-
|
| 2250 |
-
|
|
|
|
|
|
|
|
|
|
| 2251 |
return av.VideoFrame.from_ndarray(img, format="bgr24")
|
| 2252 |
|
| 2253 |
# Detect faces - la función ahora devuelve directamente los bboxes
|
| 2254 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2255 |
|
| 2256 |
# Ajustar bounding boxes al tamaño original
|
| 2257 |
original_bboxes = []
|
|
@@ -2268,7 +2293,7 @@ def main():
|
|
| 2268 |
self.face_count = len(original_bboxes)
|
| 2269 |
current_time = time.time()
|
| 2270 |
elapsed_time = current_time - self.start_time
|
| 2271 |
-
fps = self.
|
| 2272 |
|
| 2273 |
# Actualizar métricas en session_state para que sean accesibles fuera
|
| 2274 |
st.session_state.faces_detected = self.face_count
|
|
@@ -2278,83 +2303,85 @@ def main():
|
|
| 2278 |
result_img = img.copy()
|
| 2279 |
for i, (x1, y1, x2, y2, conf) in enumerate(original_bboxes):
|
| 2280 |
cv2.rectangle(result_img, (x1, y1), (x2, y2), (0, 255, 0), 2)
|
| 2281 |
-
cv2.putText(result_img, f"
|
| 2282 |
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
|
| 2283 |
|
| 2284 |
# Añadir información FPS y rostros
|
| 2285 |
cv2.putText(result_img, f"FPS: {fps:.1f}", (10, 30),
|
| 2286 |
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
|
| 2287 |
-
cv2.putText(result_img, f"
|
| 2288 |
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
|
| 2289 |
|
| 2290 |
return av.VideoFrame.from_ndarray(result_img, format="bgr24")
|
| 2291 |
except Exception as e:
|
| 2292 |
-
print(f"Error en procesamiento de video: {str(e)}")
|
| 2293 |
-
|
| 2294 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2295 |
|
| 2296 |
-
# Display WebRTC streamer
|
|
|
|
| 2297 |
webrtc_ctx = webrtc_streamer(
|
| 2298 |
key="face-recognition",
|
| 2299 |
mode=WebRtcMode.SENDRECV,
|
| 2300 |
rtc_configuration=rtc_configuration,
|
| 2301 |
-
video_processor_factory=VideoProcessor,
|
| 2302 |
media_stream_constraints={"video": {"width": 640, "height": 480}, "audio": False},
|
|
|
|
| 2303 |
async_processing=True,
|
| 2304 |
-
video_html_attrs={
|
| 2305 |
-
"style": {"width": "100%", "margin": "0 auto", "border": "2px solid"},
|
| 2306 |
-
"controls": False,
|
| 2307 |
-
"autoPlay": True,
|
| 2308 |
-
},
|
| 2309 |
)
|
| 2310 |
|
| 2311 |
-
#
|
| 2312 |
if webrtc_ctx.state.playing:
|
| 2313 |
-
# Use a separate thread to update metrics
|
| 2314 |
faces_metric.metric("Faces detected", st.session_state.get('faces_detected', 0))
|
| 2315 |
fps_metric.metric("FPS", f"{st.session_state.get('fps', 0):.1f}")
|
| 2316 |
time_metric.metric("Status", "Running")
|
| 2317 |
|
| 2318 |
-
#
|
| 2319 |
-
st.
|
| 2320 |
-
st.warning("Note: For better performance, make sure you have good lighting and face the camera directly.")
|
| 2321 |
else:
|
| 2322 |
faces_metric.metric("Faces detected", 0)
|
| 2323 |
-
fps_metric.metric("FPS", 0)
|
| 2324 |
time_metric.metric("Status", "Stopped")
|
| 2325 |
|
| 2326 |
-
|
| 2327 |
-
st.warning("
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2328 |
|
| 2329 |
-
|
| 2330 |
-
|
| 2331 |
-
|
| 2332 |
-
|
| 2333 |
-
|
| 2334 |
-
|
| 2335 |
-
|
| 2336 |
-
|
| 2337 |
-
|
| 2338 |
-
|
| 2339 |
-
|
| 2340 |
-
|
| 2341 |
-
|
| 2342 |
-
1. Intente usar otro navegador (Chrome suele funcionar mejor)
|
| 2343 |
-
2. Asegúrese de que ha concedido permisos de cámara cuando el navegador los solicita
|
| 2344 |
-
3. Si sigue sin funcionar, use las opciones alternativas que se muestran a continuación
|
| 2345 |
-
""")
|
| 2346 |
|
| 2347 |
# Añadir opción de cámara alternativa para entornos donde WebRTC no funciona bien
|
| 2348 |
st.markdown("---")
|
| 2349 |
st.markdown("### Modo de cámara alternativo")
|
| 2350 |
|
| 2351 |
col1, col2 = st.columns(2)
|
| 2352 |
-
|
|
|
|
|
|
|
|
|
|
| 2353 |
st.session_state.simple_camera = True
|
| 2354 |
st.session_state.demo_running = False
|
| 2355 |
st.session_state.upload_mode = False
|
| 2356 |
|
| 2357 |
-
if
|
| 2358 |
st.session_state.simple_camera = False
|
| 2359 |
|
| 2360 |
if st.session_state.get('simple_camera', False):
|
|
@@ -2363,44 +2390,120 @@ def main():
|
|
| 2363 |
|
| 2364 |
# Configurar métricas
|
| 2365 |
faces_metric.metric("Faces detected", 0)
|
| 2366 |
-
fps_metric.metric("FPS", "
|
| 2367 |
time_metric.metric("Status", "Running")
|
| 2368 |
|
| 2369 |
# Cámara simple que toma una imagen a la vez
|
| 2370 |
with camera_container:
|
| 2371 |
-
st.info("Cámara simple activada. Cada imagen se procesa individualmente.")
|
| 2372 |
|
| 2373 |
# Usar imagen de la cámara
|
| 2374 |
captured_image = st.camera_input("Tomar foto para reconocimiento", key="camera_simple_input")
|
| 2375 |
|
| 2376 |
# Procesar la imagen si está disponible
|
| 2377 |
if captured_image is not None:
|
| 2378 |
-
|
| 2379 |
-
|
| 2380 |
-
|
| 2381 |
-
|
| 2382 |
-
|
| 2383 |
-
|
| 2384 |
-
|
| 2385 |
-
|
| 2386 |
-
|
| 2387 |
-
|
| 2388 |
-
|
| 2389 |
-
|
| 2390 |
-
|
| 2391 |
-
|
| 2392 |
-
|
| 2393 |
-
|
| 2394 |
-
|
| 2395 |
-
|
| 2396 |
-
|
| 2397 |
-
|
| 2398 |
-
|
| 2399 |
-
|
| 2400 |
-
|
| 2401 |
-
|
| 2402 |
-
|
| 2403 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2404 |
|
| 2405 |
# Opción alternativa en caso de problemas con WebRTC (mantenemos esta opción también)
|
| 2406 |
st.markdown("---")
|
|
|
|
| 2213 |
{"iceServers": [
|
| 2214 |
{"urls": ["stun:stun.l.google.com:19302"]},
|
| 2215 |
{"urls": ["stun:stun1.l.google.com:19302"]},
|
| 2216 |
+
{"urls": ["stun2.l.google.com:19302"]}
|
| 2217 |
]}
|
| 2218 |
)
|
| 2219 |
|
| 2220 |
+
# Initialize session state variables if they don't exist
|
| 2221 |
+
if 'faces_detected' not in st.session_state:
|
| 2222 |
+
st.session_state.faces_detected = 0
|
| 2223 |
+
if 'fps' not in st.session_state:
|
| 2224 |
+
st.session_state.fps = 0
|
| 2225 |
+
|
| 2226 |
# Define callback to update session state with frames processed
|
| 2227 |
class VideoProcessor(VideoProcessorBase):
|
| 2228 |
def __init__(self):
|
|
|
|
| 2230 |
self.face_count = 0
|
| 2231 |
self.start_time = time.time()
|
| 2232 |
self.processing = True
|
| 2233 |
+
self.frame_skip = 2 # Process every other frame to reduce load
|
| 2234 |
+
self.frames_processed = 0
|
| 2235 |
+
self.last_log_time = time.time()
|
| 2236 |
|
| 2237 |
def recv(self, frame):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2238 |
try:
|
| 2239 |
+
img = frame.to_ndarray(format="bgr24")
|
| 2240 |
+
self.frame_count += 1
|
| 2241 |
+
|
| 2242 |
+
# Solo procesar algunos frames para reducir carga
|
| 2243 |
+
if self.frame_count % self.frame_skip != 0:
|
| 2244 |
+
return av.VideoFrame.from_ndarray(img, format="bgr24")
|
| 2245 |
+
|
| 2246 |
+
self.frames_processed += 1
|
| 2247 |
+
now = time.time()
|
| 2248 |
+
|
| 2249 |
+
# Registro de diagnóstico cada 5 segundos
|
| 2250 |
+
if now - self.last_log_time > 5:
|
| 2251 |
+
print(f"Frames procesados: {self.frames_processed}, " +
|
| 2252 |
+
f"Tiempo transcurrido: {now - self.start_time:.1f}s, " +
|
| 2253 |
+
f"FPS: {self.frames_processed/(now - self.start_time):.1f}")
|
| 2254 |
+
self.last_log_time = now
|
| 2255 |
+
|
| 2256 |
# Verificar que la imagen no sea nula
|
| 2257 |
if img is None or img.size == 0 or img.shape[0] == 0 or img.shape[1] == 0:
|
| 2258 |
# Si la imagen es inválida, devolver un frame en blanco
|
|
|
|
| 2260 |
cv2.putText(blank_frame, "Error: Invalid frame", (50, 240),
|
| 2261 |
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
|
| 2262 |
return av.VideoFrame.from_ndarray(blank_frame, format="bgr24")
|
| 2263 |
+
|
| 2264 |
# Reducir tamaño del frame para procesamiento más rápido
|
| 2265 |
scale_factor = 0.5
|
| 2266 |
h, w = img.shape[:2]
|
| 2267 |
+
|
| 2268 |
+
try:
|
| 2269 |
+
small_img = cv2.resize(img, (int(w * scale_factor), int(h * scale_factor)))
|
| 2270 |
+
except Exception as e:
|
| 2271 |
+
print(f"Error al redimensionar: {e}")
|
| 2272 |
return av.VideoFrame.from_ndarray(img, format="bgr24")
|
| 2273 |
|
| 2274 |
# Detect faces - la función ahora devuelve directamente los bboxes
|
| 2275 |
+
try:
|
| 2276 |
+
bboxes = detect_face_dnn(face_net, small_img, confidence_threshold)
|
| 2277 |
+
except Exception as e:
|
| 2278 |
+
print(f"Error al detectar rostros: {e}")
|
| 2279 |
+
bboxes = []
|
| 2280 |
|
| 2281 |
# Ajustar bounding boxes al tamaño original
|
| 2282 |
original_bboxes = []
|
|
|
|
| 2293 |
self.face_count = len(original_bboxes)
|
| 2294 |
current_time = time.time()
|
| 2295 |
elapsed_time = current_time - self.start_time
|
| 2296 |
+
fps = self.frames_processed / elapsed_time if elapsed_time > 0 else 0
|
| 2297 |
|
| 2298 |
# Actualizar métricas en session_state para que sean accesibles fuera
|
| 2299 |
st.session_state.faces_detected = self.face_count
|
|
|
|
| 2303 |
result_img = img.copy()
|
| 2304 |
for i, (x1, y1, x2, y2, conf) in enumerate(original_bboxes):
|
| 2305 |
cv2.rectangle(result_img, (x1, y1), (x2, y2), (0, 255, 0), 2)
|
| 2306 |
+
cv2.putText(result_img, f"Rostro {i+1}: {conf:.2f}", (x1, y1-10),
|
| 2307 |
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
|
| 2308 |
|
| 2309 |
# Añadir información FPS y rostros
|
| 2310 |
cv2.putText(result_img, f"FPS: {fps:.1f}", (10, 30),
|
| 2311 |
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
|
| 2312 |
+
cv2.putText(result_img, f"Rostros: {self.face_count}", (10, 60),
|
| 2313 |
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
|
| 2314 |
|
| 2315 |
return av.VideoFrame.from_ndarray(result_img, format="bgr24")
|
| 2316 |
except Exception as e:
|
| 2317 |
+
print(f"Error general en procesamiento de video: {str(e)}")
|
| 2318 |
+
try:
|
| 2319 |
+
# Intentar devolver el frame original
|
| 2320 |
+
return av.VideoFrame.from_ndarray(img, format="bgr24")
|
| 2321 |
+
except:
|
| 2322 |
+
# Si eso falla, devolver un frame en blanco como último recurso
|
| 2323 |
+
blank = np.ones((480, 640, 3), dtype=np.uint8) * 255
|
| 2324 |
+
return av.VideoFrame.from_ndarray(blank, format="bgr24")
|
| 2325 |
|
| 2326 |
+
# Display WebRTC streamer con opciones simplificadas para mejorar compatibilidad
|
| 2327 |
+
st.info("⚠️ Si el video no carga: Intente usar Chrome, recargar la página o pruebe las opciones alternativas abajo.")
|
| 2328 |
webrtc_ctx = webrtc_streamer(
|
| 2329 |
key="face-recognition",
|
| 2330 |
mode=WebRtcMode.SENDRECV,
|
| 2331 |
rtc_configuration=rtc_configuration,
|
|
|
|
| 2332 |
media_stream_constraints={"video": {"width": 640, "height": 480}, "audio": False},
|
| 2333 |
+
video_processor_factory=VideoProcessor,
|
| 2334 |
async_processing=True,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2335 |
)
|
| 2336 |
|
| 2337 |
+
# Establecer y actualizar métricas
|
| 2338 |
if webrtc_ctx.state.playing:
|
|
|
|
| 2339 |
faces_metric.metric("Faces detected", st.session_state.get('faces_detected', 0))
|
| 2340 |
fps_metric.metric("FPS", f"{st.session_state.get('fps', 0):.1f}")
|
| 2341 |
time_metric.metric("Status", "Running")
|
| 2342 |
|
| 2343 |
+
# Mostrar instrucciones de uso
|
| 2344 |
+
st.success("Cámara web activada. Los rostros detectados serán identificados en tiempo real.")
|
|
|
|
| 2345 |
else:
|
| 2346 |
faces_metric.metric("Faces detected", 0)
|
| 2347 |
+
fps_metric.metric("FPS", "0")
|
| 2348 |
time_metric.metric("Status", "Stopped")
|
| 2349 |
|
| 2350 |
+
# Mostrar instrucciones de activación
|
| 2351 |
+
st.warning("Haga clic en START para activar la cámara web. Esta función puede no estar disponible en entornos como Hugging Face Spaces debido a restricciones de seguridad.")
|
| 2352 |
+
|
| 2353 |
+
# WebRTC troubleshooting
|
| 2354 |
+
with st.expander("Ayuda: Problemas con WebRTC"):
|
| 2355 |
+
st.markdown("""
|
| 2356 |
+
### Solución de problemas con WebRTC
|
| 2357 |
|
| 2358 |
+
Si el reconocimiento en tiempo real no funciona, puede deberse a las siguientes razones:
|
| 2359 |
+
|
| 2360 |
+
1. **Restricciones de seguridad en Hugging Face Spaces**: Algunos navegadores restringen el acceso a la cámara en entornos como este.
|
| 2361 |
+
2. **Problemas de conexión**: WebRTC requiere establecer una conexión que puede ser bloqueada por firewalls o proxies.
|
| 2362 |
+
3. **Permisos de cámara**: Es posible que deba conceder permisos explícitos al navegador para acceder a su cámara.
|
| 2363 |
+
|
| 2364 |
+
### Qué hacer:
|
| 2365 |
+
|
| 2366 |
+
1. Intente usar otro navegador (Chrome suele funcionar mejor)
|
| 2367 |
+
2. Asegúrese de que ha concedido permisos de cámara cuando el navegador los solicita
|
| 2368 |
+
3. Si sigue sin funcionar, use las opciones alternativas que se muestran a continuación
|
| 2369 |
+
""")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2370 |
|
| 2371 |
# Añadir opción de cámara alternativa para entornos donde WebRTC no funciona bien
|
| 2372 |
st.markdown("---")
|
| 2373 |
st.markdown("### Modo de cámara alternativo")
|
| 2374 |
|
| 2375 |
col1, col2 = st.columns(2)
|
| 2376 |
+
simple_camera = col1.button("Usar cámara simple", key="simple_camera_button1", use_container_width=True)
|
| 2377 |
+
stop_simple_camera = col2.button("Detener cámara simple", key="stop_camera_button1", use_container_width=True)
|
| 2378 |
+
|
| 2379 |
+
if simple_camera:
|
| 2380 |
st.session_state.simple_camera = True
|
| 2381 |
st.session_state.demo_running = False
|
| 2382 |
st.session_state.upload_mode = False
|
| 2383 |
|
| 2384 |
+
if stop_simple_camera:
|
| 2385 |
st.session_state.simple_camera = False
|
| 2386 |
|
| 2387 |
if st.session_state.get('simple_camera', False):
|
|
|
|
| 2390 |
|
| 2391 |
# Configurar métricas
|
| 2392 |
faces_metric.metric("Faces detected", 0)
|
| 2393 |
+
fps_metric.metric("FPS", "N/A")
|
| 2394 |
time_metric.metric("Status", "Running")
|
| 2395 |
|
| 2396 |
# Cámara simple que toma una imagen a la vez
|
| 2397 |
with camera_container:
|
| 2398 |
+
st.info("Cámara simple activada. Cada imagen se procesa individualmente. Tome una foto con su cámara para detectar rostros.")
|
| 2399 |
|
| 2400 |
# Usar imagen de la cámara
|
| 2401 |
captured_image = st.camera_input("Tomar foto para reconocimiento", key="camera_simple_input")
|
| 2402 |
|
| 2403 |
# Procesar la imagen si está disponible
|
| 2404 |
if captured_image is not None:
|
| 2405 |
+
try:
|
| 2406 |
+
# Leer imagen
|
| 2407 |
+
image_bytes = captured_image.getvalue()
|
| 2408 |
+
image = cv2.imdecode(np.frombuffer(image_bytes, np.uint8), cv2.IMREAD_COLOR)
|
| 2409 |
+
|
| 2410 |
+
if image is not None and image.size > 0:
|
| 2411 |
+
# Detectar rostros
|
| 2412 |
+
bboxes = detect_face_dnn(face_net, image, confidence_threshold)
|
| 2413 |
+
|
| 2414 |
+
# Actualizar métricas
|
| 2415 |
+
faces_metric.metric("Faces detected", len(bboxes))
|
| 2416 |
+
|
| 2417 |
+
# Dibujar resultados
|
| 2418 |
+
result_img = image.copy()
|
| 2419 |
+
for i, bbox in enumerate(bboxes):
|
| 2420 |
+
x1, y1, x2, y2, conf = bbox
|
| 2421 |
+
cv2.rectangle(result_img, (x1, y1), (x2, y2), (0, 255, 0), 2)
|
| 2422 |
+
cv2.putText(result_img, f"Rostro {i+1}: {conf:.2f}", (x1, y1-10),
|
| 2423 |
+
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
|
| 2424 |
+
|
| 2425 |
+
# Mostrar resultado
|
| 2426 |
+
st.image(result_img, channels="BGR", caption="Rostros detectados", use_column_width=True)
|
| 2427 |
+
|
| 2428 |
+
if len(bboxes) > 0:
|
| 2429 |
+
# Si hay rostros registrados, intentar reconocerlos
|
| 2430 |
+
if st.session_state.face_database and len(st.session_state.face_database) > 0:
|
| 2431 |
+
st.subheader("Reconocimiento de rostros:")
|
| 2432 |
+
|
| 2433 |
+
recognition_results = []
|
| 2434 |
+
for i, bbox in enumerate(bboxes):
|
| 2435 |
+
x1, y1, x2, y2, _ = bbox
|
| 2436 |
+
face_img = image[y1:y2, x1:x2]
|
| 2437 |
+
|
| 2438 |
+
# Extraer el embedding del rostro
|
| 2439 |
+
if model_choice == "VGG-Face":
|
| 2440 |
+
embedding = vggface_model(face_img)
|
| 2441 |
+
elif model_choice == "Facenet":
|
| 2442 |
+
embedding = facenet_model(face_img)
|
| 2443 |
+
elif model_choice == "OpenFace":
|
| 2444 |
+
embedding = openface_model(face_img)
|
| 2445 |
+
elif model_choice == "ArcFace":
|
| 2446 |
+
embedding = arcface_model(face_img)
|
| 2447 |
+
else: # Default to VGG-Face
|
| 2448 |
+
embedding = vggface_model(face_img)
|
| 2449 |
+
|
| 2450 |
+
# Comparar con rostros registrados
|
| 2451 |
+
best_match = None
|
| 2452 |
+
best_similarity = -1
|
| 2453 |
+
|
| 2454 |
+
for name, info in st.session_state.face_database.items():
|
| 2455 |
+
if 'embeddings' in info and info['embeddings']:
|
| 2456 |
+
for emb_info in info['embeddings']:
|
| 2457 |
+
if emb_info['model'] == model_choice:
|
| 2458 |
+
stored_emb = emb_info['embedding']
|
| 2459 |
+
similarity = cosine_similarity(embedding, stored_emb)
|
| 2460 |
+
|
| 2461 |
+
if similarity > similarity_threshold and similarity > best_similarity:
|
| 2462 |
+
best_similarity = similarity
|
| 2463 |
+
best_match = name
|
| 2464 |
+
|
| 2465 |
+
if best_match is not None:
|
| 2466 |
+
recognition_results.append({
|
| 2467 |
+
'bbox': bbox,
|
| 2468 |
+
'name': best_match,
|
| 2469 |
+
'similarity': best_similarity
|
| 2470 |
+
})
|
| 2471 |
+
|
| 2472 |
+
# Mostrar resultados de reconocimiento
|
| 2473 |
+
if recognition_results:
|
| 2474 |
+
result_with_names = result_img.copy()
|
| 2475 |
+
for result in recognition_results:
|
| 2476 |
+
x1, y1, x2, y2, _ = result['bbox']
|
| 2477 |
+
name = result['name']
|
| 2478 |
+
similarity = result['similarity']
|
| 2479 |
+
|
| 2480 |
+
# Dibujar nombre y similitud
|
| 2481 |
+
cv2.rectangle(result_with_names, (x1, y1), (x2, y2), (0, 255, 0), 2)
|
| 2482 |
+
label = f"{name}: {similarity:.2f}"
|
| 2483 |
+
cv2.putText(result_with_names, label, (x1, y1-10),
|
| 2484 |
+
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
|
| 2485 |
+
|
| 2486 |
+
st.image(result_with_names, channels="BGR", caption="Rostros reconocidos", use_column_width=True)
|
| 2487 |
+
|
| 2488 |
+
# Mostrar tabla de resultados
|
| 2489 |
+
results_df = pd.DataFrame([
|
| 2490 |
+
{"Nombre": r['name'], "Confianza": f"{r['similarity']:.2f}"}
|
| 2491 |
+
for r in recognition_results
|
| 2492 |
+
])
|
| 2493 |
+
st.table(results_df)
|
| 2494 |
+
else:
|
| 2495 |
+
st.warning("No se pudo reconocer ninguno de los rostros detectados.")
|
| 2496 |
+
else:
|
| 2497 |
+
st.info("No hay rostros registrados para comparar. Registre rostros en la sección 'Face Registration'.")
|
| 2498 |
+
|
| 2499 |
+
st.success(f"Se detectaron {len(bboxes)} rostros")
|
| 2500 |
+
else:
|
| 2501 |
+
st.warning("No se detectaron rostros. Intente con una iluminación mejor o una posición diferente.")
|
| 2502 |
+
else:
|
| 2503 |
+
st.error("No se pudo procesar la imagen. Intente tomar otra foto.")
|
| 2504 |
+
except Exception as e:
|
| 2505 |
+
st.error(f"Error al procesar la imagen: {str(e)}")
|
| 2506 |
+
st.info("Intente tomar otra foto o use otra opción.")
|
| 2507 |
|
| 2508 |
# Opción alternativa en caso de problemas con WebRTC (mantenemos esta opción también)
|
| 2509 |
st.markdown("---")
|