ShrinkGuard
Estimates the pose of each person in video, tracks them with a stable ID and flags hand gestures towards the waistband, a pocket or a bag. It produces signals for a person to review; it never makes decisions about anyone.
Help prevent losses in shops by flagging product concealment gestures for a person to review, without accusing or identifying anyone.
- Type
- Personal project
- Status
- Finished, updated in June 2026
- Areas
- AI, Backend
- Technologies
- Python
- YOLO11-pose
- ByteTrack
- OpenCV
- NumPy
- PyTorch (LSTM)
- Threading
Interactive demo
Screenshots
From the project's real code. The ones marked as sample data use simulated data instead of the backend or real video.
What it does
- 17-point pose per person with YOLO11-pose and tracking with ByteTrack
- Confidence-weighted temporal smoothing and tolerance to brief occlusions
- Regions of interest as normalised polygons, valid for any resolution
- Several cameras in parallel, one thread per source (webcam, video or RTSP)
- Saves a crop and a line in eventos.csv for each signal so it can be reviewed
What I learned
- Calibrating thresholds with precision and recall on labelled clips instead of by eye
- Adding the chest anchor raised recall from 0.37 to 0.83
- The LSTM classifier beats the heuristic in validation (F1 0.89 vs 0.82)
- GDPR, AEPD guidelines and the AI Act: why the final decision has to be human
The demo draws synthetic figures in the browser: no video, no real people, no models.
Technical decisions
- First a heuristic, then an LSTM
- Both share the same interface, so the learned classifier replaces the heuristic without touching the rest of the pipeline.
- Logic in NumPy, separate from Ultralytics and PyTorch
- The detector, the smoothing and the region of interest are tested with synthetic data, without models or video.
- Threshold chosen with precision and recall
- Measured on hand-labelled clips instead of tuned by eye.
- Temporal smoothing and occlusion tolerance
- Reduces pose estimator jitter, and a one-off detection failure does not break a real sequence.
- Human decision is mandatory
- Because of GDPR, the Spanish data protection agency (AEPD) guidelines and the AI Act: the system only flags, it never decides.
How it's built
Click each piece to see what it does.
Video file, webcam or IP camera. In multi-camera mode each source runs in its own thread.
17 body points per person and a stable ID across frames. Ultralytics is only used in pose.py.
Confidence-weighted moving average, tolerance to brief occlusions and a region of interest in normalised coordinates. NumPy only, with tests that need no video.
The waistband and chest heuristic or the PoseLSTM classifier, which scores an F1 of 0.89 vs 0.82 in validation. They can be swapped without touching the rest.
Each signal saves a timestamped crop and a line in eventos.csv. A person decides, never the system.
