Search code examples
python-3.xopencvqr-code

Reading a barcode using OpenCV QRCodeDetector


I am trying to use OpenCV on Python3 to create an image with a QR code and read that code back.

Here is some relevant code:

def make_qr_code(self, data):
    qr = qrcode.QRCode(
        version=2,
        error_correction=qrcode.constants.ERROR_CORRECT_H,
        box_size=10,
        border=4,
    )

    qr.add_data(data)
    return numpy.array( qr.make_image().get_image())

# // DEBUG
img = numpy.ones([380, 380, 3]) * 255
index = self.make_qr_code('Hello StackOverflow!')
img[:index.shape[0], :index.shape[1]][index] = [0, 0, 255]
frame = img
# // DEBUG

self.show_image_in_canvas(0, frame)
frame_mono = cv.cvtColor(numpy.uint8(frame), cv.COLOR_BGR2GRAY)
self.show_image_in_canvas(1, frame_mono) 

qr_detector = cv.QRCodeDetector()
data, bbox, rectifiedImage = qr_detector.detectAndDecode(frame_mono)
if len(data) > 0:
    print("Decoded Data : {}".format(data))
    self.show_image_in_canvas(2, rectifiedImage)
else:
    print("QR Code not detected")

(the calls to show_image_in_canvas are just for showing the images in my GUI so I can see what is going on).

When inspecting the frame and frame_mono visually, it looks OK to me

Left panel: <code>frame</code>, middle panel: <code>frame_mono</code>, right panel: reserved for detected QR Code

However, the QR Code Detector doesn't return anything (going into the else: "QR Code not detected").

There is literally nothing else in the frame than the QR code I just generated. What do I need to configure about cv.QRCodeDetector or what additional preprocessing do I need to do on my frame to make it find the QR code?


Solution

  • OP here; solved the problem by having a good look at the generated QR code and comparing it to some other sources.

    The problem was not in the detection, but in the generation of the QR codes. Apparently the array that qrcode.QRCode returns has False (or maybe it was 0 and I assumed it was a boolean) in the grid squares that are part of the code, and True (or non-zero) in the squares that are not.

    So when I did img[:index.shape[0], :index.shape[1]][index] = [0, 0, 255] I was actually creating a negative image of the QR code.

    When I inverted the index array the QR code changed from the image on the left to the image on the right and the detection succeeded.

    The faulty and correct QR code.

    In addition I decided to switch to the ZBar library because it's much better at detecting these codes under less perfect circumstances (like from a webcam image).