Python Forum
Locate QR code on a page - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: Locate QR code on a page (/thread-32102.html)



Locate QR code on a page - Pedroski55 - Jan-21-2021

I put a QR code on a page (actually top right corner, but with say about 1cm from the edges of the page)

This code (found on stackoverflow) successfully finds that QR code, but I have no idea how it works.

Could anyone explain it a bit? If you know an improvement, that would be great too.

import cv2
import numpy as np

# cv2.imread() can't handle .pdf files, I first convert to .jpg
# jpgfiles[0] = '/home/pedro/winter2020/20BE/pdf2jpg/1825010141_QR1.jpg'
# image = cv2.imread(jpgfiles[0])

# Load image, grayscale, Gaussian blur, Otsu's threshold

image = cv2.imread(jpgfiles[0])
original = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (9,9), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Morph close
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
close = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=2)

# Find contours and filter for QR code
cnts = cv2.findContours(close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.04 * peri, True)
    x,y,w,h = cv2.boundingRect(approx)
    area = cv2.contourArea(c)
    ar = w / float(h)
    if len(approx) == 4 and area > 1000 and (ar > .85 and ar < 1.3):
        cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 3)
        ROI = original[y:y+h, x:x+w]
        cv2.imwrite('ROI.png', ROI)

cv2.imshow('thresh', thresh)
cv2.imshow('close', close)
cv2.imshow('image', image)
cv2.imshow('ROI', ROI)
cv2.waitKey(2000)
cv2.cv2.destroyAllWindows()
I can read my test QR code with:

img = '/home/pedro/ROI.png'
image = cv2.imread(img)
decodedObjects = pyzbar.decode(image) # I found cv2.detectAndDecode(image) unreliable (about 15% error, no data)
for obj in decodedObjects:
    print("Type:", obj.type)
    print("Data: ", obj.data, "\n")

# data looks a bit funny because it contains a Chinese name
# output
# Type: QRCODE
# Data:  b'1825010141:\xe9\x99\x86\xe9\x81\xa5'
# this particular Chinese name decodes correctly, but some do not decode well
# I tried it on 162 students