0

Let's say I have an image of a QR code. that I took with my phone called in.png. I would like to create a nicer looking version of the QR code (so everything is at perfect right angles, the output is only solid black/white, etc.) without changing the way the QR code looks visibly.

Here is my Python code so far:

from PIL import Image
from pyzbar import pyzbar

img1 = Image.open('in.png')
out1 = pyzbar.decode(img1)

import qrcode
output = qrcode.make(out1[0].data)
output.save("out.png", "PNG")

That's my input image:

enter image description here

And, that's my current output image:

enter image description here

Even though they both contain the same data, the QR codes look different visually (bottom right for example). I don't want this, I want the output file to be the same visual representation of the input QR code. Can somebody help me correct my Python code to achieve this?

2
  • 1
    It's more like 'write from scratch' than 'correct my code'. Do you have any ideas on how to approach this? Commented Jun 24, 2021 at 7:51
  • This might be useful: stackoverflow.com/questions/4551110/… Commented Jun 24, 2021 at 7:52

1 Answer 1

3

If you want to have the exact appearance as in your original input, you'll need to involve actual image processing, I'm afraid. I switched to OpenCV and NumPy, since array operations are much faster and comfortable to perform than with Pillow.

The workflow is quite simple:

  1. Binarize, and "clean" the input image, e.g. using morphological closing.
  2. Crop the actual QR code.
  3. Resize the cropped part to the actual QR code dimensions, i.e. to (25, 25) here.
  4. Resize that image to your desired output size, and maybe add white borders around if wanted.

That's the full code including some visualization overhead:

import cv2
import numpy as np

# Read image as grayscale, get dimensions
img = cv2.imread('dawjk.png', cv2.IMREAD_GRAYSCALE)
h, w = img.shape

# Binarize image to get rid of aliasing artifacts (gray-ish colors)
img_bin = cv2.threshold(img, 0, 255, cv2.THRESH_OTSU)[1]

# Morphological closing to get rid of artifacts
img_bin = cv2.morphologyEx(img_bin, cv2.MORPH_CLOSE, cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)))

# Count white pixels per row and column to crop actual QR code
sum_x = np.sum(img_bin == 255, axis=1)
sum_y = np.sum(img_bin == 255, axis=0)
y1, y2 = np.argwhere(sum_x < w)[[0, -1], 0]
x1, x2 = np.argwhere(sum_y < h)[[0, -1], 0]
cropped = img_bin[y1:y2, x1:x2]

# Resize cropped part to actual QR code dimension (25, 25)
resized = cv2.resize(cropped, (25, 25))

# Resize to destination size
dst_size = (400, 400)
resized_dst = cv2.resize(resized, dst_size, interpolation=cv2.INTER_NEAREST)

# Add white borders of desired size
m = 40
output = cv2.copyMakeBorder(resized_dst, m, m, m, m, cv2.BORDER_CONSTANT, value=255)

# Just for visualization
import matplotlib.pyplot as plt
plt.figure(figsize=(9, 9))
plt.subplot(2, 2, 1), plt.imshow(img, cmap='gray'), plt.title('Original image')
plt.subplot(2, 2, 2), plt.imshow(cropped, cmap='gray'), plt.title('Cropped part')
plt.subplot(2, 2, 3), plt.imshow(resized, cmap='gray'), plt.title('Resized to QR code dimensions')
plt.subplot(2, 2, 4), plt.imshow(output, cmap='gray'), plt.title('Final output')
plt.tight_layout(), plt.show()

That's the visualization output:

Visualization output

----------------------------------------
System information
----------------------------------------
Platform:      Windows-10-10.0.19041-SP0
Python:        3.9.1
PyCharm:       2021.1.2
Matplotlib:    3.4.2
NumPy:         1.20.3
OpenCV:        4.5.2
----------------------------------------
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.