My phone replaced a brass plug

An iOS engineer's journey from learning to hunt for the perfect venison steak to building a sophisticated computer vision app that automates shooting target scoring. By combining 2012-era OpenCV techniques with modern YOLOv8 models, the author replaced a tedious manual process with a high-precision AI solution.
My Phone Replaced a Brass Plug
I wanted to cook venison from scratch, which meant learning to shoot, which meant keeping track of my progress, which meant porting a 2012 OpenCV paper and training a state-of-the-art computer vision model, which meant the dinner took a bit longer than expected.
For months, I spent my Wednesday evenings in a tin tunnel just outside Edinburgh, wearing a ridiculously looking (and equally uncomfortable) jacket. I'd lie on the floor and count breaths, then walk down the range, ducking under ceiling beams. The floor says DUCK in white paint every five metres, the beams have posters saying "DUCK" as well, but occasionally I still hit my head, too busy checking the scoring cards.
If you're unlucky, a shot lands near a ring line and you need help. You walk up to a tray of Greggs sausage rolls - we're in the North, and so are our sponsors - find a wooden box which holds brass plugs in every size, choose the right one, carefully push it into the hole (ideally only once, to avoid tearing), and where it sits is your score.
The shooting part is fun. The score-counting-head-hitting-plug-pushing ritual had to end.
Negative space
I am an iOS engineer, so I started with vanilla iOS: Apple's Vision framework has ready-to-use detectors, but it kept tagging random parts of the image as bullet holes - from the dot in the target's centre to pieces of one of the scoring rings.
A bullet hole is a negative space. Object detectors are trained on the thing that should be there, so it's not very straightforward how to use them for finding something that was there before and then got removed.
A better approach would be to treat the target as an object with known geometry: find the ring structure first, then look for holes inside it.
Porting and Machine Learning
I found a 2012 paper by Rudzinski and Luckner promising 99% detection. I reproduced it step-by-step: erase ring lines, flood-fill to find hole shapes, run a Prewitt edge detector, and fit circles with a Hough transform. Since Vision doesn't have Prewitt, I brought in OpenCV. This got me to about 80% accuracy, but struggled with overlapping shots.
To bridge the gap, I turned to a 2023 paper using YOLOv8. I merged the two approaches: OpenCV handles the structural geometry (bulls, ellipses, rings, perspective transform), while YOLOv8 handles hole localisation. I fine-tuned the model on my own dataset and used coremltools to export it to CoreML, resulting in a 22.4 MB package.
Scoring and Mapping
With both pieces wired up, the final challenge was coordinate spaces. Vision returns bounding boxes with the origin at the bottom-left, but UIKit has the origin at the top-left. Once the coordinates and perspective transformations were aligned, the system finally provided the automated, high-precision scoring I needed.
Source: Hacker News

















