jarondon82 commited on
Commit
784f8aa
·
1 Parent(s): 3d308e7

Add name validation and loading spinner during image processing

Browse files
Files changed (1) hide show
  1. streamlit_app.py +216 -283
streamlit_app.py CHANGED
@@ -1469,167 +1469,98 @@ def main():
1469
  # Botón de registro
1470
  register_button = st.form_submit_button("Register Face")
1471
 
1472
- if register_button and uploaded_file is not None and person_name:
1473
- # Process imagen
1474
- raw_bytes = np.asarray(bytearray(uploaded_file.read()), dtype=np.uint8)
1475
- image = cv2.imdecode(raw_bytes, cv2.IMREAD_COLOR)
1476
-
1477
- # Detect rostros
1478
- face_net = load_face_model()
1479
- detections = detect_face_dnn(face_net, image, conf_threshold=confidence_threshold)
1480
-
1481
- # Procesar detecciones y obtener bounding boxes
1482
- processed_image, bboxes = process_face_detections(image, detections, confidence_threshold)
1483
-
1484
- if not bboxes:
1485
- st.error("No faces detected in the image. Please upload another image.")
1486
- elif len(bboxes) > 1:
1487
- st.warning("Multiple faces detected. The first one will be used.")
1488
-
1489
- # Extraer embeddings del primer rostro
1490
- if bboxes and len(bboxes) > 0 and len(bboxes[0]) == 5:
1491
- embeddings_all_models = extract_face_embeddings_all_models(image, bboxes[0])
1492
-
1493
- if embeddings_all_models:
1494
- # Guardar en la base de datos
1495
- if add_to_existing and person_name in st.session_state.face_database:
1496
- # Añadir a persona existente
1497
- if 'embeddings' in st.session_state.face_database[person_name]:
1498
- # Formato nuevo con múltiples embeddings
1499
- for embedding in embeddings_all_models:
1500
- model_name = embedding['model']
1501
- model_idx = -1
1502
-
1503
- # Buscar si ya existe un embedding de este modelo
1504
- for i, model in enumerate(st.session_state.face_database[person_name]['models']):
1505
- if model == model_name:
1506
- model_idx = i
1507
- break
1508
-
1509
- if model_idx >= 0:
1510
- # Actualizar embedding existente
1511
- st.session_state.face_database[person_name]['embeddings'][model_idx] = embedding['embedding']
1512
- else:
1513
- # Añadir nuevo modelo
1514
- st.session_state.face_database[person_name]['models'].append(model_name)
1515
- st.session_state.face_database[person_name]['embeddings'].append(embedding['embedding'])
1516
-
1517
- # Incrementar contador
1518
- st.session_state.face_database[person_name]['count'] += 1
1519
- else:
1520
- # Formato antiguo, convertir a nuevo formato
1521
- old_embedding = st.session_state.face_database[person_name]['embedding']
1522
- old_model = 'VGG-Face' # Modelo por defecto para embeddings antiguos
1523
-
1524
- # Crear nuevo formato
1525
- st.session_state.face_database[person_name] = {
1526
- 'embeddings': [old_embedding],
1527
- 'models': [old_model],
1528
- 'count': 1
1529
- }
1530
-
1531
- # Añadir nuevos embeddings
1532
- for embedding in embeddings_all_models:
1533
- model_name = embedding['model']
1534
- if model_name != old_model: # Evitar duplicados
1535
- st.session_state.face_database[person_name]['models'].append(model_name)
1536
- st.session_state.face_database[person_name]['embeddings'].append(embedding['embedding'])
1537
-
1538
- # Incrementar contador
1539
- st.session_state.face_database[person_name]['count'] += 1
1540
- else:
1541
- # Crear nueva entrada
1542
- models = []
1543
- embeddings = []
1544
-
1545
- for embedding in embeddings_all_models:
1546
- models.append(embedding['model'])
1547
- embeddings.append(embedding['embedding'])
1548
-
1549
- st.session_state.face_database[person_name] = {
1550
- 'embeddings': embeddings,
1551
- 'models': models,
1552
- 'count': 1
1553
- }
1554
 
1555
- st.success(f"Face registered successfully for {person_name}!")
 
 
1556
 
1557
- # Mostrar la imagen con el rostro detectado
1558
- processed_image, _ = process_face_detections(image, [bboxes[0]], confidence_threshold)
1559
- st.image(cv2.cvtColor(processed_image, cv2.COLOR_BGR2RGB), caption=f"Registered face: {person_name}")
1560
- else:
1561
- st.error("Failed to extract embeddings. Please try again with a clearer image.")
1562
- else:
1563
- # Solo un rostro detectado
1564
- embeddings_all_models = extract_face_embeddings_all_models(image, bboxes[0])
1565
-
1566
- if embeddings_all_models:
1567
- # Guardar en la base de datos
1568
- if add_to_existing and person_name in st.session_state.face_database:
1569
- # Añadir a persona existente
1570
- if 'embeddings' in st.session_state.face_database[person_name]:
1571
- # Formato nuevo con múltiples embeddings
1572
- for embedding in embeddings_all_models:
1573
- model_name = embedding['model']
1574
- model_idx = -1
1575
-
1576
- # Buscar si ya existe un embedding de este modelo
1577
- for i, model in enumerate(st.session_state.face_database[person_name]['models']):
1578
- if model == model_name:
1579
- model_idx = i
1580
- break
 
 
 
 
 
 
 
 
 
 
 
1581
 
1582
- if model_idx >= 0:
1583
- # Actualizar embedding existente
1584
- st.session_state.face_database[person_name]['embeddings'][model_idx] = embedding['embedding']
1585
- else:
1586
- # Añadir nuevo modelo
1587
- st.session_state.face_database[person_name]['models'].append(model_name)
1588
- st.session_state.face_database[person_name]['embeddings'].append(embedding['embedding'])
1589
-
1590
- # Incrementar contador
1591
- st.session_state.face_database[person_name]['count'] += 1
1592
- else:
1593
- # Formato antiguo, convertir a nuevo formato
1594
- old_embedding = st.session_state.face_database[person_name]['embedding']
1595
- old_model = 'VGG-Face' # Modelo por defecto para embeddings antiguos
1596
-
1597
- # Crear nuevo formato
1598
- st.session_state.face_database[person_name] = {
1599
- 'embeddings': [old_embedding],
1600
- 'models': [old_model],
1601
- 'count': 1
1602
- }
1603
-
1604
- # Añadir nuevos embeddings
1605
- for embedding in embeddings_all_models:
1606
- model_name = embedding['model']
1607
- if model_name != old_model: # Evitar duplicados
1608
- st.session_state.face_database[person_name]['models'].append(model_name)
1609
- st.session_state.face_database[person_name]['embeddings'].append(embedding['embedding'])
1610
-
1611
- # Incrementar contador
1612
- st.session_state.face_database[person_name]['count'] += 1
1613
  else:
1614
- # Crear nueva entrada
1615
- models = []
1616
- embeddings = []
1617
-
1618
- for embedding in embeddings_all_models:
1619
- models.append(embedding['model'])
1620
- embeddings.append(embedding['embedding'])
1621
 
1622
- st.session_state.face_database[person_name] = {
1623
- 'embeddings': embeddings,
1624
- 'models': models,
1625
- 'count': 1
1626
- }
1627
-
1628
- st.success(f"Face registered successfully for {person_name}!")
1629
-
1630
- # Mostrar la imagen con el rostro detectado
1631
- processed_image, _ = process_face_detections(image, [bboxes[0]], confidence_threshold)
1632
- st.image(cv2.cvtColor(processed_image, cv2.COLOR_BGR2RGB), caption=f"Registered face: {person_name}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1633
  else:
1634
  st.error("Failed to extract embeddings. Please try again with a clearer image.")
1635
 
@@ -1756,145 +1687,147 @@ def main():
1756
  )
1757
 
1758
  if uploaded_file is not None:
1759
- # Process la imagen subida
1760
- raw_bytes = np.asarray(bytearray(uploaded_file.read()), dtype=np.uint8)
1761
- image = cv2.imdecode(raw_bytes, cv2.IMREAD_COLOR)
1762
-
1763
- # Detect rostros
1764
- detections = detect_face_dnn(face_net, image, confidence_threshold)
1765
- processed_image, bboxes = process_face_detections(image, detections, confidence_threshold)
1766
-
1767
- if not bboxes:
1768
- st.error("No se detectaron rostros en la imagen.")
1769
- else:
1770
- # Mostrar imagen con rostros detectados
1771
- st.image(processed_image, channels='BGR', caption="Faces detected")
1772
 
1773
- # Reconocer cada rostro
1774
- result_image = image.copy()
 
1775
 
1776
- # Crear columnas para mostrar estadísticas
1777
- stats_cols = st.columns(len(bboxes) if len(bboxes) <= 3 else 3)
1778
-
1779
- for i, bbox in enumerate(bboxes):
1780
- # Extraer embedding del rostro
1781
- embedding = extract_face_embeddings(image, bbox, model_name=model_choice)
 
 
1782
 
1783
- if embedding is not None:
1784
- # Compare con rostros registrados
1785
- matches = []
 
 
 
1786
 
1787
- for name, info in st.session_state.face_database.items():
1788
- if 'embeddings' in info:
1789
- # Nuevo formato con múltiples embeddings
1790
- similarities = []
1791
-
1792
- for idx, registered_embedding in enumerate(info['embeddings']):
1793
- # Usar el mismo modelo si es posible
1794
- if info['models'][idx] == model_choice:
1795
- weight = 1.0 # Dar más peso a embeddings del mismo modelo
1796
- else:
1797
- weight = 0.8 # Peso menor para embeddings de otros modelos
1798
-
1799
- # Asegurarse de que los embeddings sean compatibles
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1800
  try:
1801
- similarity = cosine_similarity([embedding["embedding"]], [registered_embedding])[0][0] * 100 * weight
1802
- similarities.append(similarity)
1803
  except ValueError as e:
1804
  # Si hay error de dimensiones incompatibles, omitir esta comparación
1805
- # Modelos incompatibles: {info['models'][idx]} vs {embedding['model']}
1806
  continue
1807
-
1808
- # Aplicar método de votación seleccionado
1809
- if voting_method == "Promedio":
1810
- if similarities: # Verificar que la lista no esté vacía
1811
- final_similarity = sum(similarities) / len(similarities)
1812
- else:
1813
- final_similarity = 0.0 # Valor predeterminado si no hay similitudes
1814
- elif voting_method == "Mejor coincidencia":
1815
- if similarities: # Verificar que la lista no esté vacía
1816
- final_similarity = max(similarities)
1817
- else:
1818
- final_similarity = 0.0 # Valor predeterminado si no hay similitudes
1819
- else: # Votación ponderada
1820
- if similarities: # Verificar que la lista no esté vacía
1821
- # Dar más peso a similitudes más altas
1822
- weighted_sum = sum(s * (i+1) for i, s in enumerate(sorted(similarities)))
1823
- weights_sum = sum(i+1 for i in range(len(similarities)))
1824
- final_similarity = weighted_sum / weights_sum
1825
- else:
1826
- final_similarity = 0.0 # Valor predeterminado si no hay similitudes
1827
-
1828
- matches.append({"name": name, "similarity": final_similarity, "count": info['count']})
1829
- else:
1830
- # Formato antiguo con un solo embedding
1831
- registered_embedding = info['embedding']
1832
- try:
1833
- similarity = cosine_similarity([embedding["embedding"]], [registered_embedding])[0][0] * 100
1834
- matches.append({"name": name, "similarity": similarity, "count": 1})
1835
- except ValueError as e:
1836
- # Si hay error de dimensiones incompatibles, omitir esta comparación
1837
- # Modelos incompatibles: {embedding['model']} vs formato antiguo
1838
- continue
1839
-
1840
- # Ordenar coincidencias por similitud
1841
- matches.sort(key=lambda x: x["similarity"], reverse=True)
1842
-
1843
- # Dibujar resultado en la imagen
1844
- x1, y1, x2, y2, _ = bbox
1845
-
1846
- if matches and matches[0]["similarity"] >= similarity_threshold:
1847
- # Coincidencia encontrada
1848
- best_match = matches[0]
1849
-
1850
- # Color basado en nivel de similitud
1851
- if best_match["similarity"] >= 80:
1852
- color = (0, 255, 0) # Verde para alta similitud
1853
- elif best_match["similarity"] >= 65:
1854
- color = (0, 255, 255) # Amarillo para media similitud
1855
- else:
1856
- color = (0, 165, 255) # Naranja para baja similitud
1857
 
1858
- # Dibujar rectángulo y etiqueta principal
1859
- label = f"{best_match['name']}: {best_match['similarity']:.1f}%"
1860
- cv2.rectangle(result_image, (x1, y1), (x2, y2), color, 2)
1861
- cv2.putText(result_image, label, (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2)
1862
 
1863
- # Mostrar coincidencias adicionales si está activado
1864
- if show_all_matches and len(matches) > 1:
1865
- for j, match in enumerate(matches[1:3]): # Mostrar las siguientes 2 mejores coincidencias
1866
- sub_label = f"#{j+2}: {match['name']}: {match['similarity']:.1f}%"
1867
- cv2.putText(result_image, sub_label, (x1, y1-(j+2)*20), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (200, 200, 200), 1)
1868
 
1869
- # Mostrar estadísticas en columnas
1870
- col_idx = i % 3
1871
- with stats_cols[col_idx]:
1872
- st.metric(
1873
- f"Rostro {i+1}",
1874
- f"{best_match['name']}",
1875
- f"{best_match['similarity']:.1f}%"
1876
- )
 
 
 
 
 
 
 
 
 
 
1877
  if show_all_matches and len(matches) > 1:
1878
- st.write("Otras coincidencias:")
1879
- for j, match in enumerate(matches[1:3]):
1880
- st.write(f"- {match['name']}: {match['similarity']:.1f}%")
1881
- else:
1882
- # No hay coincidencia
1883
- label = "Desconocido"
1884
- if matches:
1885
- label += f": {matches[0]['similarity']:.1f}%"
1886
-
1887
- cv2.rectangle(result_image, (x1, y1), (x2, y2), (0, 0, 255), 2)
1888
- cv2.putText(result_image, label, (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)
1889
-
1890
- # Mostrar estadísticas en columnas
1891
- col_idx = i % 3
1892
- with stats_cols[col_idx]:
1893
- st.metric(
1894
- f"Rostro {i+1}",
1895
- "Desconocido",
1896
- f"{matches[0]['similarity']:.1f}%" if matches else "N/A"
1897
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
1898
 
1899
  # Mostrar resultado
1900
  st.subheader("Recognition Result")
 
1469
  # Botón de registro
1470
  register_button = st.form_submit_button("Register Face")
1471
 
1472
+ if register_button:
1473
+ # Validar que se haya proporcionado un nombre
1474
+ if not person_name:
1475
+ st.error("Person's name is required. Please enter a name.")
1476
+ elif uploaded_file is None:
1477
+ st.error("Please upload an image.")
1478
+ else:
1479
+ # Mostrar spinner durante el procesamiento
1480
+ with st.spinner('Processing image and extracting facial features...'):
1481
+ # Process imagen
1482
+ raw_bytes = np.asarray(bytearray(uploaded_file.read()), dtype=np.uint8)
1483
+ image = cv2.imdecode(raw_bytes, cv2.IMREAD_COLOR)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1484
 
1485
+ # Detect rostros
1486
+ face_net = load_face_model()
1487
+ detections = detect_face_dnn(face_net, image, conf_threshold=confidence_threshold)
1488
 
1489
+ # Procesar detecciones y obtener bounding boxes
1490
+ processed_image, bboxes = process_face_detections(image, detections, confidence_threshold)
1491
+
1492
+ if not bboxes:
1493
+ st.error("No faces detected in the image. Please upload another image.")
1494
+ elif len(bboxes) > 1:
1495
+ st.warning("Multiple faces detected. The first one will be used.")
1496
+
1497
+ # Extraer embeddings del primer rostro
1498
+ if bboxes and len(bboxes) > 0 and len(bboxes[0]) == 5:
1499
+ embeddings_all_models = extract_face_embeddings_all_models(image, bboxes[0])
1500
+
1501
+ if embeddings_all_models:
1502
+ # Guardar en la base de datos
1503
+ if add_to_existing and person_name in st.session_state.face_database:
1504
+ # Añadir a persona existente
1505
+ if 'embeddings' in st.session_state.face_database[person_name]:
1506
+ # Formato nuevo con múltiples embeddings
1507
+ for embedding in embeddings_all_models:
1508
+ model_name = embedding['model']
1509
+ model_idx = -1
1510
+
1511
+ # Buscar si ya existe un embedding de este modelo
1512
+ for i, model in enumerate(st.session_state.face_database[person_name]['models']):
1513
+ if model == model_name:
1514
+ model_idx = i
1515
+ break
1516
+
1517
+ if model_idx >= 0:
1518
+ # Actualizar embedding existente
1519
+ st.session_state.face_database[person_name]['embeddings'][model_idx] = embedding['embedding']
1520
+ else:
1521
+ # Añadir nuevo modelo
1522
+ st.session_state.face_database[person_name]['models'].append(model_name)
1523
+ st.session_state.face_database[person_name]['embeddings'].append(embedding['embedding'])
1524
 
1525
+ # Incrementar contador
1526
+ st.session_state.face_database[person_name]['count'] += 1
1527
+ else:
1528
+ st.error("Failed to extract embeddings. Please try again with a clearer image.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1529
  else:
1530
+ # Solo un rostro detectado
1531
+ embeddings_all_models = extract_face_embeddings_all_models(image, bboxes[0])
 
 
 
 
 
1532
 
1533
+ if embeddings_all_models:
1534
+ # Guardar en la base de datos
1535
+ if add_to_existing and person_name in st.session_state.face_database:
1536
+ # Añadir a persona existente
1537
+ if 'embeddings' in st.session_state.face_database[person_name]:
1538
+ # Formato nuevo con múltiples embeddings
1539
+ for embedding in embeddings_all_models:
1540
+ model_name = embedding['model']
1541
+ model_idx = -1
1542
+
1543
+ # Buscar si ya existe un embedding de este modelo
1544
+ for i, model in enumerate(st.session_state.face_database[person_name]['models']):
1545
+ if model == model_name:
1546
+ model_idx = i
1547
+ break
1548
+
1549
+ if model_idx >= 0:
1550
+ # Actualizar embedding existente
1551
+ st.session_state.face_database[person_name]['embeddings'][model_idx] = embedding['embedding']
1552
+ else:
1553
+ # Añadir nuevo modelo
1554
+ st.session_state.face_database[person_name]['models'].append(model_name)
1555
+ st.session_state.face_database[person_name]['embeddings'].append(embedding['embedding'])
1556
+
1557
+ st.success(f"Face registered successfully for {person_name}!")
1558
+
1559
+ # Mostrar la imagen con el rostro detectado
1560
+ processed_image, _ = process_face_detections(image, [bboxes[0]], confidence_threshold)
1561
+ st.image(cv2.cvtColor(processed_image, cv2.COLOR_BGR2RGB), caption=f"Registered face: {person_name}")
1562
+ else:
1563
+ st.error("Failed to extract embeddings. Please try again with a clearer image.")
1564
  else:
1565
  st.error("Failed to extract embeddings. Please try again with a clearer image.")
1566
 
 
1687
  )
1688
 
1689
  if uploaded_file is not None:
1690
+ # Mostrar spinner durante el procesamiento
1691
+ with st.spinner('Processing image and analyzing faces...'):
1692
+ # Process la imagen subida
1693
+ raw_bytes = np.asarray(bytearray(uploaded_file.read()), dtype=np.uint8)
1694
+ image = cv2.imdecode(raw_bytes, cv2.IMREAD_COLOR)
 
 
 
 
 
 
 
 
1695
 
1696
+ # Detect rostros
1697
+ detections = detect_face_dnn(face_net, image, confidence_threshold)
1698
+ processed_image, bboxes = process_face_detections(image, detections, confidence_threshold)
1699
 
1700
+ if not bboxes:
1701
+ st.error("No se detectaron rostros en la imagen.")
1702
+ else:
1703
+ # Mostrar imagen con rostros detectados
1704
+ st.image(processed_image, channels='BGR', caption="Faces detected")
1705
+
1706
+ # Reconocer cada rostro
1707
+ result_image = image.copy()
1708
 
1709
+ # Crear columnas para mostrar estadísticas
1710
+ stats_cols = st.columns(len(bboxes) if len(bboxes) <= 3 else 3)
1711
+
1712
+ for i, bbox in enumerate(bboxes):
1713
+ # Extraer embedding del rostro
1714
+ embedding = extract_face_embeddings(image, bbox, model_name=model_choice)
1715
 
1716
+ if embedding is not None:
1717
+ # Compare con rostros registrados
1718
+ matches = []
1719
+
1720
+ for name, info in st.session_state.face_database.items():
1721
+ if 'embeddings' in info:
1722
+ # Nuevo formato con múltiples embeddings
1723
+ similarities = []
1724
+
1725
+ for idx, registered_embedding in enumerate(info['embeddings']):
1726
+ # Usar el mismo modelo si es posible
1727
+ if info['models'][idx] == model_choice:
1728
+ weight = 1.0 # Dar más peso a embeddings del mismo modelo
1729
+ else:
1730
+ weight = 0.8 # Peso menor para embeddings de otros modelos
1731
+
1732
+ # Asegurarse de que los embeddings sean compatibles
1733
+ try:
1734
+ similarity = cosine_similarity([embedding["embedding"]], [registered_embedding])[0][0] * 100 * weight
1735
+ similarities.append(similarity)
1736
+ except ValueError as e:
1737
+ # Si hay error de dimensiones incompatibles, omitir esta comparación
1738
+ # Modelos incompatibles: {info['models'][idx]} vs {embedding['model']}
1739
+ continue
1740
+
1741
+ # Aplicar método de votación seleccionado
1742
+ if voting_method == "Promedio":
1743
+ if similarities: # Verificar que la lista no esté vacía
1744
+ final_similarity = sum(similarities) / len(similarities)
1745
+ else:
1746
+ final_similarity = 0.0 # Valor predeterminado si no hay similitudes
1747
+ elif voting_method == "Mejor coincidencia":
1748
+ if similarities: # Verificar que la lista no esté vacía
1749
+ final_similarity = max(similarities)
1750
+ else:
1751
+ final_similarity = 0.0 # Valor predeterminado si no hay similitudes
1752
+ else: # Votación ponderada
1753
+ if similarities: # Verificar que la lista no esté vacía
1754
+ # Dar más peso a similitudes más altas
1755
+ weighted_sum = sum(s * (i+1) for i, s in enumerate(sorted(similarities)))
1756
+ weights_sum = sum(i+1 for i in range(len(similarities)))
1757
+ final_similarity = weighted_sum / weights_sum
1758
+ else:
1759
+ final_similarity = 0.0 # Valor predeterminado si no hay similitudes
1760
+
1761
+ matches.append({"name": name, "similarity": final_similarity, "count": info['count']})
1762
+ else:
1763
+ # Formato antiguo con un solo embedding
1764
+ registered_embedding = info['embedding']
1765
  try:
1766
+ similarity = cosine_similarity([embedding["embedding"]], [registered_embedding])[0][0] * 100
1767
+ matches.append({"name": name, "similarity": similarity, "count": 1})
1768
  except ValueError as e:
1769
  # Si hay error de dimensiones incompatibles, omitir esta comparación
1770
+ # Modelos incompatibles: {embedding['model']} vs formato antiguo
1771
  continue
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1772
 
1773
+ # Ordenar coincidencias por similitud
1774
+ matches.sort(key=lambda x: x["similarity"], reverse=True)
 
 
1775
 
1776
+ # Dibujar resultado en la imagen
1777
+ x1, y1, x2, y2, _ = bbox
 
 
 
1778
 
1779
+ if matches and matches[0]["similarity"] >= similarity_threshold:
1780
+ # Coincidencia encontrada
1781
+ best_match = matches[0]
1782
+
1783
+ # Color basado en nivel de similitud
1784
+ if best_match["similarity"] >= 80:
1785
+ color = (0, 255, 0) # Verde para alta similitud
1786
+ elif best_match["similarity"] >= 65:
1787
+ color = (0, 255, 255) # Amarillo para media similitud
1788
+ else:
1789
+ color = (0, 165, 255) # Naranja para baja similitud
1790
+
1791
+ # Dibujar rectángulo y etiqueta principal
1792
+ label = f"{best_match['name']}: {best_match['similarity']:.1f}%"
1793
+ cv2.rectangle(result_image, (x1, y1), (x2, y2), color, 2)
1794
+ cv2.putText(result_image, label, (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2)
1795
+
1796
+ # Mostrar coincidencias adicionales si está activado
1797
  if show_all_matches and len(matches) > 1:
1798
+ for j, match in enumerate(matches[1:3]): # Mostrar las siguientes 2 mejores coincidencias
1799
+ sub_label = f"#{j+2}: {match['name']}: {match['similarity']:.1f}%"
1800
+ cv2.putText(result_image, sub_label, (x1, y1-(j+2)*20), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (200, 200, 200), 1)
1801
+
1802
+ # Mostrar estadísticas en columnas
1803
+ col_idx = i % 3
1804
+ with stats_cols[col_idx]:
1805
+ st.metric(
1806
+ f"Rostro {i+1}",
1807
+ f"{best_match['name']}",
1808
+ f"{best_match['similarity']:.1f}%"
1809
+ )
1810
+ if show_all_matches and len(matches) > 1:
1811
+ st.write("Otras coincidencias:")
1812
+ for j, match in enumerate(matches[1:3]):
1813
+ st.write(f"- {match['name']}: {match['similarity']:.1f}%")
1814
+ else:
1815
+ # No hay coincidencia
1816
+ label = "Desconocido"
1817
+ if matches:
1818
+ label += f": {matches[0]['similarity']:.1f}%"
1819
+
1820
+ cv2.rectangle(result_image, (x1, y1), (x2, y2), (0, 0, 255), 2)
1821
+ cv2.putText(result_image, label, (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)
1822
+
1823
+ # Mostrar estadísticas en columnas
1824
+ col_idx = i % 3
1825
+ with stats_cols[col_idx]:
1826
+ st.metric(
1827
+ f"Rostro {i+1}",
1828
+ "Desconocido",
1829
+ f"{matches[0]['similarity']:.1f}%" if matches else "N/A"
1830
+ )
1831
 
1832
  # Mostrar resultado
1833
  st.subheader("Recognition Result")