Surface defect inspection with a line-scan camera
Private source
The anomaly detector learns only from good samples and needs no defect images. Each image returns OK or NOK, an anomaly map, a mask and boxes around suspect regions.
Problem
Surface defects are rare and come in endless forms, so collecting enough defect images to train on is hard. The line needs a decision for every image within about 50 ms.
Approach
- PatchCore on MobileNetV3-Large, with features from blocks.4 and blocks.6, running in FP16.
- Each fixed 1024 × 1792 image is cut into 448 px tiles with 0.20 overlap. Every tile looks up nearest neighbours in a memory bank built from 10 good images (coreset 0.10).
- Tile scores are blended with a Hann window, Gaussian-smoothed, normalized against good-image statistics and restricted to the ROI. The threshold is calibrated on 50 separate good images.
- An operations dashboard built with aiohttp and React 19 (TypeScript, Vite, shadcn/ui) keeps history in SQLite and grabs frames from a Basler camera via pypylon. A Train & Setup tab lets operators create a product, upload good images, train and activate it from the browser.
Results
Results on a 133-image test set (26 defective, 107 good). The README marks the latency figures as historical results.
- Recall
- 24/26 (92.3%)
- 133 test images: 26 defective, 107 good
- False alarms
- 3/107 (2.8%)
- same test set
- P50 latency
- 43 ms
- RTX A4000, FP16, batch 15, 3,990 consecutive frames; P95 is 44 ms
- On CPU
- ≈ 683 ms
- OpenVINO FP32, 2 × Xeon Gold 6138
Deployment lessons
- 1.An encoder-triggered line-scan camera only produces frames while the table turns. No frames while the motor is stopped is correct behaviour, not a network fault.
- 2.A camera cable routed through a PLC port runs at only 100 Mbps. Around 64 Mbit/s was fine; pushing the table speed toward 98 Mbit/s started dropping frames.
How it was evaluated
Few-shot experiments under a budget of 10 or 15 good images were run across 8 seeds with nested leave-one-out validation, giving 160 operating points.
Conclusions are recorded even when a new configuration does not help, for example: no configuration yet improves recall and the false-alarm rate at the same time. Keeping negative results stops the next attempt from repeating a dead end.
Stack
- PyTorch
- PatchCore
- MobileNetV3
- FP16
- OpenVINO
- aiohttp
- React 19
- TypeScript
- SQLite
- pypylon