Supervised Machine Learning | Computer Vision | Accident Detection & Severity Assessment
- Overview
- How It Works
- System Architecture
- Models in Detail
- Project Structure
- Requirements
- Installation & Setup
- Data — What You Need & How to Prepare It
- Training the Models
- Evaluating the Models
- Running Inference (CLI)
- Streamlit Application
- How the Application Uses Trained Models
- Configuration Files
- Testing
- Future Improvements
- License
Road accidents cause massive loss of life and property every year. Delays in detecting and reporting accidents lead to slower emergency response times and increased casualties. This project builds an AI-powered system that uses computer vision and deep learning to:
- Detect whether an accident has occurred from a single image or a video clip
- Assess the severity of the detected accident
This is a supervised machine-learning project — the models learn from human-labelled datasets where each sample is tagged as either Accident or Non-Accident.
- Manual accident reporting is slow, inconsistent, and error-prone
- Emergency services often learn about accidents late, increasing casualties
- Insurance claim processing is delayed due to lack of structured reports
Input (Image / Video)
│
▼
┌──────────────┐ ┌────────────────┐
│ Is there an │ YES │ How severe is │
│ accident? │────►│ the accident? │
│ (Binary) │ │ (Severity) │
└──────┬───────┘ └────────┬───────┘
│ NO │
▼ ▼
"Non-Accident" "Minor / Moderate / Severe"
The system has three ML pipelines that work together:
"Given a single photo, is there an accident?"
- Takes one image (e.g., a traffic camera screenshot)
- Resizes it to 224 × 224 pixels
- Passes it through a MobileNetV2 CNN (pretrained on ImageNet)
- Outputs: Accident or Non-Accident with a confidence score
"Given a video clip, is there an accident?"
- Takes a short video clip (a few seconds of footage)
- Samples 16 evenly-spaced frames from the video
- Resizes each frame to 112 × 112 pixels
- Feeds all 16 frames into a 3D ResNet (R3D-18) that understands both spatial content AND temporal motion
- Outputs: Accident or Non-Accident with a confidence score
"Given an accident image, how severe is it?"
- Takes an image of a confirmed accident scene
- Passes it through a YOLOv8 model at 640 × 640 resolution
- Outputs: Severity classification (e.g., Minor / Moderate / Severe) or detected objects with bounding boxes
| Scenario | Best Pipeline |
|---|---|
| Traffic camera captures a single frame | Image Classification |
| Dashboard camera records a video clip | Video Classification |
| Accident confirmed, need to assess damage | Severity Assessment |
┌─────────────────────────────────────────────────────────────┐
│ DATA PREPARATION │
│ │
│ Raw Videos ──► extract_frames.py ──► split_frames.py │
│ Raw Images ──────────────────────► split into train/val/test│
│ Multiple Sources ──► merge_datasets.py │
│ Folder Name Fixes ──► normalize_dataset.py │
└──────────────────────────┬──────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ MODEL TRAINING │
│ │
│ train_image.py ──► MobileNetV2 ──► image_model.h5 │
│ train_video.py ──► R3D-18 ──► video_model.pth │
│ train_severity.py ──► YOLOv8 ──► severity_model.pt │
└──────────────────────────┬──────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ APPLICATION │
│ │
│ Streamlit App (app/streamlit_app.py) │
│ ├── Image Detection ──► image_service.py │
│ ├── Video Detection ──► video_service.py │
│ └── Severity Analysis ──► severity_service.py │
│ │
│ CLI Scripts (scripts/infer_*.py) │
└─────────────────────────────────────────────────────────────┘
The trained models are NOT loaded directly in the Streamlit app. Instead, a services layer (src/services/) provides clean prediction APIs:
app/streamlit_app.py
│
│ calls
▼
src/services/
├── image_service.py → predict_image(path) → {"class_index": 0, "score": 0.95}
├── video_service.py → predict_video(path) → {"class_index": 1, "score": 0.87}
└── severity_service.py → predict_severity(path) → {"class_index": 2, "score": 0.91}
│
│ uses
▼
src/image/model.py ← model architecture
src/image/dataset.py ← data loading
src/video/model.py ← model architecture
src/video/dataset.py ← frame sampling
src/severity/infer.py ← YOLO inference
src/common/config.py ← path resolution
│
│ loads weights from
▼
models/
├── image_model.h5
├── video_model.pth
└── severity_model.pt
Input Image (224 × 224 × 3)
│
▼
┌─────────────────────┐
│ Rescaling Layer │ Normalize pixels to [-1, 1]
│ (1/127.5, offset=-1)│
└──────────┬──────────┘
▼
┌─────────────────────┐
│ MobileNetV2 Base │ Pretrained on ImageNet (1.4M images)
│ (FROZEN weights) │ 1280 feature channels output
│ include_top=False │
└──────────┬──────────┘
▼
┌─────────────────────┐
│ GlobalAveragePool2D │ Reduces spatial dims → 1280-d vector
└──────────┬──────────┘
▼
┌─────────────────────┐
│ Dense(128, ReLU) │ Fully-connected hidden layer
│ Dropout(0.3) │ Regularisation to prevent overfitting
└──────────┬──────────┘
▼
┌─────────────────────┐
│ Dense(2, Softmax) │ Output: [P(Accident), P(Non-Accident)]
└─────────────────────┘
Key details:
- Transfer learning: MobileNetV2 backbone is frozen (pre-trained on ImageNet); only the top Dense layers are trained
- Loss function: Categorical cross-entropy
- Optimiser: Adam (default learning rate)
- Output: Softmax probabilities for 2 classes
- Framework: TensorFlow / Keras
- Saved as:
models/image_model.h5
Input Video → Sample 16 Frames → Each 112 × 112 × 3
│
▼
Tensor Shape: (Batch, 16, 112, 112, 3)
│
│ permute to PyTorch video format
▼
Tensor Shape: (Batch, 3, 16, 112, 112)
│ ↑
│ (C, T, H, W)
▼
┌─────────────────────┐
│ R3D-18 Backbone │ 3D ResNet with 18 layers
│ (3D convolutions) │ Learns spatial + temporal features
│ │ Understands MOTION across frames
└──────────┬──────────┘
▼
┌─────────────────────┐
│ FC Layer (512 → 2) │ Final classification
└─────────────────────┘
Output: [logit_Accident, logit_Non-Accident]
Key details:
- 3D convolutions: Unlike 2D CNNs that see one image at a time, R3D-18 uses 3D kernels that span across frames — this lets it detect motion patterns like sudden stops, collisions, and impact
- Frame sampling: 16 frames are sampled at equal intervals across the video (
np.linspace), so a 5-second or 30-second video both get 16 representative frames - Loss function: Cross-entropy loss
- Optimiser: Adam (lr=0.001)
- Output: Raw logits → softmax → class prediction
- Framework: PyTorch
- Saved as:
models/video_model.pth(state dict only)
Input Image (640 × 640)
│
▼
┌─────────────────────┐
│ YOLOv8 Model │ Can be classification or detection mode
│ (Ultralytics) │
└──────────┬──────────┘
▼
Classification Mode: {"class_index": 2, "score": 0.91} → "Severe"
OR
Detection Mode: {"detections": 3} → 3 accident-related objects found
Key details:
- YOLOv8 is trained using the Ultralytics framework with a
data.yamlconfig - Can operate in classification mode (severity grading) or detection mode (bounding boxes)
- Framework: Ultralytics
- Saved as:
models/severity_model.pt
ML_project/
│
├── app/ # ── STREAMLIT APPLICATION ──
│ ├── __init__.py
│ ├── streamlit_app.py # Main UI: upload → predict → display
│ ├── components.py # Reusable UI: result cards, confidence gauge
│ └── config.py # Model paths, label maps, colours
│
├── src/ # ── CORE ML LIBRARY ──
│ ├── __init__.py
│ ├── common/
│ │ ├── __init__.py
│ │ └── config.py # YAML loader, path resolver
│ ├── image/
│ │ ├── __init__.py
│ │ ├── model.py # build_mobilenet_v2() → tf.keras.Model
│ │ └── dataset.py # load_image_datasets() → train/val/test
│ ├── video/
│ │ ├── __init__.py
│ │ ├── model.py # VideoClassifier(nn.Module) → R3D-18
│ │ └── dataset.py # VideoDataset class → frame sampler
│ ├── severity/
│ │ ├── __init__.py
│ │ └── infer.py # infer_severity() → YOLOv8 prediction
│ └── services/ # High-level prediction APIs
│ ├── __init__.py
│ ├── image_service.py # predict_image(path) → dict
│ ├── video_service.py # predict_video(path) → dict
│ └── severity_service.py # predict_severity(path) → dict
│
├── scripts/ # ── CLI SCRIPTS ──
│ ├── train_image.py # Train MobileNetV2
│ ├── train_video.py # Train R3D-18
│ ├── train_severity.py # Train YOLOv8 severity
│ ├── eval_image.py # Evaluate image model (metrics + ROC)
│ ├── eval_video.py # Evaluate video model (conf matrix)
│ ├── eval_severity.py # Evaluate severity model
│ ├── infer_image.py # Single-image CLI inference
│ ├── infer_video.py # Single-video CLI inference
│ └── normalize_dataset.py # Fix class folder name variants
│
├── preprocessing/ # ── DATA PREPARATION ──
│ ├── extract_frames.py # Video → individual frame images
│ ├── split_frames.py # Split all_data/ → train/val/test
│ ├── merge_datasets.py # Combine multiple dataset sources
│ └── load_and_visualize.py # Dataset statistics & sample viz
│
├── configs/ # ── CONFIGURATION ──
│ ├── yolo_config.yaml # YOLO model, classes, tracking params
│ └── detection_config.yaml # Collision detection heuristic thresholds
│
├── models/ # ── TRAINED WEIGHTS (git-ignored) ──
│ ├── image_model.h5 # Keras image classifier
│ ├── video_model.pth # PyTorch video classifier
│ ├── severity_model.pt # YOLOv8 severity model
│ ├── yolov8n.pt # YOLOv8 nano (base)
│ └── yolov8x.pt # YOLOv8 extra-large (base)
│
├── data/ # ── SAMPLE DATA (git-ignored) ──
│ ├── image/ # Sample accident/non-accident images
│ └── videos/ # Sample accident/non-accident videos
│
├── tests/ # ── TEST SUITE ──
│ ├── test_services.py # Tests for image & video services
│ └── test_severity.py # Tests for severity service
│
├── .gitignore # Ignores data/, models/, venv/, etc.
├── MIT License.md
├── README.md # ← You are here
├── requirements.txt # Python dependencies
└── setup.py # Package configuration
| Component | Minimum | Recommended |
|---|---|---|
| RAM | 8 GB | 16 GB |
| GPU | Not required (CPU works) | NVIDIA GPU with CUDA (for faster training) |
| Disk | 5 GB (code + models) | 20 GB+ (with datasets) |
| Software | Version |
|---|---|
| Python | 3.9 or higher |
| pip | Latest |
| Git | Any |
| OS | Windows 10/11, Linux, macOS |
| Package | Purpose | Version |
|---|---|---|
tensorflow |
Image model (MobileNetV2) training & inference | ≥ 2.12.0 |
torch |
Video model (R3D-18) training & inference | ≥ 2.2.0 |
torchvision |
Pretrained video models, transforms | ≥ 0.17.0 |
ultralytics |
YOLOv8 severity model | ≥ 8.1.0 |
opencv-python |
Video reading, frame extraction, image processing | ≥ 4.9.0 |
numpy |
Array operations | ≥ 1.26.0 |
pillow |
Image loading/saving | ≥ 10.2.0 |
matplotlib |
Plotting training curves, confusion matrices | ≥ 3.8.0 |
seaborn |
Statistical visualisation | ≥ 0.12.0 |
scikit-learn |
Metrics (confusion matrix, classification report, ROC) | ≥ 1.2.0 |
pandas |
Data manipulation | ≥ 2.0.0 |
pyyaml |
YAML config file parsing | ≥ 6.0.0 |
streamlit |
Web application framework | ≥ 1.31.0 |
tqdm |
Progress bars during preprocessing | ≥ 4.65.0 |
pytest |
Running tests | ≥ 7.0.0 |
All dependencies are listed in requirements.txt.
git clone <repository-url>
cd ML_projectpython -m venv venv
# Activate it:
venv\Scripts\activate # Windows (PowerShell/CMD)
# source venv/bin/activate # Linux / macOSpip install -r requirements.txtThis enables from src.xxx import yyy imports from anywhere:
pip install -e .# Check TensorFlow
python -c "import tensorflow; print(tensorflow.__version__)"
# Check PyTorch
python -c "import torch; print(torch.__version__); print('CUDA:', torch.cuda.is_available())"
# Check Ultralytics
python -c "from ultralytics import YOLO; print('OK')"
# Check Streamlit
python -c "import streamlit; print(streamlit.__version__)"This project needs labelled image and/or video data. Each sample must belong to one of two classes:
| Class | Folder Name | Description | Examples |
|---|---|---|---|
| Accident | Accident/ |
Images or videos showing a road accident | Car crashes, motorcycle collisions, vehicle pile-ups |
| Non-Accident | Non_Accident/ |
Normal traffic scenes with no accident | Regular traffic flow, parked cars, empty roads |
| Pipeline | Accepted Formats | Notes |
|---|---|---|
| Image Classification | .jpg, .jpeg, .png, .bmp |
Single frame images |
| Video Classification | .mp4, .avi, .mov |
Short video clips (2-30 seconds recommended) |
| Severity Assessment | .jpg, .jpeg, .png |
For YOLO: annotated in YOLO format (see below) |
Labelling is done by folder structure — no separate annotation files needed for the image and video classifiers:
Simply place each image/video into the correct folder:
Accident/car_crash_001.jpg ← This IS an accident
Non_Accident/normal_traffic.jpg ← This is NOT an accident
For the severity model (YOLOv8), if using detection mode, you need YOLO-format annotation files:
# Each image gets a .txt file with the same name:
# image_001.jpg → image_001.txt
#
# Each line in the .txt file:
# <class_id> <x_center> <y_center> <width> <height>
#
# All values are normalised (0.0 – 1.0) relative to image dimensions
#
# Example (class 0 = Minor, class 1 = Moderate, class 2 = Severe):
0 0.45 0.32 0.12 0.08
2 0.71 0.55 0.25 0.30
The data must be split into three sets:
┌──────────────────────────────────────────────────────────┐
│ ALL YOUR DATA │
│ │
│ ┌────────────────────────────────────┐ 70% of data │
│ │ TRAINING SET │ Model learns │
│ │ │ from this │
│ └────────────────────────────────────┘ │
│ │
│ ┌──────────────────────┐ 20% of data │
│ │ VALIDATION SET │ Monitors learning during │
│ │ │ training (prevents overfit) │
│ └──────────────────────┘ │
│ │
│ ┌───────────┐ 10% of data │
│ │ TEST SET │ Final evaluation — model never sees │
│ │ │ this data during training │
│ └───────────┘ │
└──────────────────────────────────────────────────────────┘
| Split | Ratio | Purpose |
|---|---|---|
| Train | 70% | The model learns patterns from this data |
| Validation | 20% | Used during training to check performance and prevent overfitting |
| Test | 10% | Used ONLY after training to measure final accuracy — the model never sees this during training |
After splitting, your dataset must look like this:
your_dataset/
├── train/ # 70% of data
│ ├── Accident/
│ │ ├── crash_001.jpg
│ │ ├── crash_002.jpg
│ │ ├── collision_video_01.mp4 # (for video pipeline)
│ │ └── ...
│ └── Non_Accident/
│ ├── normal_001.jpg
│ ├── traffic_flow_01.mp4
│ └── ...
│
├── val/ # 20% of data
│ ├── Accident/
│ │ └── ...
│ └── Non_Accident/
│ └── ...
│
└── test/ # 10% of data
├── Accident/
│ └── ...
└── Non_Accident/
└── ...
Important: The folder must be named exactly
AccidentandNon_Accident. The system also auto-convertsNon Accident,Non-Accident, andnon-accidentvariants.
| Quality | Images per Class | Videos per Class |
|---|---|---|
| Minimum (proof of concept) | 200 | 50 |
| Good (decent accuracy) | 1,000 | 200 |
| Ideal (production-ready) | 5,000+ | 1,000+ |
Tip: Balanced classes (equal Accident and Non-Accident counts) give the best results.
If you have raw video datasets that need to be converted to frames:
Raw Videos (datasets/)
│
│ Step 1: Extract frames from each video (every 10th frame)
▼
python preprocessing/extract_frames.py \
--dataset-2 datasets/video-datasets/dataset-2 \
--dataset-3 datasets/video-datasets/dataset-3 \
--output processed-datasets \
--frame-interval 10 \
--image-size 224 224
│
│ Step 2: Split extracted frames into train/val/test
▼
python preprocessing/split_frames.py \
--source processed-datasets/all_data \
--target processed-datasets \
--train-ratio 0.7 \
--val-ratio 0.2
│
│ Step 3 (optional): Merge another dataset source
▼
python preprocessing/merge_datasets.py \
--source another-dataset \
--target processed-datasets
│
│ Step 4: Fix folder name inconsistencies
▼
python scripts/normalize_dataset.py --root processed-datasets
│
│ Step 5: Visualise & verify
▼
python preprocessing/load_and_visualize.py --dataset-path processed-datasets
The visualisation script shows:
- Total image count per class (bar chart)
- Split distribution (bar chart)
- Missing frame detection
- Random sample image display
python scripts/train_image.py \
--data-dir path/to/dataset \
--img-size 224 224 \
--batch-size 32 \
--epochs 10 \
--model-out models/image_model.h5What happens during training:
Epoch 1/10
┌─────────────────────────────────┐
│ 1. Load batch of 32 images │
│ 2. Resize to 224×224 │
│ 3. Rescale pixels to [-1, 1] │
│ 4. Pass through frozen MobileNet │
│ 5. Pass through Dense layers │
│ 6. Compute categorical cross- │
│ entropy loss │
│ 7. Backpropagate (only top │
│ layers — base is frozen) │
│ 8. Update weights with Adam │
└─────────────────────────────────┘
Train Loss: 0.45 | Train Acc: 0.82
Val Loss: 0.38 | Val Acc: 0.87
... repeat for all epochs ...
Saved: models/image_model.h5
| Parameter | Flag | Default | Description |
|---|---|---|---|
| Data directory | --data-dir |
Auto from config | Root with train/val/test subdirs |
| Image size | --img-size |
224 224 | Width and height in pixels |
| Batch size | --batch-size |
32 | Images per training step |
| Epochs | --epochs |
10 | Full passes over training data |
| Output path | --model-out |
models/image_model.h5 | Where to save trained weights |
python scripts/train_video.py \
--data-dir path/to/video-dataset \
--frame-count 16 \
--frame-size 112 112 \
--batch-size 4 \
--epochs 10 \
--lr 0.001 \
--model-out models/video_model.pthWhat happens during training:
Epoch 1/10
┌──────────────────────────────────┐
│ 1. Load batch of 4 videos │
│ 2. Sample 16 frames per video │
│ (evenly spaced) │
│ 3. Resize each frame to 112×112 │
│ 4. Normalise pixels to [0, 1] │
│ 5. Stack → tensor (4, 16, 112, │
│ 112, 3) │
│ 6. Permute → (4, 3, 16, 112, 112) │
│ 7. Pass through R3D-18 with 3D │
│ convolutions │
│ 8. Compute cross-entropy loss │
│ 9. Backpropagate through all │
│ layers │
│10. Update weights with Adam │
└──────────────────────────────────┘
Train Loss: 0.62 | Train Acc: 0.74
Val Acc: 0.78
... repeat for all epochs ...
Saved: models/video_model.pth
| Parameter | Flag | Default | Description |
|---|---|---|---|
| Data directory | --data-dir |
Auto from config | Root with train/val subdirs |
| Train subdir | --train-subdir |
train | Training split folder name |
| Val subdir | --val-subdir |
val | Validation split folder name |
| Frame count | --frame-count |
16 | Frames sampled per video |
| Frame size | --frame-size |
112 112 | Frame width and height |
| Batch size | --batch-size |
4 | Videos per training step |
| Epochs | --epochs |
10 | Full passes over training data |
| Learning rate | --lr |
0.001 | Adam learning rate |
| Output path | --model-out |
models/video_model.pth | Where to save trained weights |
python scripts/train_severity.py \
--data configs/severity.yaml \
--model yolov8n.pt \
--epochs 50 \
--imgsz 640This uses the Ultralytics YOLO training pipeline. You need a severity.yaml config pointing to your annotated severity dataset.
| Parameter | Flag | Default | Description |
|---|---|---|---|
| Data config | --data |
configs/severity.yaml | YOLO data.yaml with class names & paths |
| Base model | --model |
yolov8n.pt | Starting weights (yolov8n/s/m/l/x.pt) |
| Epochs | --epochs |
50 | Training epochs |
| Image size | --imgsz |
640 | Input resolution |
python scripts/eval_image.py --data-dir path/to/dataset --model models/image_model.h5Outputs:
- Test loss and accuracy
- Confusion matrix
- Classification report (precision, recall, F1-score per class)
- ROC-AUC score (if binary)
python scripts/eval_video.py \
--data-dir path/to/video-dataset \
--model models/video_model.pth \
--split testOutputs:
- Confusion matrix
- Classification report (precision, recall, F1-score)
python scripts/eval_severity.py \
--weights models/severity_model.pt \
--data configs/severity.yaml \
--split valOutputs:
- Standard YOLO metrics (mAP, precision, recall)
Predicted
Accident Non-Accident
┌───────────┬──────────────┐
Actual Acc. │ TP │ FN │
├───────────┼──────────────┤
Actual Non │ FP │ TN │
└───────────┴──────────────┘
Accuracy = (TP + TN) / Total
Precision = TP / (TP + FP) → "Of all predicted accidents, how many were real?"
Recall = TP / (TP + FN) → "Of all real accidents, how many did we catch?"
F1-Score = 2 × (Precision × Recall) / (Precision + Recall)
python scripts/infer_image.py --input path/to/image.jpg --model models/image_model.h5Output:
{'class_index': 0, 'score': 0.9523}
→ Class 0 = Accident, with 95.2% confidence
python scripts/infer_video.py \
--input path/to/video.mp4 \
--model models/video_model.pth \
--frame-count 16 \
--frame-size 112 112Output:
{'class_index': 1, 'score': 0.8741}
→ Class 1 = Non-Accident, with 87.4% confidence
The Streamlit app is a web interface that lets you upload files and get instant predictions without touching the command line.
streamlit run app/streamlit_app.pyThe app opens in your browser at http://localhost:8501.
┌──────────────────────────────────────────────────────────────┐
│ STREAMLIT APP │
│ │
│ Sidebar Main Area │
│ ┌──────────────┐ ┌──────────────────────────────┐ │
│ │ Select Mode: │ │ │ │
│ │ │ │ [Upload area] │ │
│ │ ● Image Det. │ ──► │ │ │
│ │ ○ Video Det. │ │ ┌──────────┐ ┌──────────┐ │ │
│ │ ○ Severity │ │ │ Image │ │ Result: │ │ │
│ │ ○ About │ │ │ Preview │ │ Accident │ │ │
│ │ │ │ │ │ │ 95.2% │ │ │
│ └──────────────┘ │ └──────────┘ └──────────┘ │ │
│ └──────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
| Mode | What It Does | Model Used |
|---|---|---|
| Image Detection | Upload .jpg/.png → Accident or Non-Accident + confidence |
MobileNetV2 (TF) |
| Video Detection | Upload .mp4/.avi → Shows sampled frames + prediction |
R3D-18 (PyTorch) |
| Severity Assessment | Upload accident image → Severity class or detection boxes | YOLOv8 |
| About | Project description, model details, architecture info | — |
| File | Purpose |
|---|---|
app/streamlit_app.py |
Main entry point — page layout, file upload, calls services |
app/components.py |
Reusable UI components: render_image_result(), render_video_result(), render_severity_result(), confidence_gauge() |
app/config.py |
App settings: model paths, label maps ({0: "Accident", 1: "Non-Accident"}), colours, supported file types |
Here is the exact flow when a user uploads an image in the Streamlit app:
User uploads photo.jpg
│
▼
app/streamlit_app.py
1. Saves upload to a temp file
2. Calls: predict_image(temp_path)
│
▼
src/services/image_service.py
1. Loads config paths (src/common/config.py)
2. Resolves model path → models/image_model.h5
3. Loads the Keras model: tf.keras.models.load_model(...)
4. Opens the image with PIL, resizes to 224×224
5. Normalises pixels to [0, 1]
6. Runs model.predict(image_array)
7. Returns: {"class_index": 0, "score": 0.95}
│
▼
app/components.py → render_image_result()
1. Maps class_index 0 → "Accident" (from app/config.py)
2. Picks colour: red for Accident, green for Non-Accident
3. Displays image alongside prediction with confidence metric
│
▼
User sees the result in the browser
The video and severity flows are analogous — the services layer abstracts all model-loading complexity, while the app layer handles only UI rendering.
Controls the YOLO object detection pipeline:
model:
name: yolov8x.pt # YOLOv8 variant (n/s/m/l/x)
confidence: 0.25 # Minimum detection confidence
iou: 0.45 # NMS (Non-Max Suppression) IoU threshold
inference:
image_size: [640, 640] # Input resolution
device: cuda # cuda or cpu
classes: # COCO class indices for vehicles
- 2 # car
- 5 # bus
- 7 # truck
- 3 # motorcycle
- 1 # bicycle
tracking:
max_age: 30 # Frames to keep tracking a lost object
min_hits: 3 # Min detections to start tracking
iou_threshold: 0.3 # IOU threshold for track associationControls accident detection heuristics (when using real-time video analysis with object tracking):
collision_detection:
min_overlap_area: 0.3 # Bounding box overlap to flag collision
sudden_overlap_threshold: 0.5 # Sudden overlap jump threshold
max_normal_speed: 50 # Normal speed in pixels/frame
sudden_speed_drop: 0.7 # Speed drop ratio to flag accident
angle_threshold: 45 # Opposing direction angle (degrees)
min_stationary_frames: 15 # Frames to flag vehicle as stopped
analysis_window: 30 # Frames to analyse for patterns
alert_system:
min_confidence: 0.8 # Minimum confidence to fire alert
cooldown_period: 300 # Min frames between alertsRun the test suite:
pytest tests/ -v| Test File | What It Tests |
|---|---|
tests/test_services.py |
Creates dummy images/videos, runs predict_image() and predict_video(), checks output format |
tests/test_severity.py |
Tests severity service with a dummy image (skips if weights not present) |
- Real-time video stream analysis (webcam / RTSP / CCTV feeds)
- Object tracking with DeepSORT/ByteTrack for trajectory-based collision detection
- Multi-camera fusion for wider coverage
- Mobile application for generating real-time alerts
- Integration with emergency response API systems
- Enhanced severity grading with more fine-grained categories
- Dashboard for historical accident analytics
This project is licensed under the MIT License — see MIT License.md for details.