Recognizing QR codes and barcodes with OpenCV and Python

Keywords: Python OpenCV Computer Vision

Computer vision expert Adrian roserock recently shared how to write a scanning program that can recognize QR code and bar code in real time with the help of OpenCV and Zbar. Finally, he deployed it on raspberry pie and successfully made a practical bar code & QR code scanning device.

Recently, a friend asked me if there are any modules in OpenCV that can directly identify bar codes and QR codes. Unfortunately, the answer is No. However, OpenCV can speed up the process of reading barcode and QR code, including loading images from the hard disk, grabbing new frames from the video stream and processing them. After we get the image or video frame, we can transfer it to the special barcode decoding library in Python, such as Zbar. Zbar then decodes the barcode or QR code. OpenCV can then perform further image processing and display the results. It sounds a little complicated. In fact, the whole process is quite simple and clear. The library Zbar has also derived many variants, of which pyzbar is my favorite.

In this article, I will teach you how to read bar codes and QR codes with OpenCV and Zbar. Moreover, I will also show how to deploy our barcode QR code scanner to raspberry pie!!

Create a barcode and QR code scanner with OpenCV and ZBar

This paper is mainly divided into four parts.

  • In the first part, I will teach you how to install the Zbar Library (Python binding).
  • The Zbar library will be used with OpenCV to scan barcodes and QR codes.
  • After properly configuring Zbar and OpenCV, I will show how to use them to scan the barcode and QR code on an image.
  • First identify the barcode and QR code on an image. After practicing, we will enter the next stage: read the QR code and bar code in real time with OpenCV and Zbar.
  • Finally, I will show how to deploy the real-time QR Code & bar code scanner to raspberry pie.

Install Zbar (with Python binding) for decoding barcode & QR code

Some time ago, Staya Mallick published a practical tutorial on the learnopuncv blog, explaining how to scan bar codes with Zbar.

The Zbar installation part of this article is basically based on the guidance of this blog, but some improvements have been made, mainly focusing on the installation of Python Zbar binding. The purpose is to ensure that we can:

Use Python 3 (the official Zbar Python binding only supports Python 2.7) to accurately detect and locate QR codes and barcodes in images

Install the required software in three simple steps.

Step 1: install Zbar from apt or brew Library

Install Zbar on Ubuntu or raspberry pie

$ sudo apt-get install libzbar0
 Copy code

Installing Zbar on MacOS system

It is also easy to install Zbar in macOS system using brew (assuming you have installed Homebrew):

$ brew install zbar
 Copy code

Step 2: create a virtual environment and install OpenCV.

Here you have two choices: use the ready-made virtual environment with OpenCV installed (skip this step and see Step 3). Or create a new independent virtual environment and install OpenCV.

Virtual environment is a very practical approach for Python development, and I highly encourage the use of virtual environment.

I chose to create a new independent Python 3 virtual environment, then installed OpenCV and named the environment barcode:

$ mkvirtualenv barcode -p python3
 Copy code

Note: if you have installed OpenCV, you can skip the OpenCV compilation process. Just put your cv2.so binding symlink into the site pages directory in your new Python virtual environment.

Step 3: install Pyzbar. Now I have installed Python 3

The virtual environment is named barcode, and then the barcode environment is activated to install pyzbar:

$ workon barcode
$ pip install pyzbar
 Copy code

If you are not using Python virtual environment, just:

$ pip install pyzbar
 Copy code

If you want to install pyzbar into the Python version of the system, make sure you also use the sudo command.

Decoding barcode and QR code on a single image with OpenCV

Before we can read barcode and QR code in real time, we first create a single image scanner to practice.

Open a new file named barcode_scanner_image.py, insert the following code:

# Import the required toolkit
from pyzbar import pyzbar
import argparse
import cv2

# Build a parameter parser and parse the parameters
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True,
 help="path to input image")
args = vars(ap.parse_args())
Copy code

In lines 2-4, we import the required toolkit.

You need to install pyzbar and cv2 (OpenCV) according to the instructions in the previous section. However, argparse is included in the Python installation, which is responsible for parsing command-line parameters.

We have a required command line parameter (- - image) for the script, which is parsed in lines 7-10.

At the end of this section, you will see how to run the script here when passing in the command line parameter containing the input image path.

Now let's get the input image and run pyzbar:

# Load input image
image = cv2.imread(args["image"])

# Locate the barcode in the image and decode it
barcodes = pyzbar.decode(image)
Copy code

In line 13, we load the image through the path of the image (included in our convenient args directory).

From here, we call pyzbar.decode to discover and decode the barcode in the image (line 16).

We haven't finished yet - now we need to parse the information contained in the barcode variable:

# Cycle detected barcodes
for barcode in barcodes:
 # The location of the bounding box from which the barcode is extracted
 # Draw the bounding box of the barcode in 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 byte object, so if we want to print it on the output image
 # To draw it, you need to convert it into 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 barcode data and barcode type to the terminal
 print("[INFO] Found {} barcode: {}".format(barcodeType, barcodeData))

# Show output image
cv2.imshow("Image", image)
cv2.waitKey(0)
Copy code

Starting at line 19, we loop through the detected barcodes. In this cycle, we continue:

Extract the bounding box (x,y) coordinates from the barcode.rect object (22 lines), which allows us to locate and determine the position of the current barcode in the input image.

Draw a bounding box around the detected barcode (line 23) on the image.

decode the barcode into a "utf-8" string and extract the type of barcode (lines 27 and 28). It is crucial to call the. decode ("utf-8") function to convert objects from byte arrays to strings. You can test the results by deleting or adding comments.

Format and draw barcodeData and barcodeType on the image (lines 31-33).

Finally, output the same data and input information to the terminal for debugging (line 36).

Let's test the OpenCV barcode scanner. From here, open your terminal and execute the following command:

$ python barcode_scanner_image.py --image barcode_example.png
[INFO] Found QRCODE barcode: {"author": "Adrian", "site": "PyImageSearch"}
[INFO] Found QRCODE barcode: https://www.pyimagesearch.com/
[INFO] Found QRCODE barcode: PyImageSearch
[INFO] Found CODE128 barcode: AdrianRosebrock
 Copy code

It can be seen in the terminal that all four barcodes are correctly found and decoded!

As shown in the figure, the barcode and QR code in the image are identified, marked with a red box, and the information they contain is displayed.

Read barcode and QR code in real time with OpenCV    Source sharing

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

Our barcode and QR code scanners work well - but the question is, can we detect and decode barcode + QR code in real time?

Let's try. Open a new file named barcode_scanner_video.py, insert the following code:

# Import the required toolkit
from imutils.video import VideoStream
from pyzbar import pyzbar
import argparse
import datetime
import imutils
import time
import cv2

# Create a parameter parser to parse parameters
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())
Copy code

In lines 2-8, we import the required toolkit. Recall the above explanation. You should recognize pyzbar,argparse and cv2. We will use VideoStream to process the acquired video frames in an efficient and single threaded manner. If imutils is not installed on your system, just use the following command:

$ pip install imutils
 Copy code

We then parse an optional command-line parameter -- output, which contains the path to the output result CSV file. The file will contain the time stamp and load of the barcode detected and parsed from the video stream. If this parameter is not specified, the CSV file will be replaced by our current working directory called "barcodes.csv" (lines 11-14).

Here, we initialize the video stream and open the CSV file:

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

# Open the output CSV file to write and initialize all barcodes found so far
csv = open(args["output"], "w")
found = set()
Copy code

In lines 18-19, we initialize and start the video stream. You can use your own USB webcam (lines 18 and 19 without comments) or PiCamera (lines 19 and 18 without comments) if you use raspberry pie (like me).

Source sharing

I chose to use my raspberry pie PiCamera, which will be mentioned in the next section.

Then we wait a few seconds for the camera to warm up (line 20).

We will write all the barcodes and QR codes found to the hard disk as CSV files (make sure not to write them repeatedly). Here is just an example of recording barcodes. Of course, you can do it according to your preferences. For example, after detecting barcodes, read them as:

  • Save it in the SQL database
  • Send it to the server
  • Upload it to the cloud
  • Send mail or text messages

The actual operation is arbitrary. We just use the CSV file as an example.

In line 24, we open the CSV file to write to the hard disk. If you modify the code to add to the file, you can just change the second parameter from "w" to "a" (but you can only search for duplicate files in another way later).

We also initialize a set for the found barcode. This set will contain unique barcodes to prevent duplication.

We begin to acquire and process video frames:

# Loop frames from video stream
while True:
 # Grab frames from a single threaded video stream, 
 # Resize to a maximum width of 400 pixels
 frame = vs.read()
 frame = imutils.resize(frame, width=400)

 # Find the barcodes in the video and parse all barcodes
 barcodes = pyzbar.decode(frame)
Copy code

In line 28, we start the loop, continue to grab the frame from the video stream and resize it (lines 31 and 32).

Here, we call pyzbar.decode to detect and decode all barcodes and QR codes in the frame.

We then loop the detected barcodes:

 # Cycle detected barcodes
 for barcode in barcodes:
  # Extract the bounding box position of the barcode
  # Draw a bounding box around the barcode on the image
  (x, y, w, h) = barcode.rect
  cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2)

  # Bar code data is a byte object, so if we want to draw it
  # You need to convert it into a string first
  barcodeData = barcode.data.decode("utf-8")
  barcodeType = barcode.type

  # Draw the barcode data and 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 not currently in the CSV file, write
  # Time stamp + 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)
Copy code

If you look at the previous loop, you will find that the loop here is very similar to the previous one.

In fact, lines 38-52 are the same as the previous script for identifying a single image. For the detailed explanation of this part of code, see the bar code detection and scanning part of single image.

Lines 56-60 are relatively new. In these lines of code, we check whether a unique (not previously found) barcode is found (line 56).

If this is the case, we write the timestamp and data as a CSV file (lines 57-59). You can also add barcodeData to the found set as a simple way to handle duplicate files.

In the remaining code lines of the real-time barcode scanning script, we show the video frame, check whether the exit key is pressed and clear:

 # Display output frame
 cv2.imshow("Barcode Scanner", frame)
 key = cv2.waitKey(1) & 0xFF

 # If the "q" key is pressed, the cycle stops
 if key == ord("q"):
  break

# Close the output CSV file for cleanup
print("[INFO] cleaning up...")
csv.close()
cv2.destroyAllWindows()
vs.stop()
Copy code

On line 63, we show the output frame.

Then, on lines 64-68, we check whether "q" is pressed to execute the main loop.

Finally, we perform cleanup on lines 72-74.

Deploy barcode and QR code scanners on raspberry pie

I decided to create my own real-time barcode scanner using raspberry pie, touch screen and a power bank.

The figure below shows my assembly results. If you want to make one yourself, here are the parts you need:

  • Raspberry Pie 3 (you can also use the latest 3 B +)
  • Raspberry pie camera module
  • Pi Foundation 7-inch touch screen
  • RAVPower 22000mAh power bank

It's easy to assemble.

Here, open the terminal on your raspberry pie and start the application with the following command (this step requires a keyboard / mouse, but not later):

$ python barcode_scanner_video.py
[INFO] starting video stream...
Copy code

When everything is ready, you can display the barcode to the camera and open the barcode.csv file (or if you like, you can execute tail -f barcodes.csv on another terminal to view the data when opening the CSV file).

I first showed the camera a QR code on a black background, and Zbar easily detected it:

Then I found another QR code in my kitchen with this device:

succeed! And it can scan and recognize QR codes from multiple angles.

Now, let's try a QR code containing JSON BLOB data:

Finally, I tried the traditional 1D barcode:

1D barcode is a little difficult for our system because the camera does not support autofocus. But in the end, the barcode was successfully detected and decoded.

If you use a USB webcam with auto focus, the effect is much better.

epilogue

In this article, we discussed how to build a barcode and QR code scanner with OpenCV and Python library Zbar.

After installing Zbar and OpenCV, we created two Python scripts:

  • The first one is used to scan the barcode and QR code on a single image.
  • The second one is used to read the information of barcode and QR code in real time. In both cases, we used OpenCV to speed up the process.

Finally, we will deploy the created program to raspberry pie and successfully recognize bar codes and QR codes in real time. You can try to make such a bar code & QR code scanner, and download the project source code   

Project source code download reference: www.pyimagesearch.com

Posted by gullit on Wed, 27 Oct 2021 15:35:59 -0700