jarondon82 commited on
Commit
fc85f1e
·
1 Parent(s): f504d9a

Mejorado detector facial y control de flujo para imágenes con demasiados rostros

Browse files
Files changed (3) hide show
  1. app.py +92 -89
  2. services/face_service.py +3 -3
  3. utils/face_validation.py +2 -1
app.py CHANGED
@@ -302,100 +302,103 @@ elif page == "Visual Analysis":
302
  display_face_validation_result(face_validation_result, img_array)
303
 
304
  # Only continue if we don't have too many faces
305
- if should_continue_processing():
306
- # 2. Validar dimensiones (como en la versión local)
307
- try:
308
- dimension_result = img_service.validate_image_dimensions(img_array)
309
- # Asegurarnos de que dimension_result contiene las claves necesarias
310
- if not isinstance(dimension_result, dict):
311
- dimension_result = {}
312
-
313
- # Asegurarnos de que contiene las claves necesarias
314
- if "width" not in dimension_result:
315
- height, width = img_array.shape[:2]
316
- dimension_result["width"] = width
317
- dimension_result["height"] = height
318
-
319
- # Verificar si es óptimo basado en las dimensiones (si no existe ya la clave)
320
- if "is_optimal" not in dimension_result:
321
- width = dimension_result["width"]
322
- height = dimension_result["height"]
323
- dimension_result["is_optimal"] = width >= 640 and height >= 480
324
- except Exception as e:
325
- st.error(f"Error validating dimensions: {str(e)}")
326
- # Crear un resultado predeterminado si hay un error
327
  height, width = img_array.shape[:2]
328
- dimension_result = {
329
- "width": width,
330
- "height": height,
331
- "is_optimal": width >= 640 and height >= 480
332
- }
333
 
334
- # 3. Evaluar calidad (como en la versión local)
335
- try:
336
- quality_result = img_service.check_image_quality(img_array)
337
- # Asegurarnos de que quality_result contiene las claves necesarias
338
- if not isinstance(quality_result, dict):
339
- quality_result = {}
340
-
341
- # Añadir claves faltantes si es necesario
342
- if "score" not in quality_result:
343
- quality_result["score"] = 50 # Valor predeterminado
344
-
345
- if "label" not in quality_result:
346
- score = quality_result["score"]
347
- if score >= 70:
348
- quality_result["label"] = "Good"
349
- elif score >= 40:
350
- quality_result["label"] = "Fair"
351
- else:
352
- quality_result["label"] = "Poor"
353
-
354
- if "brightness" not in quality_result:
355
- # Calcular brillo si no existe
356
- gray = cv2.cvtColor(img_array, cv2.COLOR_RGB2GRAY)
357
- quality_result["brightness"] = np.mean(gray) / 2.55 # Convertir a porcentaje
358
-
359
- if "contrast" not in quality_result:
360
- # Calcular contraste si no existe
361
- gray = cv2.cvtColor(img_array, cv2.COLOR_RGB2GRAY)
362
- quality_result["contrast"] = np.std(gray) / 2.55 # Convertir a porcentaje
363
-
364
- if "sharpness_label" not in quality_result:
365
- quality_result["sharpness_label"] = "Good" # Valor predeterminado
366
-
367
- if "recommendations" not in quality_result:
368
- quality_result["recommendations"] = []
369
- except Exception as e:
370
- st.error(f"Error checking quality: {str(e)}")
371
- # Crear un resultado predeterminado si hay un error
372
- quality_result = {
373
- "score": 50,
374
- "label": "Fair",
375
- "brightness": 50,
376
- "contrast": 30,
377
- "sharpness_label": "Fair",
378
- "recommendations": ["Use a clearer image for better analysis."]
379
- }
380
 
381
- # Guardar la imagen en session_state para mantener consistencia
382
- st.session_state.original_image = img_array
 
 
383
 
384
- # 4. Verificar si se debe usar imagen mejorada
385
- use_improved = "use_improved_image" in st.session_state and st.session_state["use_improved_image"]
386
- img_to_process = img_array # Por defecto usamos la imagen original
 
387
 
388
- if use_improved:
389
- try:
390
- # Convertir a BGR para procesamiento OpenCV
391
- img_bgr = cv2.cvtColor(img_array, cv2.COLOR_RGB2BGR)
392
- # Aplicar técnicas avanzadas de preprocesamiento
393
- enhanced_bgr = img_service.enhance_image_for_facial_detection(img_bgr)
394
- # Convertir de vuelta a RGB
395
- img_to_process = cv2.cvtColor(enhanced_bgr, cv2.COLOR_BGR2RGB)
396
- except Exception as e:
397
- st.warning(f"Could not apply advanced image enhancements: {str(e)}")
398
- # Ya tenemos img_to_process = img_array por defecto, no necesitamos asignarlo de nuevo
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399
 
400
  except Exception as e:
401
  st.error(f"Error processing image: {str(e)}")
 
302
  display_face_validation_result(face_validation_result, img_array)
303
 
304
  # Only continue if we don't have too many faces
305
+ if not should_continue_processing():
306
+ # Si hay demasiados rostros, terminamos la ejecución aquí
307
+ st.stop()
308
+
309
+ # 2. Validar dimensiones (como en la versión local)
310
+ try:
311
+ dimension_result = img_service.validate_image_dimensions(img_array)
312
+ # Asegurarnos de que dimension_result contiene las claves necesarias
313
+ if not isinstance(dimension_result, dict):
314
+ dimension_result = {}
315
+
316
+ # Asegurarnos de que contiene las claves necesarias
317
+ if "width" not in dimension_result:
 
 
 
 
 
 
 
 
 
318
  height, width = img_array.shape[:2]
319
+ dimension_result["width"] = width
320
+ dimension_result["height"] = height
 
 
 
321
 
322
+ # Verificar si es óptimo basado en las dimensiones (si no existe ya la clave)
323
+ if "is_optimal" not in dimension_result:
324
+ width = dimension_result["width"]
325
+ height = dimension_result["height"]
326
+ dimension_result["is_optimal"] = width >= 640 and height >= 480
327
+ except Exception as e:
328
+ st.error(f"Error validating dimensions: {str(e)}")
329
+ # Crear un resultado predeterminado si hay un error
330
+ height, width = img_array.shape[:2]
331
+ dimension_result = {
332
+ "width": width,
333
+ "height": height,
334
+ "is_optimal": width >= 640 and height >= 480
335
+ }
336
+
337
+ # 3. Evaluar calidad (como en la versión local)
338
+ try:
339
+ quality_result = img_service.check_image_quality(img_array)
340
+ # Asegurarnos de que quality_result contiene las claves necesarias
341
+ if not isinstance(quality_result, dict):
342
+ quality_result = {}
343
+
344
+ # Añadir claves faltantes si es necesario
345
+ if "score" not in quality_result:
346
+ quality_result["score"] = 50 # Valor predeterminado
347
+
348
+ if "label" not in quality_result:
349
+ score = quality_result["score"]
350
+ if score >= 70:
351
+ quality_result["label"] = "Good"
352
+ elif score >= 40:
353
+ quality_result["label"] = "Fair"
354
+ else:
355
+ quality_result["label"] = "Poor"
 
 
 
 
 
 
 
 
 
 
 
 
356
 
357
+ if "brightness" not in quality_result:
358
+ # Calcular brillo si no existe
359
+ gray = cv2.cvtColor(img_array, cv2.COLOR_RGB2GRAY)
360
+ quality_result["brightness"] = np.mean(gray) / 2.55 # Convertir a porcentaje
361
 
362
+ if "contrast" not in quality_result:
363
+ # Calcular contraste si no existe
364
+ gray = cv2.cvtColor(img_array, cv2.COLOR_RGB2GRAY)
365
+ quality_result["contrast"] = np.std(gray) / 2.55 # Convertir a porcentaje
366
 
367
+ if "sharpness_label" not in quality_result:
368
+ quality_result["sharpness_label"] = "Good" # Valor predeterminado
369
+
370
+ if "recommendations" not in quality_result:
371
+ quality_result["recommendations"] = []
372
+ except Exception as e:
373
+ st.error(f"Error checking quality: {str(e)}")
374
+ # Crear un resultado predeterminado si hay un error
375
+ quality_result = {
376
+ "score": 50,
377
+ "label": "Fair",
378
+ "brightness": 50,
379
+ "contrast": 30,
380
+ "sharpness_label": "Fair",
381
+ "recommendations": ["Use a clearer image for better analysis."]
382
+ }
383
+
384
+ # Guardar la imagen en session_state para mantener consistencia
385
+ st.session_state.original_image = img_array
386
+
387
+ # 4. Verificar si se debe usar imagen mejorada
388
+ use_improved = "use_improved_image" in st.session_state and st.session_state["use_improved_image"]
389
+ img_to_process = img_array # Por defecto usamos la imagen original
390
+
391
+ if use_improved:
392
+ try:
393
+ # Convertir a BGR para procesamiento OpenCV
394
+ img_bgr = cv2.cvtColor(img_array, cv2.COLOR_RGB2BGR)
395
+ # Aplicar técnicas avanzadas de preprocesamiento
396
+ enhanced_bgr = img_service.enhance_image_for_facial_detection(img_bgr)
397
+ # Convertir de vuelta a RGB
398
+ img_to_process = cv2.cvtColor(enhanced_bgr, cv2.COLOR_BGR2RGB)
399
+ except Exception as e:
400
+ st.warning(f"Could not apply advanced image enhancements: {str(e)}")
401
+ # Ya tenemos img_to_process = img_array por defecto, no necesitamos asignarlo de nuevo
402
 
403
  except Exception as e:
404
  st.error(f"Error processing image: {str(e)}")
services/face_service.py CHANGED
@@ -64,9 +64,9 @@ class FaceDetectionService:
64
  # Detect faces with optimized parameters for better detection
65
  faces = self.face_cascade.detectMultiScale(
66
  gray,
67
- scaleFactor=1.1,
68
- minNeighbors=5,
69
- minSize=(30, 30),
70
  flags=cv2.CASCADE_SCALE_IMAGE
71
  )
72
 
 
64
  # Detect faces with optimized parameters for better detection
65
  faces = self.face_cascade.detectMultiScale(
66
  gray,
67
+ scaleFactor=1.2, # Aumentado de 1.1 a 1.2 para reducir falsos positivos
68
+ minNeighbors=6, # Aumentado de 5 a 6 para ser más selectivo
69
+ minSize=(50, 50), # Aumentado tamaño mínimo de 30x30 a 50x50
70
  flags=cv2.CASCADE_SCALE_IMAGE
71
  )
72
 
utils/face_validation.py CHANGED
@@ -97,4 +97,5 @@ def should_continue_processing() -> bool:
97
  Returns:
98
  Boolean indicating whether to continue processing
99
  """
100
- return st.session_state.get("should_continue_analysis", True)
 
 
97
  Returns:
98
  Boolean indicating whether to continue processing
99
  """
100
+ # Si la validación no ha ocurrido aún, asumimos que debemos continuar
101
+ return not st.session_state.get("too_many_faces", False)