Monday, November 16, 2015

Easily count tiny items (200 PCB vias here)

One way to check the number of items I just bought on ebay.

How can I check that there are really 200 vias in these bags?
I bought packs of 200 tiny rivets for vias. Since I am making my PCB on a mill and I often only use only single-sided PCB copper clads, it gets tricky to solder the headers from below. This is very annoying for headers and Arduino shields for example, as they protrude from below also...

I was somehow able to do it but a proper way is to insert so called PCB "through hole rivets" first. This way, the headers can be conveniently soldered from the top, once they are themselves inserted in the rivets.

But such rivets are not cheap (I got 200 of them for $20 on ebay!). I felt I had been cheated on when seeing the small volume it represented. Really 200?


Inserting and using tiny rivets for vias on a home made PCB
(source: Mega-UK -- quite an expensive tool, but it certainly soon becomes handy!)


So I gave it some easy image processing to make sure!

Here is a trivial python script that does it all:

''
from scipy.misc import imread
from scipy.ndimage import label
from scipy import ones

img = imread("rivets.png", True)
lbl, n = label(img, ones((3,3)))  # 8-connectivity
print("detected object count = " + str(n))
''

Converting the image in black and white blobs to count the items

Now, the image must first be prepared with all rivets in pure white and the background in black. Here is how I did.

- pour the tiny rivets on a paper towel (so that they do not roll everywhere)
- separate them somehow, we want to distinguish each of them when possible
- take a picture with a flash right from above, with hard light
- import in gimp
- apply some heavy adaptive gaussian blur (i.e. that blurs homogeneous regions, but keeps details): ''Filter > Blur > Selective Gaussian Blur''. I used a large kernel of 40 (slow!). The idea is to get rid of the paper towel texture, but keep the rivet details, as can be seen below.
Heavy selective gaussian blur to get rid of the background texture.

Now, use the ''Select > By color'' option, and tune the threshold so as to select almost all of the background. There is no harm when it leaves small dots here and there as we will see, but you want to have only the rivets unselected. At worst, you may have to reduce the threshold and click/add multiple sub-selections if the lighting was not homogeneous enough in the first place (this is why a close flash helps a lot: white gets over exposed and the work is almost done directly in the original image)

Usual and easy topolgy: shrink/grow selection

If you have trouble getting a "neat" selection, you can ''Select > Shrink...'' the selection by some amount, follwed  by ''Select > Grow...'' with the same amount (or use the "feather" option). This operation "rounds" the selection contour, which in turn helps getting rid of "dirt" (eg. unselected highlights).

Once properly selected, and when your rivets are ~25 pixel wide for example, you can grow the selection by 10 pixels. This will obviously "eat" many of the rivet pixels, which in turn will "detach" those which are close to each other: only the inner 5 pixel will remain unselected. No real need to shrink the selection back (e.g. by no more than 8 pixels), but it makes prettier pictures ;)

You can also use the ''Color > Threshold'', but the background needs to be really homogeneous. Anyhow, the goal is try and get one and only one blob selected per rivet, and all noise removed.

Black was selected: growing the selection "eats" the rivet
outline, and detaches the ones that were too close to each other.
If the selection is then shrunk, and filled with black again,then the rivet images are restored, and the bridges are gone!
I usually "fill" the selection with black by using the "delete" key, after toggling the front/back color appropriately (use the flip/flow arrow near the overlapped black/white color selection). Then use ''Select > Invert'', toggle the two colors and delete again the selection. You should get a black and white image as above, that you can now export as a PNG image for the script.

Here are my results, running the script in the header of this post:

''
[17:26][jeremie@moab:/volatile] python counting_items.py
detected object count = 216
''

So in my case it proved that the seller did put 200+ rivets in the bag. Hard to believe when seeing it, but he is more than honest. I guess he uses a scale for jewelry to weight the amount :)