- Skip half_hour_report events from webhook posts in people_flow - Handle pre-existing stale worker status files during startup gracefully - Make store_dwell_alert timestamp parsing robust against invalid/empty values - Update lessons learned and todo documentation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
People Flow Project
People flow analysis for street videos using YOLO tracking and face-based demographic estimation.
What it does
- Counts unique people when they cross a configured line
- Estimates one age bucket per counted track:
minor,adult, orsenior - Estimates one gender bucket per counted track:
maleorfemale - Writes an annotated output video, per-video JSON, and batch summary CSV
Pipeline
- Detect and track
personobjects with Ultralytics YOLO. - Assign a stable
track_idwith BoT-SORT or ByteTrack. - Count each track once when it crosses the configured line.
- Sample person crops for each track and run DeepFace age/gender analysis.
- Use track-level voting so each counted person lands in only one age bucket and one gender bucket.
Project Layout
main.py: CLI entrypointsrc/people_flow/: application modulesconfigs/default_config.yaml: default runtime settingsoutputs/: generated result filesdocs/plans/: design and implementation notes
Recommended Environment
- Linux
- NVIDIA GPU with CUDA
- Python
3.10or3.11
deepface and its transitive dependencies are not a good fit for Python 3.14, so do not build this environment on the current local interpreter version.
Install
python3.11 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
Single Video
python main.py video \
--input "/path/to/video.mp4" \
--line "0.1,0.55,0.9,0.55"
Batch Directory
python main.py batch \
--input-dir "/path/to/videos" \
--line "0.1,0.55,0.9,0.55"
RTSP Stream
python main.py --output-dir outputs rtsp \
--input "rtsp://user:password@host:554/stream"
RTSP mode behaves differently from offline video mode:
- The stream is sampled at one processed frame per second
- Statistics are isolated into 30-minute windows
- Each completed window writes one JSON file
latest.jsonis overwritten on every completed window- RTSP mode does not save annotated video by default
Output Files
Each processed video produces:
outputs/<video_stem>/<video_stem>.annotated.mp4outputs/<video_stem>/<video_stem>.json
Batch mode also produces:
outputs/batch_summary.csv
RTSP mode produces:
outputs/rtsp_stream/latest.jsonoutputs/rtsp_stream/windows/stats_YYYY-MM-DD_HH-MM-SS.json
Docker On Ubuntu 24.04 x86_64
The project can be packaged for an x86_64 NVIDIA host with Docker. The expected weight layout is:
weights/yolo11n.ptweights/deepface/age_model_weights.h5weights/deepface/gender_model_weights.h5weights/deepface/retinaface.h5
Build the image:
docker build -t people-flow-project:test .
The Docker image uses requirements-docker.txt so the container installs opencv-python-headless instead of the desktop OpenCV wheel.
The image bakes in all runtime weights and copies the DeepFace .h5 files into ~/.deepface/weights during build.
Run the management API container:
docker run -d \
--name people-flow-project \
--restart unless-stopped \
--gpus all \
--shm-size 1g \
-p 18082:18082 \
-e RTSP_URL="rtsp://user:password@host:554/stream" \
-v /path/to/config:/opt/people-flow/config \
-v /path/to/outputs:/opt/people-flow/outputs \
people-flow-project:test
Or use Compose:
docker compose up --build people-flow-project
Container behavior:
- Seeds
config/local.yamlfromconfig/config.example.yamlwhen needed - Writes RTSP updates through the child API to
runtime.rtsp_url - Exposes
GET /api/manage/healthonhttp://127.0.0.1:18082 - Persists config and outputs through mounted
./configand./outputs
Notes
minormeans age< 18adultmeans age18-59seniormeans age>= 60- Tracks without a reliable face result are counted only in
total_peopleandunknown_attributes