3

Have a bunch of QR Code labels printed from the same label printer, all can be read except for this one.

Have tried all solutions from Preprocessing images for QR detection in python

QR Code

Losing my mind... any help appreciated!

Code is here:

import cv2
import numpy as np
from pyzbar.pyzbar import decode
from pyzbar.pyzbar import ZBarSymbol
from kraken import binarization
from PIL import Image
from qreader import QReader

image_path = r"C:\Users\ASinger\Pictures\hdi_pdfs\page1.png"

# Method 1
im = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
ret, bw_im = cv2.threshold(im, 127, 255, cv2.THRESH_BINARY)
barcodes = decode(bw_im, symbols=[ZBarSymbol.QRCODE])
print(f'barcodes: {barcodes}')

# Method 2
im = Image.open(image_path)
bw_im = binarization.nlbin(im)
decoded = decode(bw_im, symbols=[ZBarSymbol.QRCODE])
print(f'decoded: {decoded}')

# Method 3
im = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
blur = cv2.GaussianBlur(im, (5, 5), 0)
ret, bw_im = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
decoded = decode(bw_im, symbols=[ZBarSymbol.QRCODE])
print(f'decoded: {decoded}')

# Method 4
qreader = QReader()
image = cv2.imread(image_path)
decoded_text = qreader.detect_and_decode(image=image)
print(f'decoded_text: {decoded_text}')

# Method 5
cropped_image = image_path
im2 = Image.open(cropped_image)
im2 = im2.resize((2800, 2800))
im2.save(cropped_image, quality=500)
im2.show()
im3 = cv2.imread(cropped_image, cv2.IMREAD_GRAYSCALE)
ret, bw_im = cv2.threshold(im3, 127, 255, cv2.THRESH_BINARY)
decoded = decode(bw_im, symbols=[ZBarSymbol.QRCODE])
print(f'decoded: {decoded}')

Bilal
  • 3,191
  • 4
  • 21
  • 49

1 Answers1

3

It's difficult to tell why Pyzbar fails, but we may guess that the issue is related to low quality scanning artifacts, and maybe compression artifacts.

Here is a small ROI in native resolution:
enter image description here

As you can see there is a lot of noise and artifacts.

For improving the quality I recommend using cv2.medianBlur filter:

clean_im = cv2.medianBlur(im, 25)
  • Median filter was selected because it applies fine threshold between black and white.
  • The size of the filter was selected to be 25 (relatively large) because the resolution of the image is relatively high compared to the details of the QR Code.

Same ROI after filtering:
enter image description here

As you can see the noise is much lower, but the details are blurred.


For improving the issue, we may downscale the image using cv2.resize:

small_clean_im = cv2.resize(clean_im, (512, 512), interpolation=cv2.INTER_AREA)

Downscaling the image with cv2.INTER_AREA interpolation is merging multiple pixels into one pixel (kind of concentrating the data), and also remove noise.
The size 512x512 seems like a good tradeoff between keeping details and removing noise.

Image after medianBlur and resize:

enter image description here

Same image with resize only (without medianBlur) for comparison:
enter image description here


I suppose it's better not to apply a threshold before using Pyzbar decode method.
I assume the decode method uses an internal thresholding algorithm that may be better than our own thresholding.


Complete code sample:

import cv2
from pyzbar.pyzbar import decode
from pyzbar.pyzbar import ZBarSymbol

im = cv2.imread('page1.png', cv2.IMREAD_GRAYSCALE)

clean_im = cv2.medianBlur(im, 25)  # Apply median blur for reducing noise
small_clean_im = cv2.resize(clean_im, (512, 512), interpolation=cv2.INTER_AREA)  # Downscale the image

barcodes = decode(small_clean_im, symbols=[ZBarSymbol.QRCODE])
print(f'barcodes: {barcodes}')

# Show image for testing
cv2.imshow('small_clean_im', small_clean_im)
cv2.waitKey()
cv2.destroyAllWindows()

Output:
barcodes: [Decoded(data=b'P1693921.001', type='QRCODE', rect=Rect(left=137, top=112, width=175, height=175), polygon=[Point(x=137, y=280), Point(x=304, y=287), Point(x=312, y=119), Point(x=143, y=112)])]


Note:

  • The processing worked with the sample image, but it is not guaranteed to work with other images.
    You may try different filter sizes, and different image sizes for improving the success rate.
Christoph Rackwitz
  • 11,317
  • 4
  • 27
  • 36
Rotem
  • 30,366
  • 4
  • 32
  • 65