Spaces:
Sleeping
Sleeping
Commit ·
c96fcf1
1
Parent(s): 94d00f7
Alinear el umbral de ByteTrack para no perder personas detectadas
Browse filesByteTrack solo crea seguimientos nuevos con detecciones de confianza
>= high_conf_det_threshold (0.6 por defecto), así que las personas
detectadas con 0.4-0.6 nunca recibían número y no se mostraban: en el
video de ejemplo se perdía el 31% de las detecciones (ahora se muestra
el 95%, y se siguen 48 personas distintas en vez de 31). Se alinea con
CONF y la creación del tracker pasa a new_bytetrack() para probarla
sin cargar el modelo.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- camguard/detection.py +22 -5
- tests/test_detection.py +29 -0
camguard/detection.py
CHANGED
|
@@ -27,6 +27,27 @@ def load_model():
|
|
| 27 |
return RFDETRSmall()
|
| 28 |
|
| 29 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
class PersonTracker:
|
| 31 |
"""Detecta personas en cada cuadro y les asigna un número de seguimiento estable.
|
| 32 |
|
|
@@ -41,11 +62,7 @@ class PersonTracker:
|
|
| 41 |
def __init__(self, fps: float, conf: float = CONF):
|
| 42 |
self._model = load_model()
|
| 43 |
self._conf = conf
|
| 44 |
-
|
| 45 |
-
# y minimum_consecutive_frames=1 les da número desde el primer cuadro en que aparecen.
|
| 46 |
-
self._tracker = ByteTrackTracker(
|
| 47 |
-
frame_rate=fps, track_activation_threshold=conf, minimum_consecutive_frames=1
|
| 48 |
-
)
|
| 49 |
|
| 50 |
def update(self, frame_bgr: np.ndarray) -> sv.Detections:
|
| 51 |
"""Procesa el siguiente cuadro del video.
|
|
|
|
| 27 |
return RFDETRSmall()
|
| 28 |
|
| 29 |
|
| 30 |
+
def new_bytetrack(fps: float, conf: float = CONF) -> ByteTrackTracker:
|
| 31 |
+
"""Crea el tracker ByteTrack configurado para la demo.
|
| 32 |
+
|
| 33 |
+
Args:
|
| 34 |
+
fps: Cuadros por segundo que va a recibir (los analizados, no los del archivo). ByteTrack
|
| 35 |
+
lo usa para saber cuánto tiempo "recordar" a una persona que dejó de verse.
|
| 36 |
+
conf: Confianza mínima para empezar a seguir a una persona.
|
| 37 |
+
"""
|
| 38 |
+
# ByteTrack trae dos umbrales propios más exigentes que CONF: el de activación (0.7) y el de
|
| 39 |
+
# "detección de alta confianza" (0.6), que es el único que puede crear un seguimiento nuevo.
|
| 40 |
+
# Si no se alinean con CONF, una persona detectada con 0.4-0.6 nunca recibe número y no se
|
| 41 |
+
# muestra (en el video de ejemplo se perdía el 31% de las detecciones).
|
| 42 |
+
# minimum_consecutive_frames=1 les da número desde el primer cuadro en que aparecen.
|
| 43 |
+
return ByteTrackTracker(
|
| 44 |
+
frame_rate=fps,
|
| 45 |
+
track_activation_threshold=conf,
|
| 46 |
+
high_conf_det_threshold=conf,
|
| 47 |
+
minimum_consecutive_frames=1,
|
| 48 |
+
)
|
| 49 |
+
|
| 50 |
+
|
| 51 |
class PersonTracker:
|
| 52 |
"""Detecta personas en cada cuadro y les asigna un número de seguimiento estable.
|
| 53 |
|
|
|
|
| 62 |
def __init__(self, fps: float, conf: float = CONF):
|
| 63 |
self._model = load_model()
|
| 64 |
self._conf = conf
|
| 65 |
+
self._tracker = new_bytetrack(fps, conf)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
|
| 67 |
def update(self, frame_bgr: np.ndarray) -> sv.Detections:
|
| 68 |
"""Procesa el siguiente cuadro del video.
|
tests/test_detection.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import numpy as np
|
| 2 |
+
import supervision as sv
|
| 3 |
+
|
| 4 |
+
from camguard.config import PERSON_ID
|
| 5 |
+
from camguard.detection import new_bytetrack
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def person(confidence):
|
| 9 |
+
return sv.Detections(
|
| 10 |
+
xyxy=np.array([[10.0, 10.0, 30.0, 60.0]]),
|
| 11 |
+
confidence=np.array([confidence]),
|
| 12 |
+
class_id=np.array([PERSON_ID]),
|
| 13 |
+
)
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def test_tracks_people_with_confidence_between_conf_and_06():
|
| 17 |
+
# ByteTrack trae un umbral interno (0.6) para crear seguimientos: si no se alinea con CONF,
|
| 18 |
+
# una persona detectada con 0.5 nunca recibe número y no aparece (se perdía ~31%).
|
| 19 |
+
tracker = new_bytetrack(fps=5, conf=0.4)
|
| 20 |
+
for _ in range(3):
|
| 21 |
+
tracked = tracker.update(person(0.5))
|
| 22 |
+
assert tracked.tracker_id.tolist() != [-1]
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def test_ignores_people_below_conf():
|
| 26 |
+
tracker = new_bytetrack(fps=5, conf=0.4)
|
| 27 |
+
for _ in range(3):
|
| 28 |
+
tracked = tracker.update(person(0.3))
|
| 29 |
+
assert all(tid == -1 for tid in tracked.tracker_id)
|