'QR Code Detection from Pyzbar with Camera Image

I am having trouble detecting QR code using Pyzbar. Under perfection condition, I am able to detect the QR code using the original png image. However, when I do video capture from a camera, and then save that frame as in image, pyzbar fails to detect the QR code.

For example, this works

enter image description here

[Decoded(data=b'GOAL', type='QRCODE', rect=Rect(left=16, top=16, width=168, height=168))]

But the following does not even after I manually cropped the surroundings to only show the QR code.

enter image description here

[]

For both of the images, I am using

decode(image, scan_locations=True)

I am wondering what do I need to do in order for pyzbar to decode my QR code image?



Solution 1:[1]

Used OpenCV to threshold the image to black-in-white then pyzbar is able to decode the QR code.

Firstly, threshold the image with the code below.

from pyzbar import pyzbar
import argparse
import numpy as np
import cv2

image =cv2.imread("QRCode.png")

# thresholds image to white in back then invert it to black in white
#   try to just the BGR values of inRange to get the best result
mask = cv2.inRange(image,(0,0,0),(200,200,200))
thresholded = cv2.cvtColor(mask,cv2.COLOR_GRAY2BGR)
inverted = 255-thresholded # black-in-white

The following is the processed images.

enter image description here

With,

barcodes = pyzbar.decode(inverted)
print (barcodes)

The print out showed the decoded type is QRCODE and the data is GOAL.

[Decoded(data='GOAL', type='QRCODE', rect=Rect(left=5, top=13, width=228, height=212), 
polygon=[Point(x=5, y=222), Point(x=233, y=225), Point(x=220, y=19), Point(x=13, y=13)])]

Hope this help.

Solution 2:[2]

the problem you are facing is due to the fact that you flipped the image before processing

flipping the image after processing with pyzbar will make it align as you would want it to be

Solution 3:[3]

I found the existing answers didn't work for some images and ended up using this approach.

''' detect and decode QR from image '''
def scan_qr(image, old_method=False):
    if image.ndim == 3:
        image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    else: # ndim == 2
        image_gray = image
    min_dim = min(image.shape[:2])
    block_size = int(min_dim/3)
    block_size += 0 if block_size%2 == 1 else 1 # blockSize should be odd
    image_bw = cv2.adaptiveThreshold(image_gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, block_size, 2)
    return decode(image_bw, symbols=[ZBarSymbol.QRCODE])

I am using adaptiveThreshold as it is better in converting an image of varying brightness to a black & white image.

Your qr looks like this

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Martijn Pieters
Solution 3 Avinash Thakur