Python OpenCV: Detecting and Decoding a QRCode

In this tutorial we will learn how to detect and decode a QR Code on an image, using Python and OpenCV.

Introduction

In this tutorial we will learn how to detect and decode a QR Code on an image, using Python and OpenCV.

This tutorial was tested with version 4.0.0 of OpenCV and version 3.7.2 of Python.

The Code

We will start by importing the cv2 module.

import cv2

After that we will read an image with a QR code from the file system, so we can later decode it.

You can use this online tool to generate a QR code with a text of your choice. In my case, the QR Code I’ll generate will contain the text “TechTutorialsX!“.

I’ve downloaded the generated QR Code and added some text above in an image editor, just to add some more content to the image. You can check below in figure 1 the image used in the test.

Image used in the tests
Figure 1 – Image used in the tests.

After that we will read the image with a call to the imread function from the cv2 module. As input we need to pass the path to the file, as a string.

image = cv2.imread('C:/Users/N/Desktop/testQRCode.png')

After that we will create an object of class QRCodeDetector, which we will use for detecting and decoding the QR Code.

qrCodeDetector = cv2.QRCodeDetector()

Followed by that we will call the detectAndDecode method on this object, passing as input the image where we want to detect the QR Code.

This method returns a tuple of values, by the following order:

  • Decoded text [1]. It is an empty string if the QR Code is not found.
  • Output array of vertices of the found QR code. It will be empty if not found [1].
  • Optional output image containing the rectified and binarized QR Code [1]. We won’t make use of it in this tutorial.
decodedText, points, _ = qrCodeDetector.detectAndDecode(image)

Note that the _ is a simple convention for ignoring the third returned value which, as we have mentioned before, we won’t use.

Since there might be cases where there is no QR Code in the image, we will do a check on the returned points. If there are no points, it means no QR Code was not found in the image.

if points is not None:
    # QR Code detected handling code

else:
    print("QR code not detected")

Assuming that a QR Code was detected, we will then draw lines delimiting it, using the array of vertices returned by the detectAndDecode method.

We will simply get the length of the array and iterate by each vertex, connecting it to the one immediately after. Note that the last vertex from the array should connect with the first, to close the shape around the QR Code.

We can draw a line in an image by calling the line function from the cv2 module. You can check in more detail how to do it here.

In short, as already mentioned, we call the line function passing the following inputs:

  • image: the image on which we will draw the line.
  • point 1: first point of the line. It is specified as a tuple with the x and y coordinates.
  • point 2: second point of the line. It is specified as a tuple with the x and y coordinates.
  • color: color of the line. This is defined as a tuple with the 3 colors in the BGR format. We will set it to blue.
  • thickness: thickness of the line, specified in pixels. We will set it to 5 px.

Note that, when passing the points from the vertices array, we need to convert them to tuples.

nrOfPoints = len(points)

for i in range(nrOfPoints):
    nextPointIndex = (i+1) % nrOfPoints
    cv2.line(image, tuple(points[i][0]), tuple(points[nextPointIndex][0]), (255,0,0), 5)

After this we will print the decoded text from the QR Code and then display the image. The image should now show the QR Code with blue lines around its shape.

print(decodedText)    

cv2.imshow("Image", image)
cv2.waitKey(0)
cv2.destroyAllWindows()

The final code can be seen below.

import cv2

image = cv2.imread('C:/Users/N/Desktop/testQRCode.png')

qrCodeDetector = cv2.QRCodeDetector()

decodedText, points, _ = qrCodeDetector.detectAndDecode(image)

if points is not None:

    nrOfPoints = len(points)

    for i in range(nrOfPoints):
        nextPointIndex = (i+1) % nrOfPoints
        cv2.line(image, tuple(points[i][0]), tuple(points[nextPointIndex][0]), (255,0,0), 5)

    print(decodedText)    

    cv2.imshow("Image", image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

else:
    print("QR code not detected")

Testing the code

To test the code, simply run it with a tool of your choice. I’m using IDLE, a Python IDE.

You should obtain a result similar to figure 2. As can be seen, the blue lines are drown around the QR Code shape and the text encoded on it was printed to the Python prompt.

Output of the program, with the decoded QR Code text.
Figure 2 – Output of the program, with the decoded QR Code text.

References

[1] https://docs.opencv.org/4.0.0/de/dc3/classcv_1_1QRCodeDetector.html#a7290bd6a5d59b14a37979c3a14fbf394

Leave a Reply