Как расшифровать изображение QR-кода в (желательно чистом) Python?

86

TL; DR : мне нужен способ декодирования QR-кода из файла изображения с использованием (предпочтительно чистого) Python.

У меня есть файл jpg с QR-кодом, который я хочу декодировать с помощью Python. Я нашел пару библиотек, которые утверждают, что это делают:

PyQRCode ( веб-сайт здесь ), который предположительно может декодировать qr-коды из изображений, просто указав такой путь:

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!

kramer65
источник
It should be: 'if myCode.decode("/home/kramer65/qrcode.jpg")' and not 'QR(filename='/home/kramer65/qrcode.jpg')'
Dmitry Chichkov
I feel it is worth mentioning a follow-up question posed by @kramer65 about installing zbar with pip: stackoverflow.com/questions/27406641/…
Ian

Ответы:

108

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
    
mu 無
источник
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: stackoverflow.com/questions/27406641/… . 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
3
This does not work, gives Exception: tostring() has been removed.
Bhishan Poudel
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
5
not works. AttributeError: module 'qrtools' has no attribute 'QR'
Saeed Mohtasham
1
@SaeedMohtasham try from qrtools import qrtools
Krenair
9

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
источник
for the above solution to work, u also need to run pip install pypng && pip install image
asad_hussain
6

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
источник
0

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
источник
0

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
источник