How to Optimize QR Recognition Performance by Image Preprocessing and Parameter Tuning

Prerequisites

  • OpenCV Python
pip install opencv-python   pip install opencv-contrib-python
  • Dynamsoft Barcode Reader SDK
pip install dbr

Preprocessing QR Images

Color Image

import cv2
import numpy as np
import dbr
import time

reader = dbr.BarcodeReader()
reader.init_license("LICENSE-KEY") # https://www.dynamsoft.com/customer/license/trialLicense?product=dbr
image = cv2.imread('Air-Force-Reserve-San-Diego.jpg')

def detect(windowName, image, pixel_format):
try:
buffer = image.tobytes()
height = image.shape[0]
width = image.shape[1]
stride = image.strides[0]
start = time.time()
results = reader.decode_buffer_manually(buffer, width, height, stride, pixel_format, "")
end = time.time()
print("Time taken: {:.3f}".format(end - start) + " seconds")
cv2.putText(image, "Time taken: {:.3f}".format(end - start) + " seconds", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)

if results != None:
for result in results:
print("Barcode Format : ")
print(result.barcode_format_string)
print("Barcode Text : ")
print(result.barcode_text)

points = result.localization_result.localization_points
data = np.array([[points[0][0], points[0][1]], [points[1][0], points[1][1]], [points[2][0], points[2][1]], [points[3][0], points[3][1]]])
cv2.drawContours(image=image, contours=[data], contourIdx=-1, color=(0, 255, 0), thickness=2, lineType=cv2.LINE_AA)

x = min(points[0][0], points[1][0], points[2][0], points[3][0])
y = min(points[0][1], points[1][1], points[2][1], points[3][1])
cv2.putText(image, result.barcode_text, (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)

cv2.imshow(windowName, image)
except BarcodeReaderError as bre:
print(bre)

detect('Color', image, dbr.EnumImagePixelFormat.IPF_RGB_888)
cv2.waitKey(0)
reader = dbr.BarcodeReader()
reader.init_license("LICENSE-KEY")
buffer = image.tobytes()
height = image.shape[0]
width = image.shape[1]
stride = image.strides[0]
results = reader.decode_buffer_manually(buffer, width, height, stride, dbr.EnumImagePixelFormat.IPF_RGB_888, "")
points = result.localization_result.localization_points
data = np.array([[points[0][0], points[0][1]], [points[1][0], points[1][1]], [points[2][0], points[2][1]], [points[3][0], points[3][1]]])
cv2.drawContours(image=image, contours=[data], contourIdx=-1, color=(0, 255, 0), thickness=2, lineType=cv2.LINE_AA)

x = min(points[0][0], points[1][0], points[2][0], points[3][0])
y = min(points[0][1], points[1][1], points[2][1], points[3][1])
cv2.putText(image, result.barcode_text, (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)

Grayscale Image

grayscale_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
detect('Grayscale', grayscale_image, dbr.EnumImagePixelFormat.IPF_GRAYSCALED)

Binary Image

# https://docs.opencv.org/4.5.1/d7/d4d/tutorial_py_thresholding.html
blur = cv2.GaussianBlur(grayscale_image,(5,5),0)
ret, thresh = cv2.threshold(blur, 0,255,cv2.THRESH_BINARY + cv2.THRESH_OTSU)
detect('Binary', thresh, dbr.EnumImagePixelFormat.IPF_GRAYSCALED)

More Tests

Perspective Distortion

image = cv2.imread('perspective-distortion-qr-code.jpg')
grayscale_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(grayscale_image, 125, 255,cv2.THRESH_BINARY)
detect('Binary', thresh, dbr.EnumImagePixelFormat.IPF_GRAYSCALED)
Time taken: 0.0080 seconds
Barcode Format :
QR_CODE
Barcode Text :
http://goo.by/wb0Ric

Inverted Color

ret, thresh = cv2.threshold(grayscale_image, 150,255,cv2.THRESH_BINARY )
cv2.bitwise_not(thresh, thresh)
detect('Inverted', thresh, dbr.EnumImagePixelFormat.IPF_GRAYSCALED)
Time taken: 0.0541 seconds
Barcode Format :
QR_CODE
Barcode Text :
https://www.jalna.com.au/

Adjusting the Algorithm Parameters

print(reader.get_runtime_settings().__dict__){'terminate_phase': 32, 'timeout': 10000, 'max_algorithm_thread_count': 4, 'expected_barcodes_count': 0, 'barcode_format_ids': -31457281, 'barcode_format_ids_2': 0, 'pdf_raster_dpi': 300, 'scale_down_threshold': 2300, 'binarization_modes': [2, 0, 0, 0, 0, 0, 0, 0], 'localization_modes': [2, 16, 4, 8, 0, 0, 0, 0], 'colour_clustering_modes': [0, 0, 0, 0, 0, 0, 0, 0], 
'colour_conversion_modes': [1, 0, 0, 0, 0, 0, 0, 0], 'grayscale_transformation_modes': [2, 0, 0, 0, 0, 0, 0, 0], 'region_predetection_modes': [2, 0, 0, 0, 0, 0, 0, 0], 'image_preprocessing_modes': [2, 0, 0, 0, 0, 0, 0, 0], 'texture_detection_modes': [2, 0, 0, 0, 0, 0, 0, 0], 'text_filter_modes': [2, 0, 0, 0, 0, 0, 0, 0], 'dpm_code_reading_modes': [0, 0, 0, 0, 0, 0,
0, 0], 'deformation_resisting_modes': [0, 0, 0, 0, 0, 0, 0, 0], 'barcode_complement_modes': [0, 0, 0, 0, 0, 0, 0, 0], 'barcode_colour_modes': [1, 0, 0, 0, 0, 0, 0, 0], 'text_result_order_modes': [1, 2, 4, 0, 0, 0, 0, 0], 'text_assisted_correction_mode': 2, 'deblur_level': 9, 'intermediate_result_types': 0, 'intermediate_result_saving_mode': 1, 'result_coordinate_type': 1, 'return_barcode_zone_clarity': 0, 'region_top': 0, 'region_bottom': 0, 'region_left': 0, 'region_right': 0, 'region_measured_by_percentage': 0, 'min_barcode_text_length': 0, 'min_result_confidence': 0, 'scale_up_modes': [1, 0, 0, 0, 0, 0, 0, 0], 'accompanying_text_recognition_modes': [0, 0, 0, 0, 0, 0, 0, 0], 'pdf_reading_mode': 1, 'deblur_modes': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 'barcode_zone_min_distance_to_image_borders': 0}
  1. Go to Advanced Settings > Binarization mode > Threshold.
  2. Change the threshold value to 125.
error = reader.init_runtime_settings_with_file('perspective-qr.json')
image = cv2.imread('perspective-distortion-qr-code.jpg')
detect('Color', image_copy, dbr.EnumImagePixelFormat.IPF_RGB_888)
Time taken: 0.0080 seconds
Barcode Format :
QR_CODE
Barcode Text :
http://goo.by/wb0Ric
Time taken: 0.0160 seconds
Barcode Format :
QR_CODE
Barcode Text :
https://www.jalna.com.au/

Source Code

--

--

--

Manager of Dynamsoft Open Source Projects | Tech Lover

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Bicameral Mind — Humanoid Robot With GPT-3 as the Story-Teller

AI is already killing humanity

Please teach my computer how to spell

Mask Detector in just 10 minutes

AI and Customer Experience in the ‘Age of the Customer’

What Already Pragmatic Failure Is

Zombox — Multiplayer Demonstrative Learning in Unity ML Agents in 48 hours.

Three predictions for enterprise AI in 2019

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Xiao Ling

Xiao Ling

Manager of Dynamsoft Open Source Projects | Tech Lover

More from Medium

HOW TO DETECT SHAPES USING CV2- WITH SOURCE CODE — EASY PROJECT

Face Recognition Based Attendance System with GUI Using Opencv and Tkinter

Object Detection

OCR is Optical Character Recognition, which defines the process of converting scanned documents or…