114

TL;DR: I need a way to decode a QR-code from an image file using (preferable pure) Python.

I've got a jpg file with a QR-code which I want to decode using Python. I've found a couple libraries which claim to do this:

PyQRCode (website here) which supposedly can decode qr codes from images by simply providing a path like this:

import sys, qrcode
d = qrcode.Decoder()
if d.decode('out.png'):
    print 'result: ' + d.result
else:
    print 'error: ' + d.error

So I simply installed it using sudo pip install pyqrcode. The thing I find strange about the example code above however, is that it only imports qrcode (and not pyqrcode though) Since I think qrcode refers to this library which can only generate qr-code images it kind of confused me. So I tried the code above with both pyqrcode and qrcode, but both fail at the second line saying AttributeError: 'module' object has no attribute 'Decoder'. Furthermore, the website refers to Ubuntu 8.10 (which came out more than 6 years ago) and I can't find a public (git or other) repository of it to check the latest commit. So I moved on to the next library:

ZBar (website here) claims to be "an open source software suite for reading bar codes from various sources, such as image files." So I tried installing it on Mac OSX running sudo pip install zbar. This fails with error: command 'cc' failed with exit status 1. I tried to suggestions in the answers to this SO question, but I can't seem to solve it. So I decided to move on again:

QRTools, which according to this blogpost can decode images easily by using the following code:

from qrtools import QR
myCode = QR(filename=u"/home/psutton/Documents/Python/qrcodes/qrcode.png")
if myCode.decode():
  print myCode.data
  print myCode.data_type
  print myCode.data_to_string()

So I tried installing it using sudo pip install qrtools, which can't find anything. I also tried it with python-qrtools, qr-tools, python-qrtools and a couple more combinations, but unfortunately to no avail. I suppose it refers to this repo which says it is based on ZBar (see above). Although I want to run my code on Heroku (and thus prefer a pure Python solution) I successfully installed it on a Linux box (with sudo apt-get install python-qrtools) and tried running it:

from qrtools import QR
c = QR(filename='/home/kramer65/qrcode.jpg')
c.data  # prints u'NULL'
c.data_type  # prints u'text'
c.data_to_string()  # prints '\xef\xbb\xbfNULL' where I expect an int (being `1234567890`)

Although this seems to decode it, It doesn't seem to do it correctly. It furthermore needs ZBar and is thus not pure Python. So I decided to find yet another library.

PyXing (website here) is supposedly a Python port of the popular Java ZXing library, but the initial and only commit is 6 years old and the project has no readme or documentation whatsoever.

For the rest I found a couple qr-encoders (not decoders) and some API endpoints which can decode for you. Since I don't like this service to be dependent on other API endpoints I would want to keep the decoding local though.

So to conclude; would anybody know how I can decode QR-codes from images in (preferable pure) Python? All tips are welcome!

Community
  • 1
  • 1
kramer65
  • 50,427
  • 120
  • 308
  • 488
  • It should be: 'if myCode.decode("/home/kramer65/qrcode.jpg")' and not 'QR(filename='/home/kramer65/qrcode.jpg')' – Dmitry Chichkov Apr 20 '16 at 21:09
  • I feel it is worth mentioning a follow-up question posed by **@kramer65** about installing `zbar` with `pip`: http://stackoverflow.com/questions/27406641/how-to-install-python-bindings-originating-from-an-apt-package – Ian Jun 01 '16 at 18:09

9 Answers9

121

You can try the following steps and code using qrtools:

  • Create a qrcode file, if not already existing

    • I used pyqrcode for doing this, which can be installed using pip install pyqrcode
    • And then use the code:

      >>> import pyqrcode
      >>> qr = pyqrcode.create("HORN O.K. PLEASE.")
      >>> qr.png("horn.png", scale=6)
      
  • Decode an existing qrcode file using qrtools

    • Install qrtools using sudo apt-get install python-qrtools
    • Now use the following code within your python prompt

      >>> import qrtools
      >>> qr = qrtools.QR()
      >>> qr.decode("horn.png")
      >>> print qr.data
      u'HORN O.K. PLEASE.'
      

Here is the complete code in a single run:

In [2]: import pyqrcode
In [3]: qr = pyqrcode.create("HORN O.K. PLEASE.")
In [4]: qr.png("horn.png", scale=6)
In [5]: import qrtools
In [6]: qr = qrtools.QR()
In [7]: qr.decode("horn.png")
Out[7]: True
In [8]: print qr.data
HORN O.K. PLEASE.

Caveats

  • You might need to install PyPNG using pip install pypng for using pyqrcode
  • In case you have PIL installed, you might get IOError: decoder zip not available. In that case, try uninstalling and reinstalling PIL using:

    pip uninstall PIL
    pip install PIL
    
  • If that doesn't work, try using Pillow instead

    pip uninstall PIL
    pip install pillow
    
Community
  • 1
  • 1
Anshul Goyal
  • 73,278
  • 37
  • 149
  • 186
  • 1
    Hi mu 無, thanks for your answer. Although qrtools requires zbar and is thus not pure python, it does indeed work now. The main problem is now that I need to install the zbar python binding on heroku, about which I asked a question here: http://stackoverflow.com/questions/27406641/how-to-install-python-bindings-originating-from-an-apt-package . I'm going to accept your answer, but I would greatly appreciate if you also have a look at my other question so that I can solve running qrtools on heroku. Thanks a million! – kramer65 Dec 10 '14 at 17:03
  • @kramer65 Unfortunately, I don't have much experience with heroku, so am not sure how packages are installed there... – Anshul Goyal Dec 10 '14 at 18:21
  • 3
    This does not work, gives Exception: tostring() has been removed. – BhishanPoudel Oct 01 '16 at 16:42
  • @Bhishan might be a case where newer packages give the error, ask a new question and share a link here ... – Anshul Goyal Oct 01 '16 at 18:26
  • 2
    @BhishanPoudel I encountered this as well. It seems the bug has been fixed and should appear in the next release. For anyone encountering this, you can edit line 181 of /usr/lib/python2.7/dist-packages/qrtools.py (location may vary) and replace "tostring" with "tobytes". It's running nicely for me now. – jonthalpy Oct 02 '16 at 22:40
  • 11
    not works. AttributeError: module 'qrtools' has no attribute 'QR' – Saeed Mohtasham Jun 03 '18 at 12:17
  • 3
    @SaeedMohtasham try `from qrtools import qrtools` – Krenair Jun 21 '18 at 01:57
  • 1
    @mu-無 Hi, on `qr.decode('myPicture.png')`, I get an `AttributeError: module 'zbar' has no attribute 'ImageScanner'` error, any idea ? – SebMa Jun 26 '18 at 14:29
  • 7
    No module named zbar when importing qrtools – Crazy-Kaleidoscope-7 Mar 15 '19 at 10:07
  • Note from 2021 - qrtools does not support python3, since its dependency zbar does not support python3. Use the solution with pyzbar+PIL instead. – Daniel Kats Jul 23 '21 at 17:01
  • Strictly speaking this flow uses a bunch of more or less outdated libraries. What would be nice is to have a reverse version of libZint, which can decode barcodes depending on the pattern. Given the specification (ISO), it should be possible to do in pure Python using a single image reader library only. – MyICQ Feb 14 '23 at 13:45
35

The following code works fine with me:

brew install zbar
pip install pyqrcode
pip install pyzbar

For QR code image creation:

import pyqrcode
qr = pyqrcode.create("test1")
qr.png("test1.png", scale=6)

For QR code decoding:

from PIL import Image
from pyzbar.pyzbar import decode
data = decode(Image.open('test1.png'))
print(data)

that prints the result:

[Decoded(data=b'test1', type='QRCODE', rect=Rect(left=24, top=24, width=126, height=126), polygon=[Point(x=24, y=24), Point(x=24, y=150), Point(x=150, y=150), Point(x=150, y=24)])]
Yuqi
  • 391
  • 4
  • 4
13

I found a new and effective way, just using cv2. The code below will decode a QR code.

import cv2
# Name of the QR Code Image file
filename = "attandence_Record_QR_code.png"
# read the QRCODE image
image = cv2.imread(filename)
# initialize the cv2 QRCode detector
detector = cv2.QRCodeDetector()
# detect and decode
data, vertices_array, binary_qrcode = detector.detectAndDecode(image)
# if there is a QR code
# print the data
if vertices_array is not None:
  print("QRCode data:")
  print(data)
else:
  print("There was some error") 
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
Somen Das
  • 366
  • 2
  • 7
  • can;t decode image like tinyurl.com/cv2qrerr – CS QGB Aug 13 '22 at 17:51
  • I can't see the error your link is down. This code works most of the times. And an future update of cv2 can help you. – Somen Das Aug 13 '22 at 17:58
  • 1
    @CSQGB i found your problem, in your image it don't have any white edge background that's why it cannot be detected,after i do some GIMP (Linux Photoshop ) i got the result, – Somen Das Feb 21 '23 at 15:25
  • This is a superb answer, it works flawlessly on Windows. – Sam Feb 21 '23 at 19:22
8

I'm answering only the part of the question about zbar installation.

I spent nearly half an hour a few hours to make it work on Windows + Python 2.7 64-bit, so here are additional notes to the accepted answer:

PS: Making it work with Python 3.x is even more difficult: Compile zbar for Python 3.x.

PS2: I just tested pyzbar with pip install pyzbar and it's MUCH easier, it works out-of-the-box (the only thing is you need to have VC Redist 2013 files installed). It is also recommended to use this library in this pyimagesearch.com article.

Basj
  • 41,386
  • 99
  • 383
  • 673
6

There is a library called BoofCV which claims to better than ZBar and other libraries.
Here are the steps to use that (any OS).

Pre-requisites:

  • Ensure JDK 14+ is installed and set in $PATH
  • pip install pyboof

Class to decode:

import os
import numpy as np
import pyboof as pb

pb.init_memmap() #Optional

class QR_Extractor:
    # Src: github.com/lessthanoptimal/PyBoof/blob/master/examples/qrcode_detect.py
    def __init__(self):
        self.detector = pb.FactoryFiducial(np.uint8).qrcode()
    
    def extract(self, img_path):
        if not os.path.isfile(img_path):
            print('File not found:', img_path)
            return None
        image = pb.load_single_band(img_path, np.uint8)
        self.detector.detect(image)
        qr_codes = []
        for qr in self.detector.detections:
            qr_codes.append({
                'text': qr.message,
                'points': qr.bounds.convert_tuple()
            })
        return qr_codes

Usage:

qr_scanner = QR_Extractor()
output = qr_scanner.extract('Your-Image.jpg')
print(output)

Tested and works on Python 3.8 (Windows & Ubuntu)

Gokul NC
  • 1,111
  • 4
  • 17
  • 39
  • This is the correct answer for original question : A Pure Python library for QR-Code scanning. All other answers required external library setups. Tested on macOS in a virtualenv with Python3.8.4. – NightFury13 Feb 20 '21 at 08:03
  • 3
    It seems to be trying to call java: jar_path = os.path.join(os.path.dirname(jar_path),"PyBoof-all.jar") So not really pure Python ... – havlock Mar 27 '21 at 18:49
  • No pure python-based QR decoder would be fast enough for real-time. Even OpenCV-Python runs on a C++-core – Gokul NC Mar 28 '21 at 10:54
  • I get " File "C:\pythonProject\qrcode\venv\lib\site-packages\pyboof\common.py", line 179, in mmap_array_java_to_python mm.seek(0) AttributeError: 'NoneType' object has no attribute 'seek'. – Rony Tesler Jul 05 '23 at 22:27
  • Please [raise an issue in the PyBoof repo](https://github.com/lessthanoptimal/PyBoof/issues). – Gokul NC Jul 10 '23 at 08:29
3

In 2022 using Python 3 this is what worked for me.

Step 1: Install the zbar library

macOS:

brew install zbar

If you get an 'Unable to find zbar shared library' ImportError then do:

mkdir ~/lib
ln -s $(brew --prefix zbar)/lib/libzbar.dylib ~/lib/libzbar.dylib

Ubuntu/Debian Linux:

sudo apt-get update
sudo apt-get install zbar-tools

Windows:

According to the pyzbar project page: Install "Visual C++ Redistributable Packages for Visual Studio 2013. Install vcredist_x64.exe if using 64-bit Python, vcredist_x86.exe if using 32-bit Python."

Step 2: Install the PIP Python packages

pip3 install opencv-python
pip3 install pyzbar

Step 3: Create a Python script

Create a .py script and run the following:

import cv2 as cv
from pyzbar.pyzbar import decode

qrcode_img = 'path/to/qrcode/img.png'
img = cv.imread(qrcode_img)
decoded_data = decode(img)

# parse the decoded zbar data
url = decoded_data[0].data.decode()
print(f'URL: {url}')
Benji
  • 310
  • 3
  • 12
2

For Windows using ZBar

Pre-requisites:

To decode:

from PIL import Image
from pyzbar import pyzbar

img = Image.open('My-Image.jpg')
output = pyzbar.decode(img)
print(output)

Alternatively, you can also try using ZBarLight by setting it up as mentioned here:
https://pypi.org/project/zbarlight/

Gokul NC
  • 1,111
  • 4
  • 17
  • 39
1

PyBoof is a wrapper around BoofCV and has an easy to use QR Code reader. It also give you access to a ton of information about the QR, e.g. number of bit errors, precise location, raw message, ...

image = pb.load_single_band(data_path, np.uint8)

detector = pb.FactoryFiducial(np.uint8).qrcode()
detector.detect(image)

for qr in detector.detections:
    print("Message: " + qr.message)
    print("     at: " + str(qr.bounds))
lessthanoptimal
  • 2,722
  • 2
  • 23
  • 25
1

first intsall pip install pyzbar

then:

import cv2 as cv
from pyzbar.pyzbar import decode
     img=cv.imread('/path/img.jpg')
     objs=decode(img)
     for obj in objs:
         print('data: ', obj) 
Max
  • 4,152
  • 4
  • 36
  • 52