Robust and Straight-Forward solution for reading difficult and tricky QR codes within images in Python. Supported by a YOLOv7 QR Detection model.
Project description
QReader
QReader is a Robust and Straight-Forward solution for reading difficult and tricky QR codes within images in Python. Powered by a YOLOv7 model.
Behind the scenes, the library is composed by two main building blocks: A QR Detector based on a YOLOv7 model trained on a large dataset of QR codes (also offered as stand-alone), and the Pyzbar QR Decoder. On top of Pyzbar, QReader transparently applyes different image preprocessing techniques that maximize the decoding rate on difficult images.
Installation
To install QReader, simply run:
pip install qreader
If you're not using Windows, you may need to install some additional pyzbar dependencies:
On Linux:
sudo apt-get install libzbar0
On Mac OS X:
brew install zbar
NOTE: If you're running QReader in a server with very limited resources, you may want to install the CPU version of PyTorch, before installing QReader. To do so, run: pip install torch --no-cache-dir
(Thanks to @cjwalther for his advice).
Usage
QReader is a very simple and straight-forward library. For most use cases, you'll only need to call detect_and_decode
:
from qreader import QReader
import cv2
# Create a QReader instance
qreader = QReader()
# Get the image that contains the QR code (QReader expects an uint8 numpy array)
image = cv2.cvtColor(cv2.imread("path/to/image.png"), cv2.COLOR_BGR2RGB)
# Use the detect_and_decode function to get the decoded QR data
decoded_text = qreader.detect_and_decode(image=image)
detect_and_decode
will return a tuple
containing the decoded string of every QR found in the image.
NOTE: Some entries can be None
, it will happen when a QR have been detected but couldn't be decoded.
API Reference
QReader.detect_and_decode(image, return_bboxes = False)
This method will decode the QR codes in the given image and return the decoded strings (or None, if any of them could be detected but not decoded).
-
image
: np.ndarray. NumPy Array containing theimage
to decode. The image is expected to be inuint8
format [HxWxC], RGB. -
return_bboxes
: boolean. IfTrue
, it will also return the bboxes of each detected QR. Default:False
-
Returns: tuple[str | None] | tuple[tuple[tuple[int, int, int, int], str | None]]: A tuple with all detected QR codes decodified. If
return_bboxes
isFalse
, the output will look like:('Decoded QR 1', 'Decoded QR 2', None, 'Decoded QR 4', ...)
. Ifreturn_bboxes
isTrue
it will look like:(((x1_1, y1_1, x2_1, y2_1), 'Decoded QR 1'), ((x1_2, y1_2, x2_2, y2_2), 'Decoded QR 2'), ...)
.
QReader.detect(image)
This method detects the QR codes in the image and returns the bounding boxes surrounding them in the format (x1, y1, x2, y2).
-
image
: np.ndarray. NumPy Array containing theimage
to decode. The image must is expected to be inuint8
format [HxWxC], RGB. -
Returns: tuple[tuple[int, int, int, int]]. The bounding boxes of the QR code in the format
((x1_1, y1_1, x2_1, y2_1), (x1_1, y1_1, x2_1, x2_2))
.
NOTE: This the only function you will need? Take a look at QRDet.
QReader.decode(image, bbox = None)
This method decodes a single QR code on the given image, if a bbox
is given (recommended) it will only look within that delimited region.
Internally, this method will run the pyzbar decoder, using different image preprocessing techniques (sharpening, binarization, blurring...) every time it fails to increase the detection rate.
-
image
: np.ndarray. NumPy Array containing theimage
to decode. The image must is expected to be inuint8
format [HxWxC], RGB. -
bbox
: tuple[int, int, int, int] | None. The bounding box of the QR code in the format (x1, y1, x2, y2) [that's the output ofdetect
]. IfNone
, it will look for the QR code in the whole image (not recommended). Default:None
. -
Returns: str. The decoded text of the QR code. If no QR code can be decoded, it will return
None
.
Usage Tests
The following code will try to decode these images containing QRs with QReader, pyzbar and OpenCV.
from qreader import QReader
from cv2 import QRCodeDetector, imread
from pyzbar.pyzbar import decode
# Initialize the three tested readers (QRReader, OpenCV and pyzbar)
qreader_reader, cv2_reader, pyzbar_reader = QReader(), QRCodeDetector(), decode
for img_path in ('test_mobile.jpeg', 'test_draw_64x64.jpeg'):
# Read the image
img = imread(img_path)
# Try to decode the QR code with the three readers
qreader_out = qreader_reader.detect_and_decode(image=img)
cv2_out = cv2_reader.detectAndDecode(img=img)[0]
pyzbar_out = pyzbar_reader(image=img)
# Read the content of the pyzbar output (double decoding will save you from a lot of wrongly decoded characters)
pyzbar_out = tuple(out.data.data.decode('utf-8').encode('shift-jis').decode('utf-8') for out in pyzbar_out)
# Print the results
print(f"Image: {img_path} -> QReader: {qreader_out}. OpenCV: {cv2_out}. pyzbar: {pyzbar_out}.")
The output of the previous code is:
Image: test_mobile.jpeg -> QReader: ('https://github.com/Eric-Canas/QReader'). OpenCV: . pyzbar: ().
Image: test_draw_64x64.jpeg -> QReader: ('https://github.com/Eric-Canas/QReader'). OpenCV: . pyzbar: ().
Note that QReader internally uses pyzbar as decoder. The improved detection-decoding rate that QReader achieves comes from the combination of different image pre-processing techniques and the YOLOv7 based QR detector that is able to detect QR codes in harder conditions than classical Computer Vision methods.
Acknowledgements
This library is based on the following projects:
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.