Open Sourcing Our Real-Time PPE Detection Mobile App

Janani G

4 min read

By Spritle Software Engineering Team

Workplace safety isn’t negotiable. But manual safety compliance monitoring is slow, inconsistent, and doesn’t scale. We built a real-time Personal Protective Equipment (PPE) detection app that runs entirely on your smartphone — no cloud, no expensive hardware, no delays.

The Problem We’re Solving

Every year, thousands of workplace accidents happen because workers aren’t wearing the right safety gear. Construction sites, manufacturing floors, and industrial facilities need instant feedback — not end-of-day audit reports.

Traditional solutions require:

  • Fixed CCTV cameras with expensive cloud processing
  • Internet connectivity at remote job sites
  • Dedicated hardware or servers
  • Minutes of delay before an alert fires

We wanted to prove that sophisticated computer vision can run entirely on a  Android phone, giving instant feedback the moment a safety violation occurs.

Why We’re Open Sourcing This

When we started this project, we did what every engineer does — searched for an open-source implementation that already existed.

We found plenty of PPE detection projects on GitHub. YOLO models, Python scripts, Roboflow datasets, Flask dashboards. The computer vision side was well covered. But when we looked for a complete, ready-to-run Android app— something you could clone, build, and point a phone camera at a worker — it simply didn’t exist.


Every project we found had the same problem. Built for Raspberry Pi. Runs on a laptop with OpenCV. Needs a server in the background. Depends on cloud APIs. Great demos, but none of it worked offline on a phone in someone’s pocket.
Nobody had taken a PPE model all the way to a native Android app with real-time on-device inference. The last mile was always missing.
So we built it ourselves — trained the model, exported it to TFLite, wired it into a CameraX pipeline, and got it running at 30 FPS on a mid-range Android phone with no internet required.


And since we couldn’t find it when we needed it, we’re putting it out there so the next team doesn’t have to go through the same search.

What It Detects

The app detects 5 key PPE classes in real-time:

helmet       — worker is wearing a hard hat

⚠️  no-helmet   — worker is NOT wearing a hard hat  ← most critical

vest         — worker is wearing a safety vest

⚠️  no-vest     — worker is NOT wearing a safety vest

👤 person       — any person in frame

The no-helmet and no-vest classes are the most important — they trigger the safety alert.

The Full Tech Stack

How It All Fits Together

Deep Dive: Each Component

1. The Dataset — Roboflow Construction Safety

We used the construction-safety-gsnvb dataset from Roboflow-100 — a curated, open-source collection of real construction site images.

Dataset: construction-safety-gsnvb (Roboflow-100)

Images:  2,424 real construction site photos

Split:   Train / Validation / Test

Classes: helmet, no-helmet, vest, no-vest, person

License: CC BY 4.0 (free to use commercially)

Why this dataset? Because it has real-world construction site images with workers in different lighting conditions, angles, and distances — not studio photos.

2. The Model — YOLOv8s

We chose YOLOv8s (small variant) from Ultralytics after evaluating three options:

We went with yolov8s — better accuracy than nano, still fast enough for real-time mobile inference.

Training configuration:

//code
from ultralytics import YOLO

model = YOLO('yolov8s.pt')   # pretrained on COCO (transfer learning)

results = model.train(
    data='data.yaml',
    epochs=100,
    imgsz=640,
    device=0,          # GPU
    batch=16,
    mosaic=1.0,        # augmentation
    mixup=0.15,
    fliplr=0.5,
    degrees=10.0,
)

Why transfer learning? Instead of training from scratch, we started from yolov8s.pt — a model already trained on 80 COCO classes. This means the model already understands shapes, edges, and human bodies. We just fine-tuned it to recognize PPE specifically. This cut training time from days to under 30 minutes on a free Colab GPU.

3. Model Training — Google Colab (Free)

The entire training pipeline ran on Google Colab’s free T4 GPU — no paid compute needed.

Training environment:

  Platform:   Google Colab (free tier)

  GPU:        NVIDIA T4 (15GB VRAM)

  Runtime:    ~25-30 minutes for 100 epochs

  Framework:  Ultralytics 8.4.33

  Python:     3.12

Training progression (loss decreasing = model learning):

Epoch  1/100  →  loss: 3.17  mAP50: 0.14

Epoch 10/100  →  loss: 1.93  mAP50: 0.36

Epoch 50/100  →  loss: 1.12  mAP50: 0.71

Epoch 100/100 →  loss: 0.87  mAP50: 0.92  ✅

4. Export Pipeline — PyTorch to TFLite

After training, the model exists as a .pt (PyTorch) file. Android can’t run that directly. We export it to TensorFlow Liteformat:

from ultralytics import YOLO
model = YOLO('runs/detect/train/weights/best.pt')
model.export(format='tflite')
# Output: runs/detect/train/weights/best_saved_model/best_float32.tflite

TFLite gave us:

  • ~6MB model instead of 22MB PyTorch weights
  • Runs entirely on-device — no internet needed
  • Hardware acceleration via GPU delegate on compatible phones
  • 40-60ms inference on mid-range Android devices

5. Android App Architecture

The Android app is written in Kotlin, using CameraX for camera access and TFLite Interpreter for running the model.

android_app/
├── app/
│   └── src/main/
│       ├── assets/
│       │   ├── model.tflite     ← your trained PPE model
│       │   └── labels.txt       ← class names
│       └── java/com/ppeapp/yolov8tflite/
│           ├── MainActivity.kt  ← camera + UI
│           ├── Detector.kt      ← TFLite inference
│           ├── BoundingBox.kt   ← box data class
│           └── Constants.kt     ← model/label paths

The inference loop:

Why CameraX over Camera2?

Camera2:

  Powerful but complex. 1000+ lines of boilerplate.

           Device-specific bugs. Manual lifecycle management.

CameraX:  

Lifecycle-aware. Works the same across all Android devices.

           Built-in frame analysis. 30+ FPS out of the box.

We chose CameraX. Zero device-specific camera bugs after launch.

6. The labels.txt File

This tiny file maps class IDs to human-readable names. The order must exactly match your training data.yaml:

helmet

no-helmet

no-vest

person

vest

If this order is wrong, the model will show the right box but the wrong label — like drawing a box around a helmet and calling it “person.”

Model Performance

Inference speed:  40-60ms per frame (mid-range Android)

FPS:              15-30 FPS depending on device

Model size:       ~6MB

Min Android:      API 24 (Android 7.0+)

Why is no-helmet accuracy lower? Because “no helmet” is just a human head — it looks like any person. The model has to learn the absence of a hard hat rather than the presence of one. This is a fundamentally harder computer vision problem than detecting a distinctive yellow helmet.

What We Learned

1. Small datasets have accuracy ceilings. With 2,424 images, we hit a ceiling around mAP50 ~0.92 overall. The individual class scores for no-helmet and no-vest plateau. More data is the only real fix.

2. Transfer learning is a superpower. Starting from COCO-pretrained weights cut our training time from hours to 25 minutes. The model already knew what humans look like — we just taught it what PPE looks like.

3. TFLite export is straightforward. One line of code converts a YOLOv8 model to TFLite. Ultralytics handles all the graph optimization and format conversion.

4. CameraX is production-ready. After switching from Camera2, we had zero device-specific bugs. Highly recommend for any Android camera work.

5. On-device beats cloud for safety. Zero latency. Works in basements, tunnels, remote sites with no signal. Privacy-preserving — footage never leaves the device.

Getting Started

Run the App
# Clone the repo
git clone https://github.com/AarohiSingla/Object-Detection-Android-App.git

# Add your model files to:
# android_app/android_app/app/src/main/assets/
#   ├── model.tflite
#   └── labels.txt

# Open android_app/android_app in Android Studio
# Connect Android phone (USB debugging on)
# Click Run ▶
Train Your Own Model
# Step 1 — Install
pip install ultralytics roboflow

# Step 2 — Download PPE dataset
from roboflow import Roboflow
rf = Roboflow(api_key="YOUR_KEY")
project = rf.workspace("roboflow-100").project("construction-safety-gsnvb")
dataset = project.version(1).download("yolov8")

# Step 3 — Train
from ultralytics import YOLO
model = YOLO('yolov8s.pt')
model.train(data='data.yaml', epochs=100, imgsz=640, device=0)

# Step 4 — Export to TFLite
model = YOLO('runs/detect/train/weights/best.pt')
model.export(format='tflite')

License & Credits

Released under MIT License — use it commercially, modify it, ship it.

Built by the engineering team at Spritle Software.

Thanks to the open-source communities behind:

Repository: github.com/spritle-software/ppe-detection-app

Let’s make workplaces safer, one frame at a time. 🦺

Related posts:

Leave a Reply

Your email address will not be published. Required fields are marked *