• Home
  • >
  • Tutorial
  • >
  • Barcode and QR Code Scanner Using ZBar and OpenCV

Barcode and QR Code Scanner Using ZBar and OpenCV

In this post, we will share C++ and Python code for writing a barcode and QR code scanner using a library called ZBar and OpenCV. The Python code works in both Python 2 and Python 3. If you have never seen a barcode or a QR code, please send me

Barcode and QR code Scanner using ZBar and OpenCV
Barcode and QR code Scanner using ZBar and OpenCV

In this post, we will share C++ and Python code for writing a barcode and QR code scanner using a library called ZBar and OpenCV. The Python code works in both Python 2 and Python 3.

If you have never seen a barcode or a QR code, please send me the address of your cave so I can send you a sample by mail. Jokes aside, barcodes and QR codes are everywhere. In fact, I have a QR code on the back of my business card as well! Pretty cool, huh?

How to Detect and Decode Barcodes and QR Codes in an Image?

Step 1 : Install ZBar

The best library for detecting and decoding barcodes and QR codes of different types is called ZBar. Before we begin, you must download and install ZBar by following the instructions.

macOS users can simply install using Homebrew

brew install zbar

Ubuntu users can install using

sudo apt-get install libzbar-dev libzbar0

Step 2 : Install pyzbar (for Python users only)

The official version of ZBar does not support Python 3. So we recommend using pyzbar which supports both ython 2 and Python 3. If you want to work with python 2, you can install zbar and skip installing pyzbar.

Install ZBar

# NOTE: Official zbar version does not support Python 3
pip install zbar

Install pyzbar

pip install pyzbar
Download Code To easily follow along this tutorial, please download code by clicking on the button below. It's FREE!

Step 3: Understanding the structure of a barcode / QR code

A barcode / QR code object returned by ZBar has three fields

  1. Type: If the symbol detected by ZBar is a QR code, the type is QR-Code. If it is barcode, the type is one of the several kinds of barcodes ZBar is able to read. In our example, we have used a barcode of type CODE-128
  2. Data: This is the data embedded inside the barcode / QR code. This data is usually alphanumeric, but other types ( numeric, byte/binary etc. ) are also valid.
  3. Location: This is a collection of points that locate the code. For QR codes, it is a list of four points corresponding to the four corners of the QR code quad. For barcodes, location is a collection of points that mark the barcode’s start and end of word boundaries. The location points are plotted for a few different kinds of symbols below.
ZBar Location Field - barcode and QR code scanner
ZBar location points plotted using red dots. For QR codes, it is a vector of 4 corners of the symbol. For barcodes, it is a collection of points that form lines along word boundaries.

Step 3a : C++ code for scanning barcode and QR code using ZBar + OpenCV

We first define a structure to hold the information about a barcode or QR code detected in an image.

typedef struct
{
  string type;
  string data;
  vector <Point> location;
} decodedObject;

The type, data, and location fields are explained in the previous section.

Download Code To easily follow along this tutorial, please download code by clicking on the button below. It's FREE!

Let’s look at the decode function that takes in an image and returns all barcodes and QR codes found.

// Find and decode barcodes and QR codes
void decode(Mat &im, vector<decodedObject>&decodedObjects)
{

  // Create zbar scanner
  ImageScanner scanner;

  // Configure scanner
  scanner.set_config(ZBAR_NONE, ZBAR_CFG_ENABLE, 1);

  // Convert image to grayscale
  Mat imGray;
  cvtColor(im, imGray,CV_BGR2GRAY);

  // Wrap image data in a zbar image
  Image image(im.cols, im.rows, "Y800", (uchar *)imGray.data, im.cols * im.rows);

  // Scan the image for barcodes and QRCodes
  int n = scanner.scan(image);

  // Print results
  for(Image::SymbolIterator symbol = image.symbol_begin(); symbol != image.symbol_end(); ++symbol)
  {
    decodedObject obj;

    obj.type = symbol->get_type_name();
    obj.data = symbol->get_data();

    // Print type and data
    cout << "Type : " << obj.type << endl;
    cout << "Data : " << obj.data << endl << endl;

    // Obtain location
    for(int i = 0; i< symbol->get_location_size(); i++)
    {
      obj.location.push_back(Point(symbol->get_location_x(i),symbol->get_location_y(i)));
    }

    decodedObjects.push_back(obj);
  }
}

First, in lines 5-9 we create an instance of a ZBar ImageScanner and configure it to detect all kinds of barcodes and QR codes. If you want only a specific kind of symbol detected, you must change ZBAR_NONE to a different type listed here. We then convert the image to grayscale ( lines 11-13). We then convert the grayscale image to a ZBar compatible format in line 16 . Finally, we scan the image for symbols (line 19). Finally, we iterate over the symbols, extract the type, data, and location information, and push it in the vector of detected objects (lines 21-40).

Next, we will explain the code for displaying all the symbols. The code below takes in the input image and a vector of decoded symbols from the previous step. If the points form a quad ( e.g. in a QR code ), we draw the quad ( line 14 ). If the location is not a quad, we draw the outer boundary of all the points ( also called the convex hull ) of all the points. This is done using OpenCV function called convexHull shown in line 12.

// Display barcode and QR code location
void display(Mat &im, vector<decodedObject>&decodedObjects)
{
  // Loop over all decoded objects
  for(int i = 0; i < decodedObjects.size(); i++)
  {
    vector<Point> points = decodedObjects[i].location;
    vector<Point> hull;

    // If the points do not form a quad, find convex hull
    if(points.size() > 4)
      convexHull(points, hull);
    else
      hull = points;

    // Number of points in the convex hull
    int n = hull.size();

    for(int j = 0; j < n; j++)
    {
      line(im, hull[j], hull[ (j+1) % n], Scalar(255,0,0), 3);
    }

  }

  // Display results
  imshow("Results", im);
  waitKey(0);

}

Finally, we have the main function shared below that reads an image, decodes the symbols using the decode function described above, and displays the location using the display function described above.

int main(int argc, char* argv[])
{

  // Read image
  Mat im = imread("zbar-test.jpg");

  // Variable for decoded objects
  vector<decodedObject> decodedObjects;

  // Find and decode barcodes and QR codes
  decode(im, decodedObjects);

  // Display location
  display(im, decodedObjects);

  return EXIT_SUCCESS;
}

Step 3b : Python code for scanning barcode and QR code using ZBar + OpenCV

For Python, we use pyzbar, which has a simple decode function to locate and decode all symbols in the image. The decode function in lines 6-15 warps pyzbar’s decode function and loops over the located barcodes and QR codes and prints the data.

The decoded symbols from the previous step are passed on to the display function (lines 19-41). If the points form a quad ( e.g. in a QR code ), we draw the quad ( line 30 ). If the location is not a quad, we draw the outer boundary of all the points ( also called the convex hull ) of all the points. This is done using OpenCV function called cv2.convexHull shown in line 27.

Finally, the main function reads an image, decodes it and displays the results.

from __future__ import print_function
import pyzbar.pyzbar as pyzbar
import numpy as np
import cv2

def decode(im) :
  # Find barcodes and QR codes
  decodedObjects = pyzbar.decode(im)

  # Print results
  for obj in decodedObjects:
    print('Type : ', obj.type)
    print('Data : ', obj.data,'\n')

  return decodedObjects

# Display barcode and QR code location
def display(im, decodedObjects):

  # Loop over all decoded objects
  for decodedObject in decodedObjects:
    points = decodedObject.polygon

    # If the points do not form a quad, find convex hull
    if len(points) > 4 :
      hull = cv2.convexHull(np.array([point for point in points], dtype=np.float32))
      hull = list(map(tuple, np.squeeze(hull)))
    else :
      hull = points;

    # Number of points in the convex hull
    n = len(hull)

    # Draw the convext hull
    for j in range(0,n):
      cv2.line(im, hull[j], hull[ (j+1) % n], (255,0,0), 3)

  # Display results
  cv2.imshow("Results", im);
  cv2.waitKey(0);

# Main
if __name__ == '__main__':

  # Read image
  im = cv2.imread('zbar-test.jpg')

  decodedObjects = decode(im)
  display(im, decodedObjects)

Some Results

 

 

Read Next

VideoRAG: Redefining Long-Context Video Comprehension

VideoRAG: Redefining Long-Context Video Comprehension

Discover VideoRAG, a framework that fuses graph-based reasoning and multi-modal retrieval to enhance LLMs' ability to understand multi-hour videos efficiently.

AI Agent in Action: Automating Desktop Tasks with VLMs

AI Agent in Action: Automating Desktop Tasks with VLMs

Learn how to build AI agent from scratch using Moondream3 and Gemini. It is a generic task based agent free from…

The Ultimate Guide To VLM Evaluation Metrics, Datasets, And Benchmarks

The Ultimate Guide To VLM Evaluation Metrics, Datasets, And Benchmarks

Get a comprehensive overview of VLM Evaluation Metrics, Benchmarks and various datasets for tasks like VQA, OCR and Image Captioning.

Subscribe to our Newsletter

Subscribe to our email newsletter to get the latest posts delivered right to your email.

Subscribe to receive the download link, receive updates, and be notified of bug fixes

Which email should I send you the download link?

 

Get Started with OpenCV

Subscribe To Receive

We hate SPAM and promise to keep your email address safe.​