Tuesday, September 22, 2015

Scanning barcodes, using Raspberry Pi


My objective for this proof of concept project was to use a regular webcam to scan for barcodes, parse them and transmit the same via a REST service, using Raspberry Pi as the hardware platform.

I believe a lot of people have already "been there, done that", but somehow I found no single source of information to help me through all the obstacles I came across while trying to scan barcode using Raspberry Pi. So here is my version of how I went about it.


Ingredients

  1. I used the Raspberry Pi B+ described here
  2. I used a Logitech webcam for better scan quality, and automatic focus
  3. Logitech wireless keyboard for ease of coding as listed here
  4. I used power source via USB port
  5. I did NOT use a commercial barcode scanner, though that I had kept as a Plan B, if the code would not have worked via the webcam. Using that is actually very trivial, because once connected via USB, it acts as a regular keyboard. So any barcode it scans, Raspberry should ideally see it as keystrokes containing the barcode data. Anyway, I cannot guarantee that because I did not need to go to this path.
  6. Portable keyboard and optionally mouse for interacting with the Raspberry

Bake the cake time!


I spent almost till midnight with the raspberry trying to understand from scratch how it works, and how it reacts to Python as the base programming language. So I was able to hookup my Logitech wireless keyboard+mouse to the board using the Logitech Unifying dongle. I did not expect the tiny Raspberry to work with Unifying, but it did work instantly post a reboot! Now I had keyboard and mouse access to my Raspberry.

Next, I connected ethernet and saw Raspberry connect to the Internet. I realized later that this was a critical step, as I would soon be downloading a lot of libraries/packages for this project.

I tried to write a hello world Python script and all Bash scripts require the code to begin with #, but I realized that the keyboard was not allowing me to type '#' !! Bummer. I had to dig into Raspberry preferences, and select keyboard style 101, for English US. Post a reboot, my gained the power to type '#' and was happy. While in the settings, I also set the clock and changed the timezone to my preferred CST timezone.

Next I connected the USB external webcam. This was used so I could start off with better quality optics, and the capability of auto focus. To begin using the webcam, I had to make my Raspberry webcam aware. 

After a lot of digging I realized that I needed to install a number of libraries to make Raspberry ready for action. I also had to install 'pillow', which works as an alternative for PIL image manipulation library. I also installed httpplib2 for my other part of this project, which is supposed to make REST service requests.

I installed the libraries in the below order:

sudo apt-get install python-dev
sudo apt-get install python-pip
sudo pip install pillow
sudo apt-get install python-httplib2



Next,  I issued the below command to install USB webcam package. This allows for leveraging an external USB based webcam, with autofocus capabilities and user configurable resolution.

sudo apt-get install fswebcam

I could now take a screenshot using the command

fswebcam image.jpg

I explored if I could change the resolution of the image to increase/decrease the resolution at will. I later found that indeed, that could be done using the command:

fswebcam -r 1280x720 –-no-banner image2.jpg


At this stage, I was feeling confident that Raspberry had started to respond to my whims.

What if i could run a cron job to take screenshots at set intervals? I was able to do that by issuing:

Crontab –e


This allowed me to setup cron to repeat, and loop for continuous image shots

All this was fun, but till now all that was achieved was to make the webcam work. Nothing done so far, had anything to do with the real parsing of barcodes.

Enter ZBar. This is an Open Source library, which is excellent in what it advertises. It can scan and parse a lot of different types of barcodes, and is very configurable. Unfortunately, the original Zbar library id not work for me as it was not well maintained. I spent a lot of time trying to work but got stuck at one place or the other. The original Zbar is quite old code and not meant for this version of ARM processor. Then I discovered a fork of Zbar at Github, which was a PHP wrapper for the original Zbar. This was available here which had superb sample scripts too to get started.

I installed python Zbar dependencies by executing:

sudo apt-get install python-zbar
sudo apt-get install libzbar-dev


Next I put the script files from the above URL on Raspberry in a folder, and then from that folder executed:

python setup.py install –user

The above went successfully and Zbar was now completely ready to do its magic.


Now, together with Zbar I had four available capability ready to be used as per will:
  • Take an image capture using fswebcam, and process later with zbar
  • Use video stream to read the first available barcode
  • Use video stream to read as many stable barcodes as possible
  • Use video stream to read continuous barcodes, till a mouse/keyboard activity happens


Here is an example of a simple script I wrote to take screenshots and store it with a unique name each time

#!/bin/bash

DATE=$(date +"%Y-%m-%d_%H%M%S")

fswebcam -r 1280x720 -i 0 --delay 1 --frames 10 --skip 5 --no-banner /home/pi/Documents/saurabh/webcam_cap/$DATE.jpg


And here is the final script, which was majorly provided as a Zbar sample script which initializes the webcam, and then run continually waiting for a valid barcode to appear. As soon as a barcode is detected, it is scanned, parsed and the the script ends. Just what I needed for this part of this proof of concept project.

#!/usr/bin/python
from sys import argv
import zbar

# create a Processor
proc = zbar.Processor()

# configure the Processor
proc.parse_config('enable')

# initialize the Processor
device = '/dev/video0'
if len(argv) > 1:
    device = argv[1]

#proc.request_size(800,480)

proc.init(device)

# enable the preview window
proc.visible = True

# read at least one barcode (or until window closed)
proc.process_one()

# hide the preview window
proc.visible = False

# extract results
for symbol in proc.results:
    # do something useful with results
    print 'decoded', symbol.type, 'symbol', '"%s"' % symbol.data


Here is a screenshot of the code in action. Notice that the barcode got read even when scanned upside down.


Up, Up and Away!


Here is a bonus script. In case you require your little Raspberry to let the world know about this barcode just read, or otherwise, then here is how I called a REST service using another Python script:

import httplib2
import json
import time
import datetime

def sendHTTPRq(barcode):
    httplib2.debuglevel     = 0
    http                    = httplib2.Http()
    content_type_header     = "application/json"

    url = "http://www.YOURSERVER.COM/JSONSVC/" +str(barcode)

    data = {    'Id':         barcode,
                'CreatedDateTime':    str(datetime.datetime.now()),
                'CreatedUser':    'saurabh',
                'UpdatedDateTime':    str(datetime.datetime.now())
           }

    headers = {'Content-Type': content_type_header}
    print ("Posting %s" % data)

    #while True:
    response, content = http.request( url,
                                      'GET',
                                      json.dumps(data),
                                      headers=headers)
    print (response);
    print (content);
    #time.sleep(3)
    return;

That's It. Do leave a comment if this may have helped you, or if you have suggestions for improvement, or a better process flow.

13 comments:

yayan yogo santoso said...

Awesome, I hope to be compared with some types of POS (open source) applications. Which are used as inputs like usb barcode scanner... :)

Ronnos said...

Great script! I just installed it on my raspberry pi 2b.
Unfortunately the camera is stuttering, and its very slow to recognize a barcode. I think it has something to to with my camera resolution...

Thanks for this, it's very fun to work with it.

iyed ahmed said...
This comment has been removed by the author.
iyed ahmed said...

Hello , i'm traying to do the same thing that you did , but when i run the programme this message apear :
Traceback (most recent call last):
File "setup.py", line 18, in
proc.init(device)
zbar.SystemError: ERROR: zbar processor in _zbar_video_open():
system error: opening video device 'install': No such file or directory (2)

Can you help me with this ?

Philip said...

Where would I find a tutorial in using the video stream to read as many stable barcodes?
(quick question, did that mean multiple barcodes on the screen or just sequentially presented barcodes?

Saurabh Kumar said...

@Philip.j.chou@gmail.com, I think the ZBar library provides three major methods. I used the process_one method which keeps on waiting for a barcode, and as soon as one barcode is received, it ends the program after dumping the results. The other two methods are process_image and processor_user_wait. process_image can be used to feed the routine saved images of barcodes, instead of reading from live webcam. The one of your interest might be processor_user_wait. This one will keep on reading barcodes one after another, until you provide input from mouse or keyboard. In all cases though, I think the library can read only one barcode at a time on screen. So I am not sure what will happen if you try to show it 5 barcodes at the same time. Hope this helps.

Philip said...

@Saurabh Kumar
Do you have any issues where zbar won't work unless fswebcam is run once? That seems to be an issue for me whenever i restart my raspberry pi.

Unknown said...

If i want to run the qr code url automatically after it is been scanned. What do i need to do?

Rafiq Husaini said...

If i want to run the qr code url automatically after it is been scanned. What do i need to do?

Unknown said...

@Saurabh Kumar
processor_user_wait is giving error that zbarprocessor has no attribute named proccessor_user_wait()

nkg_2001 said...

I am a new Pi user. I have raspbian jessie on model B+. I am trying follow your installation and code. but I get error at following step.
python setup.py install –user
Please help.

Vagish Adhav said...

Why I am getting error at
proc.request_size(800,480)?
I want to change the size.

Rahul Modi said...

Could you please tell me or write a code to send barcode data to IBM Watson IoT platform via REST service or via some other way ?