A hard-hat and vest detector tested on real site photos, not just its test set.

Merged three public datasets into 10,864 images, trained YOLO11 and served it as an app that flags missing hard hats and vests. An independent real-world benchmark exposed a model that missed real vests; two fixes raised real-world vest recall from 0% to 50.5%.

The demo runs on a free server that may take a minute to wake.

Sector
Construction safety
Method
Computer vision
When
Mar – Oct 2026
Context
MSc Deep Learning coursework
Role
Solo: data merging, training, evaluation and deployment

Key figures

  • 50.5% real-world vest recall, up from 0%
  • 80% precision on the same real photos
  • 93.2% test mAP50 of the earlier baseline model
The PPE Compliance Detector app: an upload area for a site photo or clip, a detection-sensitivity slider and a results panel.

How it works

Built on one 8 GB GPU
  1. Merge : Three public datasets, five shared classes
  2. Clean : Duplicates and broken files out: 10,864 images
  3. Train : YOLO11s at 1,280 px, rare vest images oversampled
  4. Benchmark : 214 real vests from a separate photo source
  5. Fix : A colour bug, then labels for the missing classes
  6. Export : A 38 MB ONNX model for CPU inference
Runs for each photo or clip
  1. Upload : A photo, or a clip up to 15 seconds
  2. Detect : YOLO11s on CPU, at the chosen sensitivity
  3. Flag : Missing hard hats and vests marked as violations
  4. Report : Boxed image or clip, a summary and a JSON report

Architecture and results

  • A model runs here
  • Deterministic code
  • An outside source
  • A stored artefact
  • A boundary the design refuses
  1. Trained on merged data, tested on photos it never saw

    Three public datasets were merged into one with five shared classes, and YOLO11s was trained on an 8 GB laptop GPU. An independent benchmark of 84 SH17 photos with 214 hand-labelled vests exposed the failure, and each fix went back into training. The deployed model is a 38 MB ONNX file on a free CPU server, behind a React front end.

    Two rows. Training: three datasets, merge and clean, YOLO11s, the SH17 benchmark and two fixes looping back into training. Running: a photo or clip, YOLO11s on CPU, flags and a report. Open full size: Trained on merged data, tested on photos it never saw
  2. Real-world vest recall, round by round

    Recall on the benchmark's 214 vests at the app's default threshold. The first model scored 93.2% mAP50 on its own test split and found none of the real vests. Round 2 reached 24.8%, fully cross-domain; round 3 added more varied vest images and reached 50.5%, at 80% precision.

    Vests found in 84 real site photos (214 vests)

    Real-world vest recall, round by round
    Item Recall
    First deployed model 0%
    Round 2 24.8%
    Round 3 50.5%

Numbers from the project's public repository (README and results).

The question

On a construction site, a missing hard hat or vest is a safety violation. Can a detector spot them in ordinary photos and short clips, well enough to help someone screening a site?

One dataset from three

  • Three public datasets, of 2,801, 7,581 and 784 images, came in three annotation formats with different class lists. All were converted to five shared classes.
  • Exact and near-duplicate images were removed by hashing, and broken images and boxes filtered out, leaving 10,864 images with 144,986 boxes, split 80/10/10 within each source.
  • The classes are very uneven: heads without hard hats are 78.1% of all boxes, vests and missing vests about 5% together. Vest images were oversampled with fog, rain, noise and blur.

A test score that hid a failure

YOLO11s, trained at 1,280 px on an 8 GB laptop GPU, reached 93.2% mAP50 on the test split, and 92.0% for vests. Then it found almost no vests in real photographs. The test split shared its sources, lighting and vest styles with training, so it measured whether the model knew those vests, not vests in general.

An independent benchmark settled it: 84 photos from a separate industrial-photo dataset, SH17, with 214 vests labelled by people and no image shared with training. The deployed model found none of them.

Two fixes

  1. A colour bug. The app handed images to the model in the wrong channel order, which turned orange vests blue before the model saw them.
  2. Missing labels taught the model to ignore things. Adding a vest-only dataset cut hard-hat accuracy by 2.6 points: its images label only vests, so every unlabelled hard hat and worker in them trained as background. Labelling the missing classes with the current model before merging restored hard-hat accuracy and kept the vest gains.

Recall on the benchmark rose from 0% to 24.8%, then to 50.5% after adding more varied vest images, at 80% precision. That model is the one deployed.

A deliberate trade

The last round gained 25.7 points of recall for 8 points of precision. In compliance screening a missed violation costs more than a false alarm, so the trade is chosen, not accidental. The original test split still guards the other classes against regressions.

Running it

The model runs as a 38 MB ONNX file on a free CPU server, about 2 to 4 seconds a photo. Clips of up to 15 seconds are checked twice a second, with boxes drawn on every frame so playback stays smooth, and come back as video that plays in any browser.

Limits

  • It still misses about half of real vests: from unusable to useful, not solved.
  • The benchmark shares a source with some of the last round’s training images, with no image in common, so part of that gain is adaptation to the source. The 24.8% before it was fully cross-domain.
  • People without vests, the violation itself, are measured only on the original test split: no independent dataset labels them.
  • The free CPU server limits clips to 15 seconds.

Built with

  • YOLO11
  • Albumentations
  • ONNX Runtime
  • Gradio
  • React
  • Vercel
Next project Agentic menu development