Title: An OpenCV barcode and QR code scanner with ZBar - PyImageSearch

URL Source: https://pyimagesearch.com/2018/05/21/an-opencv-barcode-and-qr-code-scanner-with-zbar/

Published Time: 2018-05-21T14:00:22+00:00

Markdown Content:
![Image 1](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20360'%3E%3C/svg%3E)

Today’s blog post on reading barcodes and QR codes with OpenCV is inspired by a question I received from PyImageSearch reader, Hewitt:

> Hey Adrian, I really love the PyImageSearch blog. I look forward to your emails each week. Keep doing what you’re doing.
> 
> I have a question for you:
> 
> Does OpenCV have any modules that can be used to read barcodes or QR codes? Or do I need to use an entirely separate library?
> 
> Thanks Adrian.

Great question, Hewitt.

The short answer is _no_, OpenCV does not have any dedicated modules that can be used to read and decode barcodes and QR codes.

_However_, what OpenCV can do is **facilitate the process of reading barcodes and QR codes**, including loading an image from disk, grabbing a new frame from a video stream, and processing it.

Once we have the image or frame we can then **pass it to a dedicated Python barcode decoding library such as a Zbar.**

The ZBar library will then decode the barcode or QR code. OpenCV can come back in to perform any further processing and display the result.

If this sounds like a complicated process, it’s actually pretty straightforward. The ZBar library, along with its various forks and variations, have come a long way. One set of ZBar bindings in particular, `pyzbar` , is my personal favorite.

Inside today’s tutorial, I will show you how to read barcodes and QR codes with OpenCV and ZBar.

And as an added bonus, I’ll demonstrate how to deploy our barcode scanner to the Raspberry Pi as well!

**To learn more about reading barcodes and QR codes with OpenCV and ZBar, _just keep reading._**

![Image 2](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20128%20128'%3E%3C/svg%3E)

#### Looking for the source code to this post?

[Jump Right To The Downloads Section](#download-the-code)

Today’s blog post is broken into four parts.

In the first part, I’ll show you how to install the [ZBar library](http://zbar.sourceforge.net/) (with Python bindings).

The ZBar library will be used together with OpenCV to scan and decode barcodes and QR codes.

Once ZBar and OpenCV are properly configured I’ll demonstrate how to scan barcodes and QR codes in a _single image_.

Starting with a single image will give us the practice we need to prepare for the next step: Reading barcodes and QR codes in real-time with OpenCV and ZBar,

Finally, I’ll demonstrate how to deploy our real-time barcode scanner to the Raspberry Pi.

### Installing ZBar (with Python bindings) for barcode decoding

A few weeks ago Satya Mallick from the LearnOpenCV blog posted a really great tutorial on [using the ZBar library to scan barcodes](https://www.learnopencv.com/barcode-and-qr-code-scanner-using-zbar-and-opencv/).

The instructions to install ZBar in today’s post are largely based on his instructions, but with a few updates, the largest one being related to how we install the Python `zbar` bindings themselves, ensuring we can:

1.  **Use Python 3** (the official `zbar` Python bindings only support Python 2.7)
2.  **Detect and localize** exactly where in the image the barcode is.

Installing the necessary software is an easy 3-step process.

**Step 1:** Install `zbar` from the `apt` or `brew` repository

**Installing ZBar for Ubuntu or Raspbian**

Installing ZBar for Ubuntu can be accomplished with the following command:

$ sudo apt-get install libzbar0

**Installing ZBar for macOS**

Installing ZBar for macOS using brew is equally as easy (assuming you have Homebrew installed):

$ brew install zbar

**Step 2 (Optional):** Create a virtual environment and install OpenCV

You have two options here:

1.  Use an existing virtual environment that has OpenCV ready to go (skip this step and head to **Step 3**).
2.  Or create a new, isolated virtual environment which involves installing OpenCV.

Virtual environments are a best practice for Python development and I highly encourage you to make use of them.

I elected to create a new, isolated Python 3 virtual environment and followed the Ubuntu (or macOS, depending on which machine I was using) OpenCV installation instructions linked on [this page](https://pyimagesearch.com/opencv-tutorials-resources-guides/). The only change I made while following those instructions was to name my environment `barcode` :

$ mkvirtualenv barcode -p python3

_**Note:** If you already have OpenCV installed on your system you can skip the OpenCV compile process and simply sym-link your `cv2.so` bindings into the `site-packages` directory of your new Python virtual environment._

**Step 3:** Install `pyzbar`

Now that I have a Python 3 virtual environment named `barcode` on my machine, I activated the `barcode` environment (yours might have a different name) and installed `pyzbar` :

$ workon barcode
$ pip install pyzbar

If you are not using a Python virtual environment you can just do:

$ pip install pyzbar

If you’re trying to install `pyzbar` into the system version of Python make sure you use the `sudo` command as well.

### Decoding barcodes and QR codes with OpenCV in single images

[![Image 3](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20444'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2018/05/barcode_scanner_output.jpg)

**Figure 1:** Both QR and 1D barcodes can be read with our Python app using ZBar + OpenCV.

Before we implement real-time barcode and QR code reading, let’s first start with a _single image_ scanner to get our feet wet.

Open up a new file, name it `barcode_scanner_image.py` and insert the following code:

\# import the necessary packages
from pyzbar import pyzbar
import argparse
import cv2

# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add\_argument("-i", "--image", required=True,
	help="path to input image")
args = vars(ap.parse\_args())

On **Lines 2-4** we import our required packages.

Both `pyzbar` and `cv2` (OpenCV) need to be installed following the instructions in the previous section.

In contrast, `argparse` is included with the Python install and it is responsible for parsing command line arguments.

We have one _required_ command line argument for this script (`--image` ) and it is parsed on **Lines 7-10**.

You’ll see at the end of this section how to run the script while passing a [command line argument](https://pyimagesearch.com/2018/03/12/python-argparse-command-line-arguments/) containing the input image path.

Now, let’s take the input image and put `pyzbar` to work:

\# load the input image
image = cv2.imread(args\["image"\])

# find the barcodes in the image and decode each of the barcodes
barcodes = pyzbar.decode(image)

On **Line 13**, we load the input `image` via its path (contained in our convenient `args` dictionary).

From there, we call `pyzbar.decode` to find and decode the `barcodes` in the `image` (**Line 16**). This is where all the magic of ZBar happens.

We aren’t finished yet — now we need to parse the information contained within the `barcodes` variable:

\# loop over the detected barcodes
for barcode in barcodes:
	# extract the bounding box location of the barcode and draw the
	# bounding box surrounding the barcode on the image
	(x, y, w, h) = barcode.rect
	cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 255), 2)

	# the barcode data is a bytes object so if we want to draw it on
	# our output image we need to convert it to a string first
	barcodeData = barcode.data.decode("utf-8")
	barcodeType = barcode.type

	# draw the barcode data and barcode type on the image
	text = "{} ({})".format(barcodeData, barcodeType)
	cv2.putText(image, text, (x, y - 10), cv2.FONT\_HERSHEY\_SIMPLEX,
		0.5, (0, 0, 255), 2)

	# print the barcode type and data to the terminal
	print("\[INFO\] Found {} barcode: {}".format(barcodeType, barcodeData))

# show the output image
cv2.imshow("Image", image)
cv2.waitKey(0)

Beginning on **Line 19**, we loop over the detected `barcodes` .

In this loop, we proceed to:

1.  Extracting the bounding box _(x, y)-_coordinates from the `barcode.rect` object (**Line 22**), enabling us to _localize_ and determine _where_ in the input image the current barcode is.
2.  Draw draw a bounding box rectangle on the `image` around the detected `barcode` (**Line 23**).
3.  Decode the `barcode` into a `"utf-8"` string and extract the type of barcode (**Lines 27 and 28**). It is critical to call the `.decode("utf-8")` function on the object to convert from a byte array to a string. You can experiment by removing/commenting it out to see what happens — I’ll leave this as an experiment for you to try.
4.  Format and draw the `barcodeData` and `barcodeType` on the image (**Lines 31-33**).
5.  And finally, output the same data and type information to the terminal for debugging purposes (**Line 36**).

Let’s test our OpenCV barcode scanner. You should use the _**“Downloads”**_ section at the bottom of this blog post to download the code and example image.

From there, open up your terminal and execute this command:

$ python barcode\_scanner\_image.py --image barcode\_example.png
\[INFO\] Found QRCODE barcode: {"author": "Adrian", "site": "PyImageSearch"}
\[INFO\] Found QRCODE barcode: https://pyimagesearch.com/
\[INFO\] Found QRCODE barcode: PyImageSearch
\[INFO\] Found CODE128 barcode: AdrianRosebrock

As you can see in the terminal, all four of the barcodes were found and properly decoded!

Refer to **Figure 1** for the processed image which has overlaid red rectangles and text for each barcode our software found.

### Real-time barcode and QR code reading with OpenCV

In the previous section, we learned how to create a Python + OpenCV barcode scanner for single images.

Our barcode and QR code scanner worked well — but it raises the question, _can we detect and decode barcode + QR codes in real-time?_

To find out, open up a new file, name it `barcode_scanner_video.py` , and insert the following code:

\# import the necessary packages
from imutils.video import VideoStream
from pyzbar import pyzbar
import argparse
import datetime
import imutils
import time
import cv2

# construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add\_argument("-o", "--output", type=str, default="barcodes.csv",
	help="path to output CSV file containing barcodes")
args = vars(ap.parse\_args())

On **Lines 2-8** we import our required packages.

At this point, recalling the above explanation, you should recognize `pyzbar` , `argparse` , and `cv2` .

We’ll also use `VideoStream` to handle capturing video frames in an efficient, threaded approach. You can [learn more about the VideoStream class here](https://pyimagesearch.com/2016/01/04/unifying-picamera-and-cv2-videocapture-into-a-single-class-with-opencv/). And if you do not have `imutils` installed on your system, just use the following command:

$ pip install imutils

We’re going to parse one _optional_ command line argument, `--output` , which contains the path to the output Comma Separated Values (CSV) file. This file will contain the timestamp and payload of each detected and decoded barcode from our video stream. If this argument isn’t specified, the CSV file will be placed in our current working directory with a name of `"barcodes.csv"` (**Lines 11-14**).

From there, let’s initialize our video stream and open our CSV file:

\# initialize the video stream and allow the camera sensor to warm up
print("\[INFO\] starting video stream...")
# vs = VideoStream(src=0).start()
vs = VideoStream(usePiCamera=True).start()
time.sleep(2.0)

# open the output CSV file for writing and initialize the set of
# barcodes found thus far
csv = open(args\["output"\], "w")
found = set()

On **Lines 18 and 19** we initialize and start our `VideoStream` . You may either:

*   Use your USB webcam (uncomment **Line 18** and comment **Line 19**)
*   Or if you’re using a Raspberry Pi (like me) you can use the PiCamera (uncomment **Line 19** and comment **Line 18**).

I chose to use my Raspberry Pi PiCamera, as is shown in the next section.

We then pause for two seconds to allow the camera can warm up (**Line 20**).

We’ll be writing all barcodes we find to disk in a CSV file (but ensuring duplicates are not written). **This is meant to be a (trivial) example of logging barcodes.** You could, of course, do whatever you want once a barcode is detected and read such as:

*   Save it in a SQL database
*   Send it to a server
*   Upload it to the cloud
*   Send an email or text message

**The actual action is arbitrary** — we’re simply using the CSV file as an example.

**Feel free to update the code to include any notification you may wish.**

We open the `csv` file for writing on **Line 24**. If you are modifying the code to append to the file, you can simply change the 2nd parameter from `"w"` to `"a"` (but you’ll have to search the file for duplicates in a different way).

We also initialize a `set` for `found` barcodes. This set will contain unique barcodes while preventing duplicates.

Let’s begin capturing + processing frames:

\# loop over the frames from the video stream
while True:
	# grab the frame from the threaded video stream and resize it to
	# have a maximum width of 400 pixels
	frame = vs.read()
	frame = imutils.resize(frame, width=400)

	# find the barcodes in the frame and decode each of the barcodes
	barcodes = pyzbar.decode(frame)

On **Line 28** we start our loop and proceed to grab and and resize a `frame` from our video stream (**Lines 31 and 32**).

From there, we call `pyzbar.decode` to detect and decode any QR + barcodes in the `frame` .

Let’s proceed to loop over the detected `barcodes` :

	# loop over the detected barcodes
	for barcode in barcodes:
		# extract the bounding box location of the barcode and draw
		# the bounding box surrounding the barcode on the image
		(x, y, w, h) = barcode.rect
		cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2)

		# the barcode data is a bytes object so if we want to draw it
		# on our output image we need to convert it to a string first
		barcodeData = barcode.data.decode("utf-8")
		barcodeType = barcode.type

		# draw the barcode data and barcode type on the image
		text = "{} ({})".format(barcodeData, barcodeType)
		cv2.putText(frame, text, (x, y - 10),
			cv2.FONT\_HERSHEY\_SIMPLEX, 0.5, (0, 0, 255), 2)

		# if the barcode text is currently not in our CSV file, write
		# the timestamp + barcode to disk and update the set
		if barcodeData not in found:
			csv.write("{},{}\\n".format(datetime.datetime.now(),
				barcodeData))
			csv.flush()
			found.add(barcodeData)

This loop should look very familiar if you read the previous section.

In fact, **Lines 38-52** are _identical_ to those the _single image_ script. Please refer to the single image barcode detection and scanning section for a detailed review of this code block.

**Lines 56-60** are new. On these lines, we check if we’ve found a unique (not previously found) barcode (**Line 56**).

If that’s the case, we write the timestamp and data to the `csv` file (**Lines 57-59**). We also append the `barcodeData` to a `found` set as a simple way to handle duplicates.

In the remaining lines of the real-time barcode scanner script, we display the frame, check if the quit key is pressed, and perform cleanup:

	# show the output frame
	cv2.imshow("Barcode Scanner", frame)
	key = cv2.waitKey(1) & 0xFF
 
	# if the \`q\` key was pressed, break from the loop
	if key == ord("q"):
		break

# close the output CSV file do a bit of cleanup
print("\[INFO\] cleaning up...")
csv.close()
cv2.destroyAllWindows()
vs.stop()

On **Line 63** we display the output `frame` .

Then on **Lines 64-68**, we check for keys and if `"q"` is pressed, we `break` out of the main execution loop.

Finally, we perform cleanup on **Lines 72-74**.

### Building a barcode and QR code scanner on the Raspberry Pi

[![Image 4](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20481'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2018/05/barcode_scanner_setup.jpg)

**Figure 2:** My Raspberry Pi barcode scanner project consists of a Raspberry Pi, PiCamera, 7-inch touchscreen, and battery pack.

What fun is a barcode scanner if I’m limited to my desk?

I decided that I’d like to take my barcode scanner with me using my Pi, touchscreen, and battery pack.

Shown in **Figure 2** is my setup — the exact one I used for my [mobile Pokedex deep learning project](https://pyimagesearch.com/2018/04/30/a-fun-hands-on-deep-learning-project-for-beginners-students-and-hobbyists/) recently. If you’re looking to build your own with the exact peripherals shown, I’ve listed the products and links:

*   [Raspberry Pi 3](https://amzn.to/2Hn1b7b) (or you could use the [latest 3 B+](https://amzn.to/2rmm3p9))
*   [Raspberry Pi camera module](https://amzn.to/2Kb9lBd)
*   [Pi Foundation 7″ touchscreen display](https://amzn.to/2KaYYOa)
*   [Portable Charger RAVPower 22000mAh Power Bank](https://amzn.to/2HpAjmS)

Building the system is really easy and I’ve made step-by-step instructions in [this blog post](https://pyimagesearch.com/2018/04/30/a-fun-hands-on-deep-learning-project-for-beginners-students-and-hobbyists/).

Once your mobile ZBar barcode scanner is ready, use the _**“Downloads”**_ section of this blog post to download the code associated with this blog post.

From there, open up a terminal on your Pi and launch the app with the following command (you’ll need a keyboard/mouse for this step but then you can disconnect and let the app run):

$ python barcode\_scanner\_video.py
\[INFO\] starting video stream...

Now you can present barcodes to the camera and when you’re done, you can open the `barcodes.csv`  file (or if you’re so inclined you can execute `tail -f barcodes.csv`  in a separate terminal to view the data as it enters the CSV file live).

The first QR code that I tried is shown on a black background — it is very easy for ZBar to detect:

[![Image 5](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20360'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2018/05/barcode_scanner_result_01.jpg)

**Figure 3:** A QR code with the code “PyImageSearch” is recognized with our Python + ZBar application

Then I headed to my kitchen, with Pi, screen, and battery pack in hand, and found another QR code:

[![Image 6](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20360'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2018/05/barcode_scanner_result_02.jpg)

**Figure 4:** My website, “https://pyimagesearch.com/” is encoded in a QR code and recognized with ZBar and Python on my Raspberry Pi.

Success! It even works at many angles.

Now let’s try a QR code that is contains a JSON-blob of data:

[![Image 7](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20360'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2018/05/barcode_scanner_result_03.jpg)

**Figure 5:** An OpenCV barcode and QR scanner with ZBar decodes an image of a QR with ease. I deployed the project to my Raspberry Pi so I can take it on the go.

No match for my OpenCV + ZBar + Python barcode scanner project!

And finally, I tried a traditional 1-D barcode:

[![Image 8](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20600%20360'%3E%3C/svg%3E)](https://pyimagesearch.com/wp-content/uploads/2018/05/barcode_scanner_result_04.jpg)

**Figure 6:** ZBar coupled with OpenCV and Python makes for a great Raspberry Pi barcode project. My name, “AdrianRosebrock” is encoded in this CODE128 barcode.

1-D barcodes are slightly more challenging for the system especially with a PiCamera which doesn’t support autofocus. That being said, I achieved a successful detection and decoding of this barcode as well.

You might have best luck with a USB webcam such as the Logitech C920 which has great autofocus. Alternatively, you can actually change the factory focus on your PiCamera using the method that Jeff Geerling describes [on his blog](https://www.jeffgeerling.com/blog/2017/fixing-blurry-focus-on-some-raspberry-pi-camera-v2-models).

That’s a wrap!

If you’re interested in reading additional barcode blog posts on my website, check out the [posts with the “barcode” tag](https://pyimagesearch.com/tag/barcode/).

### What's next? We recommend [PyImageSearch University](https://pyimagesearch.com/pyimagesearch-university/?utm_source=blogPost&utm_medium=bottomBanner&utm_campaign=What%27s%20next%3F%20I%20recommend).

**Course information:**  
84 total classes • 114+ hours of on-demand code walkthrough videos • Last updated: February 2024  
★★★★★ 4.84 (128 Ratings) • 16,000+ Students Enrolled

**I strongly believe that if you had the right teacher you could _master_ computer vision and deep learning.**

Do you think learning computer vision and deep learning has to be time-consuming, overwhelming, and complicated? Or has to involve complex mathematics and equations? Or requires a degree in computer science?

That’s _not_ the case.

All you need to master computer vision and deep learning is for someone to explain things to you in _simple, intuitive_ terms. _And that’s exactly what I do_. My mission is to change education and how complex Artificial Intelligence topics are taught.

If you're serious about learning computer vision, your next stop should be PyImageSearch University, the most comprehensive computer vision, deep learning, and OpenCV course online today. Here you’ll learn how to _successfully_ and _confidently_ apply computer vision to your work, research, and projects. Join me in computer vision mastery.

**Inside PyImageSearch University you'll find:**

*   ✓ **84 courses** on essential computer vision, deep learning, and OpenCV topics
*   ✓ **84 Certificates** of Completion
*   ✓ **114+ hours** of on-demand video
*   ✓ **Brand new courses released _regularly_**, ensuring you can keep up with state-of-the-art techniques
*   ✓ **Pre-configured Jupyter Notebooks in Google Colab**
*   ✓ Run all code examples in your web browser — works on Windows, macOS, and Linux (no dev environment configuration required!)
*   ✓ Access to **centralized code repos for _all_ 536+ tutorials** on PyImageSearch
*   ✓ **Easy one-click downloads** for code, datasets, pre-trained models, etc.
*   ✓ **Access** on mobile, laptop, desktop, etc.

[Click here to join PyImageSearch University](https://pyimagesearch.com/pyimagesearch-university/?utm_source=blogPost&utm_medium=bottomBanner&utm_campaign=What%27s%20next%3F%20I%20recommend)

Summary
-------

In today’s blog post you learned how to build an OpenCV barcode and QR code scanner.

To accomplish this, we used the [ZBar library](http://zbar.sourceforge.net/).

Once the ZBar library was installed on our system, we created two Python scripts:

1.  The first one to scan barcodes and QR codes in a single image
2.  And a second script to read barcodes and QR codes in real-time

In both cases, we used OpenCV to facilitate the process of building our barcode/QR code scanner.

Finally, we wrapped up today’s blog post by deploying our barcode reader to the Raspberry Pi.

The barcode scanner is fast enough to run in real-time on the Raspberry Pi without an issue.

Feel free to use this barcode and QR code scanner functionality in your own projects!

And if you build something fun and interesting with it, be sure to share your project in the comments.

I hope you enjoyed today’s post. I’ll see you next week.

**To be notified when future blog posts are published here on PyImageSearch, _be sure to enter your email address in the form below!_**

![Image 9](data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%20410%20567'%3E%3C/svg%3E)

#### Download the Source Code and FREE 17-page Resource Guide

Enter your email address below to get a .zip of the code and a **FREE 17-page Resource Guide on Computer Vision, OpenCV, and Deep Learning.** Inside you'll find my hand-picked tutorials, books, courses, and libraries to help you master CV and DL!