Barcode image segmentation

Written by luca_picci | Published 2017/04/22
Tech Story Tags: barcode | opencv | image-processing | python | image-segmentation

TLDRvia the TL;DR App

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

Code and technique

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

Conclusions

The presented technique is very simple and effective, however it presents some annoying drawbacks:

  • it is very sensitive on barcode skewness; it works well until about 45 degrees, then you have to permorm a second pass, modifying kernels direction;
  • it can find barcodes only inside a fixed range of dimensions;
  • despite the filtering imposed on rectangles areas, it is not unusual that some non barcode is not cleaned out;

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 :).

Material

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!


Published by HackerNoon on 2017/04/22