Questo articolo è dispobinile anche in italiano
In this article i’m going to explain a simple technique for barcode segmentation from images. For the example code, i’m going to adopt Python 2.7 in its Anaconda incarnation and OpenCV as image processing library. I choose Python as it is a very practical choice in order to quickly write examples, however the technique can be adopted in any language of your choice. Anaconda is an interesting Python distribution that bundles a series of usefull tools for scientific programming. It’s like a matlab for “poor people” :).
Segmentation is inteded as the process of identifying the position of one or more objects inside an image.
The technique that i’m going to present is very simple; it makes use of morphological operators dilation and erosion and combinations as opening, closing and black-hat operators. The exploited barcode feature is than the close distance between barcode bars.
Once Anaconda is installed, let’s move to OpenCv installation with the following command:
conda install -c https://conda.anaconda.org/menpo opencv
from Anaconda prompt.
And now let’s launch the Spyder IDE from the Anaconda launcher
Anaconda launcher
Once you have Spyder running, i suggest to verify that opencv installation have succeded: from the bottom right IPython console, let’s test with
import cv2
I have created a startup github repository; you can clone it with:
git clone --branch step1 https://github.com/lucapiccinelli/BarcodesTutorial.git
with this, you will download the test image and the starting code that reads and shows the image
Test image
<a href="https://medium.com/media/b82f6d52bbc82549de41c6b1cb174032/href">https://medium.com/media/b82f6d52bbc82549de41c6b1cb174032/href</a>
From now on, it will start the real processing. At first we are going to binarize the image, possibly enhancing the more interesting features. With blackhat operator we can enhance the darkest image elements.
Now we can safely binarize the image with a simple global threshold: blackhat operator let us use a very low threshold value, without giving to much emphasis to the noise.
<a href="https://medium.com/media/ba7715752b4ee54c261d01eb74ebb389/href">https://medium.com/media/ba7715752b4ee54c261d01eb74ebb389/href</a>
When applying blackhat, we use a kernel that gives more importance to vertical image elements. The kernel has a fixed size, so the image is scaled achieving also performance improvement (and favoring some kind of input normalization).
blackhat + thresholding
It follows the adoption of the others morphological operators, sequentially combining them in order to obtain connected components in barcode positions.
<a href="https://medium.com/media/9f58d094797492ab9111cae59e87fe8d/href">https://medium.com/media/9f58d094797492ab9111cae59e87fe8d/href</a>
This combination of dilation and closing works very well with the test image, however it could happen that it doesn’t achieve the same effectiveness on other images; no problem, you can try to variate the parameters and combination of operators until you are satisfied of the results.
dilation + closing
Last preprocessing step is to apply an opening operator with a very big kernel, in order to remove the elements that are to little to fit a barcode shape.
<a href="https://medium.com/media/bfd88918cfc1c7238da242860ad2a693/href">https://medium.com/media/bfd88918cfc1c7238da242860ad2a693/href</a>
And here you are the final result
opening with a 35x21 kernel
Now we can run the connected components detection algorithm and retrieve barcodes rectangles, with coordinates and dimensions. As you can see in the previous image, some noise has not been filtered from the last morphological step; however in this case it is quite simple to filter them out, thresholding on rectangle area value.
<a href="https://medium.com/media/1052b42f7e8407851bdd1ea2b1b07464/href">https://medium.com/media/1052b42f7e8407851bdd1ea2b1b07464/href</a>
Finally, in the above code i use extracted rectangles to draw them overlayed on the original image.
Risultato finale con i codici a barre evidenziati da riquadri verdi
The presented technique is very simple and effective, however it presents some annoying drawbacks:
It could be that the first and the second are not real problems, depending on application context, however the last one is quite more an annoying problem, as you can spend very much cpu time trying to decode something that is not a barcode.
A good solution is to instruct an artificial neural network (or some other classifier that you like) on barcode features (image gradient, fourier transform) and filter out the noise in a second moment. Maybe the next article will be on this topic :).
Here it follows the complete example code.
<a href="https://medium.com/media/5f5291562986c54e4c14557abe80b0f1/href">https://medium.com/media/5f5291562986c54e4c14557abe80b0f1/href</a>
Here it is the github repository. In the “img” directory i put all the images of the intermediate steps.
That’s all folks. I hope to have succeeded in the explanation of the technique: if not, please let me know.
Questions, reviews, comments or any kind of feedback will be very appreciated.
Thank you for reading :).
Bye!