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
Step 3: Understanding the structure of a barcode / QR code
A barcode / QR code object returned by ZBar has three fields
- 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
- 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.
- 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.

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.
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
Great post as always! Would be nice if some visuals were included too for some steps, for ex, to show the result of the convex hull.
Hi Jatin,
Thanks. The result of the convex hull is basically the rectangle you see in blue.
Satya
Hi Satya,
I tried Zbar with C# but after adding nuget package of zbar, i am getting exception at Time of creating New Image Scanner object, That exception is ” Unable to load DLL ‘libzbar-0’: The specified module could not be found. (Exception from HRESULT: 0x8007007E)”, how i can solve this
Hello Sir, I am getting this error while running the python(3.6) code. Please take a look.
in line 23, in display
points = decodedObject.location
AttributeError: ‘Decoded’ object has no attribute ‘location’
Can you tell me what i am doing wrong?
Did you install using the github pull request I suggested? If not, pyzbar does not support location.
Hi, I can’t log into the forum. Can any one help? When I tried lost passwd link but it says my email is not matched. But I have no issue to log into the course.
Hi Han,
The forum is only part of the paid course. If you have taken the course, please send me an email [email protected] so we can investigate.
Satya
Of course, I am enrolled in the paid course. And I also sent you email, but got no response and it might be ended at your spam box. Still waiting for support.
Sent you email. Sorry for the inconvenience.
Thank you, now I got access to it.
Hello Sir, What exactly gives in location information of qr code using ZBar ? It is image co-ordinate or what?
How can i find the location of qr code corners in terms of depth( (x,y,z ) or in world co-ordinate)?
I want to find the the distance between camera to qr code.
You cannot find the distance without knowing the camera intrinsic parameters ( most importantly the focal length ).
Hello, I have an error when I tried to install “pip install git+git://github.com/globophobe/[email protected]”
Error [WinError 2] . . . while executing command git clone -q git://github.com/globophobe/pyzbar.git C:UsersAdminAppDataLocalTemppip-uaw5deel-build
Cannot find command ‘git’.
I have not used Windows in a very long time and am not sure how git works on windows. But you need git ( version control ) installed.
if you find error after typing sudo apt-get install libzbar-dev libzbar0.
you can try: sudo apt-get install zbar-tools
Thanks!
do you know if pyzbar current version (0.1.5 3/18/2018) supports location?
It looks like the branch has been merged in the latest repo. Will it checkout to see in a day or two.
yes. pip install pyzbar will install 0.1.7.
Hi
thank you for your great post !!
It works correctly for picture only show bar code
but Is this code (c++ code) can apply on my webcam to detect Bar code and QR code
I have tried to take pic in main like that
VideoCapture cap(0);
for(;;){
Mat frame;
cap>>frame;
……..
and I use frame instead of im at the rest of code , but it didn’t work.
any help please ?? 🙁
Yes, you can use this on a webcam frame. Make sure the lighting is good and there is no motion blur.
Yeah , I check all of that and the output is a small black rectangle without show anything ? 🙁
Ok, I will try to put together a video demo. Give me some time.
Thank you very much 🙂
I am waiting for you
As more stores try to go cashier-less, I think this tech is gaining more interest.
When I record a video source and run zbar or pyzbar (using your source scripts as starters) the decode of the data seems to work most of the time (assuming good lighting, steady camera – no motion blur), but the drawing of the locations (points) seems to vary quite a bit for barcodes. I thought the display drawing would always resemble a rectangle, but I am seeing all types of shapes and sizes and sometimes plain horizontal lines…??? https://uploads.disquscdn.com/images/77524688e1747e3e691407775481efa822e199a4d976e23bf7fb768f3036492c.png
Strange indeed. I will check this and report in a couple of days. Thanks for pointing out.
I noticed the latest pyzbar now uses rects and polygons to represent location information. I referenced bounding_box_and_polygon.py and read_zbar.py files from pyzbar github site.
I modified my original code to reflect the latest changes to the pyzbar (0.1.7) package. The code is working well with video and rectangular barcodes on ubuntu 16 (py27). I still need to validate with QR code to make sure they display correctly (e.g. rectangle vs polygon).
————————————————————————————-
from __future__ import print_function
import numpy as np
import cv2
import sys
import pyzbar.pyzbar as pyzbar
from pyzbar.pyzbar import decode
def decode_barcode(im) :
# Find barcodes and QR codes
decodedObjects = decode(im)
# Print results
for obj in decodedObjects:
print(‘Type : ‘, obj.type)
print(‘Data : ‘, obj.data)
return decodedObjects
# Display barcode and QR code location
def display(im, decodedObjects):
# Loop over all decoded objects
for decodedObject in decodedObjects:
print(‘decodedObject.Type : ‘, decodedObject.type)
print(‘decodedObject.Data : ‘, decodedObject.data)
rect = decodedObject.rect
print (“left: ” + str(rect.left))
print (“top: ” + str(rect.top))
print (“width: ” + str(rect.width))
print (“height: ” + str(rect.height))
startX = rect.left
startY = rect.top
endX = (rect.left + rect.width)
endY = (rect.top + rect.height)
cv2.rectangle(im, (startX, startY), (endX, endY), (0, 255, 0), 3)
return im
# Main
if __name__ == ‘__main__’:
# Read image
im = cv2.imread(‘/home/nvidia/pyzbar/pyzbar/tests/code128.png’)
decodedObjects = decode_barcode(im)
im = display(im, decodedObjects)
cv2.imshow(“Results”, im);
cv2.waitKey(0);
Here is my latest code script which includes support for barcodes and qrcodes (polygons). Note – I am using cv2.polylines. I need to push this code to my github at some point. I’m not sure if this blog site preserves spaces in the code formatting…
————————————————-
from __future__ import print_function
import numpy as np
import cv2
import sys
import pyzbar.pyzbar as pyzbar
from pyzbar.pyzbar import decode
def decode_barcode(im) :
# Find barcodes and QR codes
decodedObjects = decode(im)
# Print results
for obj in decodedObjects:
print(‘Type : ‘, obj.type)
print(‘Data : ‘, obj.data)
return decodedObjects
# Display barcode and QR code location
def display(im, decodedObjects):
# Loop over all decoded objects
for decodedObject in decodedObjects:
print(‘decodedObject.Type : ‘, decodedObject.type)
print(‘decodedObject.Data : ‘, decodedObject.data)
rect = decodedObject.rect
print (“left: ” + str(rect.left))
print (“top: ” + str(rect.top))
print (“width: ” + str(rect.width))
print (“height: ” + str(rect.height))
startX = rect.left
startY = rect.top
endX = (rect.left + rect.width)
endY = (rect.top + rect.height)
cv2.rectangle(im, (startX, startY), (endX, endY), (255, 0, 0), 3)
points = decodedObject.polygon
print (“len(points): ” + str(len(points)))
for pt in points:
print(“ptx: ” + str(pt.x))
print(“pty: ” + str(pt.y))
pts = np.array([point for point in points], np.int32)
hull = cv2.convexHull(np.array([point for point in points]))
hull = map(tuple, np.squeeze(hull))
# Number of points in the convex hull
n = len(hull)
print(“len(hull): ” + str(len(hull)) )
# Draw the convex hull
#for j in xrange(0,n):
#cv2.line(im, hull[j], hull[ (j+1) % n], (255,0,0), 3) #this also works
pts = pts.reshape((-1,1,2))
cv2.polylines(im,[pts],True,(0,255,0),3)
return im
# Main
if __name__ == ‘__main__’:
# Read image
#im = cv2.imread(‘/home/nvidia/pyzbar/pyzbar/tests/code128.png’)
#im = cv2.imread(‘/home/nvidia/pyzbar/pyzbar/tests/qrcode.png’)
im = cv2.imread(‘/home/nvidia/pyzbar/pyzbar/tests/qrcode_rotated.png’)
decodedObjects = decode_barcode(im)
im = display(im, decodedObjects)
cv2.imwrite(“/home/nvidia/cviz/learnopencv/barcode-QRcodeScanner/barcode-scanner-out.png”,im)
cv2.imshow(“Results”, im);
cv2.waitKey(0);
https://uploads.disquscdn.com/images/3b257d95061d56959fe055a6972859901d6699e2fcf3301e5c50a5d4cf701d1c.png
hey kaisar i ran your program but it shows syntax error like this(expected an indented block)
Replace waitKey(0) by
int k=waitKey(10);
if(k==27)
{
destroyAllWindows();
return 0;
}
Hello, I would like to simply get the code read by the zbar and paste it into the active field by the mouse cursor. Is there such a possibility?
Yes, sure. You just need to know how to get that information from zbar’s output to whatever GUI library you are using.
Please let me know the install command equivalent on Linux since the command above works on ubuntu, but not on linux.
which linux distro do you have? Ubuntu is linux.
Thank you so much Satya, terrific work. Can you please show us how to install Zbar with pdf417 enabled so we can scan those barcodes as well. Much appreciated.
I don’t think zbar supports it.You may have to try zxing https://github.com/zxing/zxing or LEAD Tools PDF417 ( https://www.leadtools.com/sdk/barcode/2d-pdf417 )
how do i download zbar because i am a bit of a beginer and i don’t really understand any of the instructions (i am using python 3). i don’t know if it is because i don’t have zbar but when i enter your code into python it doesn’t seem to recognise any of the imports.
Did you try `
“`
pip install zbar
pip install pyzbar
“`
i wasn’t sure where to type it, i have tried it in python and python idle
m using python 3.7 and the downloaded code is using zbar..
and zbar.ImageScanner() is giving me validation error
Do you know if its possible to test images with resolutions over 2000×2000? (not the qrcode itself but whole image, qrcode+otherparts)
Why not? Are you facing any issues?
Yes, I have tried with 2000×2000 image (with qrcode size around 1000×1000 pixels) all were fine. then made a slightly larger crop from same main image (2100×2100), this one failed. I will use high DPI scans to extract qrcode, thats why I need to be able to render larger images.
edit. Forgot to tell, I am actually using Kaisar Khatak’s code, found within comments, to get the exact corners of qrcode. Receiving following error, with larger files;
local variable ‘points’ referenced before assignment
I am trying to get the C++ code working and reading a barcode. I have converted an image to greyscale, the image has once EAN13 code in it and scan returns 0. Are you able to offer any advice?
Hi David,
Zbar supports EAN-13
http://zbar.sourceforge.net/
Check if one of the following apply
1. Blurry image
2. low resolution
3. bad lighting
Are you able to post your image here?
Hi,
Thanks for post code is working fine for few images, but also getting wrong values in few cases, like for the image I posted, should I add any additional things, how can I get this?
The result I got is :
Type : EAN13
Data : b’0000000000000′
Type : EAN13
Data : b’5572106000000′
https://uploads.disquscdn.com/images/da0cfa91284877834a5be04d064cd4b73039c4f4701f8e827148d387ed6840c4.png
Thanks Satya for this great tutorial. What would you suggest I use to read the metadata from the barcode? For example if we scan a book barcode and we have the data about the book stored, I want to be able to get the metadata so I know which book was scanned. Or should I store the barcode for each book and do an image matching/comparison?