A real-time AI-powered surveillance system that simultaneously detects violent fights, weapons (firearms, knives, grenades, etc.), and performs facial recognition β all from a single camera feed. Built with a multi-model YOLO pipeline and InsightFace, with a clean Streamlit dashboard for live monitoring and alerts.
This was built as a team exploratory project under Dr. Sanjeev Sharma, focused on exploring how far you can push real-time multi-model inference on consumer hardware without sacrificing accuracy.
- Demo & Screenshots
- What It Actually Does
- System Architecture
- Models & Accuracy
- Performance & Optimizations
- Dataset Details
- Tech Stack
- Getting Started
- Project Structure
- How It Works (in detail)
- Limitations & Future Work
- Acknowledgements
π For detailed architecture decisions, alternative models tested, and iteration history, see ARCHITECTURE.md.
The system runs as a Streamlit web app with live video feed, bounding box annotations, and a sidebar alert panel.
| Annotation | Meaning |
|---|---|
| π₯ Red box | Fight / Violence detected |
| π§ Orange box | Weapon detected (firearm, knife, etc.) |
| π© Green box | Known face identified |
| π₯ Red box (face) | Unrecognized face |
The sidebar shows real-time status: β
Safe, β οΈ Weapon Warning, or π¨ Critical Alert depending on what's happening in the frame.
Most surveillance projects I came across were basically "run YOLO on a video and draw some boxes." I wanted something more practical β a system that could:
- Detect physical fights as they happen β not just "person detected," but actual violent altercations
- Identify weapons in the frame β pistols, knives, firearms, grenades, ammo, rockets
- Recognize faces against a pre-built database β so you know who is involved, not just what is happening
- Run all three simultaneously on a single video stream without tanking the framerate
- Alert the operator with a hierarchical alert system (safe β warning β critical)
The tricky part was making all of this work together in real-time. Running three YOLO models + InsightFace on every single frame is computationally brutal, so a good chunk of the engineering effort went into optimizations (more on that below).
The backend pipeline processes each frame through multiple detection stages before rendering the annotated output.
High-level flow:
Detailed architecture with all inference paths, thresholds, and caching logic:
The pipeline works like this:
- Frame Capture β OpenCV grabs a frame from webcam or uploaded video
- Dynamic Resolution Scaling β All YOLO models run at
imgsz=480for speed; InsightFace gets a 640px-wide downscaled copy - Concurrent YOLO Inference β Three models run on every frame:
fight_detector_yolo.ptβ Custom-trained YOLOv8 for violence/fight detectionyolo11n_threat_detection.ptβ YOLO11n fine-tuned on weapon classesyolov8n-face.ptβ YOLOv8n for face localization
- InsightFace Recognition β Runs only every 5th frame (the most expensive operation), extracts 512-D ArcFace embeddings using ResNet-100 (buffalo_l), and matches against the known faces database via cosine similarity
- IoU-Based Identity Tracking β On non-InsightFace frames, YOLO face boxes are matched to cached InsightFace identities using IoU overlap, so recognized names persist smoothly between recognition frames
- Annotation & Alerts β Bounding boxes are drawn with color-coded labels, and a hierarchical alert system classifies the threat level
The system uses three specialized YOLO models running in parallel, each fine-tuned for its specific detection task.
| Model | Task | Precision | Recall | mAP@0.5 | mAP@0.5:0.95 |
|---|---|---|---|---|---|
| YOLOv8 (Custom) | Fight Detection | 0.89 | 0.86 | 0.92 | 0.70 |
| YOLO11n | Weapon Detection | 0.88 | 0.82 | 0.87 | 0.67 |
| YOLOv8n-face | Face Localization | 0.96 | 0.94 | 0.94 | 0.82 |
Face Recognition uses InsightFace's buffalo_l model (ResNet-100 backbone, ArcFace loss) and matches against the database using cosine similarity with a threshold of 0.4.
The plot below shows how confident each model's detections are in practice. Most detections cluster well above the 0.4 confidence threshold, meaning false positives are relatively rare at inference time.
Weapon detection classes: ammo, firearm, grenade, knife, pistol, rocket
Running three YOLO networks + InsightFace on every frame is extremely slow out of the box. The naive approach gives about 1.5 FPS on CPU β completely unusable for real-time surveillance. Here's what I did to fix that:
The single biggest bottleneck was InsightFace. Extracting 512-D facial embeddings with ResNet-100 is expensive. The key insight: face identities don't change between consecutive frames. So InsightFace only runs every 5th frame, and the results are cached and matched to YOLO face boxes via IoU on the intermediate frames.
A skip interval of 5 was chosen as the sweet spot β going higher starts to cause noticeable identity lag when people move quickly, while lower values don't help CPU performance much.
| Configuration | FPS | Real-Time? |
|---|---|---|
| CPU, no optimization | ~1.5 | β |
| CPU + frame-skip | ~10.5 | |
| GPU (RTX 3060) + frame-skip | ~30.0 | β Yes |
Where does the time actually go? Here's the per-model breakdown:
On GPU, total per-frame latency is ~31 ms (about 32 FPS). On CPU it's ~254 ms per frame. InsightFace dominates in both cases β which is exactly why the frame-skip optimization matters so much.
- Resolution scaling β YOLO inference runs at 480px instead of full resolution. Barely affects accuracy but significantly reduces computation.
- Streamlit caching β
@st.cache_resourceensures models are loaded once and reused across reruns, avoiding the ~15 second cold-start penalty. - Frame downscaling for InsightFace β Frames wider than 640px are resized before being passed to InsightFace, which is already resolution-tolerant.
The models were trained/fine-tuned on the following datasets:
| Category | Training Images | Validation Images |
|---|---|---|
| Violence / Physical Fights | 12,450 | 2,100 |
| Weapons (Firearms) | 8,200 | 1,500 |
| Weapons (Knives) | 5,100 | 950 |
| Human Faces | 35,000 | 5,000 |
Total: ~70,300 images across all categories. The face detection model (YOLOv8n-face) had the largest dataset, which is reflected in its higher accuracy scores.
| Component | Technology |
|---|---|
| Object Detection | YOLOv8, YOLO11n (Ultralytics) |
| Face Recognition | InsightFace (ArcFace, buffalo_l) |
| Face Embedding | ResNet-100 (512-D embeddings) |
| Video Processing | OpenCV |
| Web Interface | Streamlit |
| Deep Learning | PyTorch, ONNX Runtime |
| Language | Python 3.8+ |
- Python 3.8 or higher
- A webcam (for live mode) or video files (mp4/avi/mov/mkv)
- GPU recommended for real-time performance (CUDA-capable NVIDIA GPU)
# Clone the repository
git clone https://github.com/yourusername/threat-detection.git
cd threat-detection
# Install dependencies
pip install -r requirements.txt
# InsightFace needs to be installed separately
pip install insightface onnxruntime-gpu # or onnxruntime for CPU-onlyTo use facial recognition, create a directory structure under known_faces/:
known_faces/
βββ person_name_1/
β βββ photo1.jpg
β βββ photo2.jpg
β βββ photo3.jpg
βββ person_name_2/
β βββ photo1.jpg
β βββ photo2.jpg
βββ ...
The folder name becomes the identity label. Use 3-5 clear frontal photos per person for best results. The system automatically builds the embedding database on startup.
streamlit run app.pyThis opens a browser dashboard where you can:
- Webcam mode β Start/stop your live camera feed
- Video file mode β Upload and process any video file
.
βββ app.py # Main application (Streamlit + inference pipeline)
βββ requirements.txt # Python dependencies
βββ fight_detector_yolo.pt # YOLOv8 model β fight/violence detection
βββ yolo11n_threat_detection.pt # YOLO11n model β weapon detection (6 classes)
βββ yolov8n-face.pt # YOLOv8n model β face localization
βββ known_faces/ # Face recognition database
β βββ <person_name>/ # One folder per identity, containing reference photos
βββ graphs/ # Performance & accuracy visualizations
β βββ accuracy_comparison.png
β βββ confidence_distribution.png
β βββ dataset_composition.png
β βββ fps_comparison.png
β βββ frameskip_impact.png
β βββ latency_breakdown.png
β βββ backend_flowchart.png
β βββ backend_flowchart_simple.png
β βββ flowchart_minimal.png
βββ README.md
The fight detection model is a custom-trained YOLOv8 that classifies bounding box regions as either "normal" (class 0) or "fight" (class 1). Only class 1 detections with confidence > 0.4 trigger alerts. The model was trained on ~14,500 images of physical altercations and normal human interactions.
Uses a YOLO11n model fine-tuned on 6 weapon categories: ammo, firearm, grenade, knife, pistol, and rocket. Detections above 0.4 confidence are drawn as orange bounding boxes with the weapon class label.
This was the most complex part to get right. The pipeline works in two stages:
- Detection (every frame): YOLOv8n-face localizes all faces in the frame with bounding boxes.
- Recognition (every 5th frame): InsightFace extracts 512-dimensional ArcFace embeddings from detected faces, then compares them against pre-computed embeddings from the
known_faces/database using cosine similarity.
On frames where InsightFace doesn't run, the system uses IoU (Intersection over Union) matching to link the current YOLO face boxes to the most recent InsightFace results. This keeps identity labels stable without running the expensive recognition model every frame.
The cosine similarity threshold is set at 0.4 β intentionally low to avoid missing matches, since the ArcFace embeddings are quite discriminative even at lower thresholds.
The alert engine uses a simple hierarchy:
Fight + Weaponβ π¨ CRITICAL ALERT (red)Fight onlyβ π¨ ALERT (red)Weapon onlyββ οΈ WARNING (orange)Nothingβ β Safe (green)
Current limitations:
- No persistent logging or recording β alerts are real-time only, nothing is saved to disk
- Single-camera support β the system processes one video stream at a time
- InsightFace on CPU is still the main bottleneck even with frame-skipping
- The face recognition database is static β adding new faces requires a restart
- No temporal smoothing on fight detections, so brief false positives can occur
Things I'd like to add:
- Multi-camera support with a unified dashboard
- Alert logging with timestamps and frame snapshots
- Temporal smoothing / confirmation buffers to reduce false positive spikes
- Dynamic face enrollment through the UI (without restart)
- Integration with notification services (email, Telegram, etc.)
- RTSP stream support for actual CCTV cameras
- Ultralytics for YOLO model training and inference
- InsightFace for the ArcFace facial recognition pipeline
- Streamlit for the web interface
- OpenCV for video capture and frame processing
Built as part of coursework at IIT BHU. If you're working on something similar or have suggestions, feel free to open an issue or reach out.







