102

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
  • 45,059
  • 106
  • 285
  • 459
  • 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

7 Answers7

117

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
  • 67,326
  • 35
  • 140
  • 172
  • 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
  • 9
    not works. AttributeError: module 'qrtools' has no attribute 'QR' – Saeed Mohtasham Jun 03 '18 at 12:17
  • 2
    @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
  • 5
    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
25

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)])]
Yuiq
  • 291
  • 3
  • 3
8

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
  • 506,650
  • 124
  • 909
  • 1,183
Somen Das
  • 101
  • 1
  • 4
7

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
  • 36,818
  • 81
  • 313
  • 561
4

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
  • 833
  • 4
  • 13
  • 32
  • 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
  • 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
3

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
  • 833
  • 4
  • 13
  • 32
0

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,572
  • 2
  • 22
  • 22