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!
27 Answers
You can try the following steps and code using qrtools:
Create a
qrcodefile, if not already existing- I used
pyqrcodefor doing this, which can be installed usingpip install pyqrcode And then use the code:
>>> import pyqrcode >>> qr = pyqrcode.create("HORN O.K. PLEASE.") >>> qr.png("horn.png", scale=6)
- I used
Decode an existing
qrcodefile usingqrtools- Install
qrtoolsusingsudo 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.'
- Install
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
PyPNGusingpip install pypngfor usingpyqrcode In case you have
PILinstalled, you might getIOError: decoder zip not available. In that case, try uninstalling and reinstallingPILusing:pip uninstall PIL pip install PILIf that doesn't work, try using
Pillowinsteadpip uninstall PIL pip install pillow
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)])] 1I 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") 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:
Install it with
pip install zbar-0.10-cp27-none-win_amd64.whlIf Python reports an
ImportError: DLL load failed: The specified module could not be found.when doingimport zbar, then you will just need to install the Visual C++ Redistributable Packages for VS 2013 (I spent a lot of time here, trying to recompile unsuccessfully...)Required too: libzbar64-0.dll must be in a folder which is in the PATH. In my case I copied it to "C:\Python27\libzbar64-0.dll" (which is in the PATH). If it still does not work, add this:
import os os.environ['PATH'] += ';C:\\Python27' import zbar
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.
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: 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)
3For Windows using ZBar
Pre-requisites:
- Install ZBar by either:
- Install Chocolatey and
choco install zbar - Or use Windows Installer for ZBar
- Install Chocolatey and
pip install pyzbar
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:
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))