Why can't qrCodeDetector decode this QR code?

I’m working on an application that needs to decode QR codes found within photos. I have found that even if I use methods to isolate likely sub areas in the images that contain the QR code, qrCodeDetector still doesn’t work very reliably.

Here is a QR code cropped from a larger image that I can not seem to decode. My phone can decode it from the image on my monitor readily. Any insight as to why this is difficult to decode with qrCodeDetector, and any suggestions as to how to adjust the image to fix things, would be greatly appreciated.

QR

Here’s my code. Whether or not I threshold the image before detecting, detectAndDecode still returns an empty string in for decodedtext.

import cv2

img = cv2.imread('QR.jpg', cv2.IMREAD_GRAYSCALE)
ret, img2 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)

qrCodeDetector = cv2.QRCodeDetector()
decodedText, points, _ = qrCodeDetector.detectAndDecode(img2)
print(decodedText)

related:

Very related :slight_smile: A user there suggested I ask here.

Is it possible that QR code doesn’t have enough of a “quiet zone” around it? If that’s the problem, then maybe your phone’s QR reader is simply a bit more tolerant than OpenCV’s?

when I run that code on the picture you posted, I get an empty retval (instead of 73), but I get four points.

the detection code can probably not deal with such warped codes.

I don’t know if OpenCV’s QR decoder is a standalone implementation… I think it is. and it seems to not be terribly robust, compared to “industry standard” libraries specific to the purpose.

furas mentioned upscaling… that doesn’t inherently solve the issue. I tried this with NN and LINEAR and it failed to decode. with CUBIC, it happens to become decodable…

that’s pure luck. the sampling points happen to change such that it becomes marginally decodable.

basically, OpenCV has a basic QR decoder but it can’t handle your warped code.

if you absolutely had to handle warped codes, one could devise some method that assumes local smoothness and warps the sample grid bit by bit, so a sample is adjusted to land in the middle of a perceivable square. that’s R&D though.

this is probably a clean version of the original code, manually derived from the one successful decode I got, which had a few faulty squares:

image