Counting parts with a camera, not a model
Someone needed loose components counted from a photo. I reached for a neural network first, then put it down and used plain OpenCV, and it worked better.
The ask was simple. Tip a pile of small parts onto a tray, photograph it with a phone, get a count back and have that count land in the stock record. Nobody wants to count 340 identical washers by hand twice a week.
My first instinct was the fashionable one: this is object detection, so I need a model, which means I need a labelled dataset, which means somebody has to draw a few thousand boxes around washers. I got about an hour into that thought before I stopped.
Why the model was the wrong tool
Look at the actual problem. The parts are identical. The tray is a known colour. The lighting is whatever the warehouse has, but it is the same warehouse every time. There is one class of object and it does not vary.
A neural network is for when you cannot describe what you are looking for. Here I can describe it precisely: dark blobs of a fairly consistent size on a light background. That is a threshold and a contour finder, which is about fifteen lines of OpenCV and runs in under a second on a machine with no GPU.
So the pipeline ended up being conventional and boring:
- Convert to greyscale and blur slightly, so the surface texture of the tray stops registering as detail.
- Adaptive threshold rather than a fixed one, because a phone photo is never lit evenly and one corner is always darker.
- Morphological open and close to knock out speckle and fill the small holes inside parts.
- Find contours, then filter them by area to drop dust and reflections.
That gets most of the way there. The rest of the work was in the two places it fails.
The two hard cases
Parts that touch. Two washers resting against each other are one contour, so the count is one short. The standard fix is a watershed transform: compute a distance map from the blob edges, treat the local peaks as separate seeds, and let the regions grow until they meet. It splits touching pairs reliably. It also occasionally splits one oddly shaped part into two, which is why the area filter matters, and why the final answer is checked by a human.
Parts that overlap. One part sitting on top of another is genuinely ambiguous from a single photo. No amount of preprocessing fixes it, because the information is not in the image. So the honest answer was to not solve it. The tool tells the operator to spread the parts out, and the instruction on screen says exactly that.
The part that mattered more than the algorithm
Every tuning constant is a named value at the top of the file with a comment explaining what it does and which direction to move it.
This sounds like a small thing. It is the reason the tool is still used. When a new part
type arrives that is smaller than anything before, somebody who is not me can open the
file, read MIN_AREA and the sentence next to it, and change the number. If those had been
literals buried three functions deep, every new part would have been a support request.
The lesson I keep relearning
I wanted this to be a machine learning project because machine learning projects are more interesting to talk about. It did not need to be one. It needed a threshold, a contour finder, and honesty about the case that cannot be solved from one photo.
The test I use now, before reaching for a model: can I write down, in one plain sentence, what distinguishes the thing I am looking for? If yes, I should probably just write that sentence as code and see how far it gets. Most of the time it gets all the way.
WRITTEN BY
Vishwas Jha
Software Engineer · New Delhi, India
Get the next one in your inbox: