How to Optimize Parameters for Multiple QR Code Decoding in a Single Image with YOLO

Installation

  • Dynamsoft Barcode Reader Python
pip install dbr
  • OpenCV Python
pip install opencv-python
  • Darknet
git clone https://github.com/AlexeyAB/darknet.git

How to Get and Use Pre-configured Parameter Templates of Dynamsoft Barcode SDK

  1. Visit Dynamsoft Barcode Reader online demo
import cv2 as cv
import numpy as np
import time
from dbr import *
import os
reader = BarcodeReader()
# Apply for a trial license: https://www.dynamsoft.com/customer/license/trialLicense?product=dbr
license_key = "LICENSE-KEY"
reader.init_license(license_key)
def decode(filename, template_name):
frame = cv.imread(filename)
template_path = os.path.dirname(os.path.abspath(__file__)) + os.path.sep + template_name
settings = reader.reset_runtime_settings()
error = reader.init_runtime_settings_with_file(template_path, EnumConflictMode.CM_OVERWRITE)
before = time.time()
results = reader.decode_buffer(frame)
after = time.time()
COLOR_RED = (0,0,255)
thickness = 2
if results != None:
found = len(results)
for result in results:
text = 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]]])
cv.drawContours(image=frame, contours=[data], contourIdx=-1, color=COLOR_RED, thickness=thickness, lineType=cv.LINE_AA)
cv.putText(frame, result.barcode_text, points[0], cv.FONT_HERSHEY_SIMPLEX, 0.5, COLOR_RED)
cv.putText(frame, '%.2f s, Qr found: %d' % (after - before, found), (20, 20), cv.FONT_HERSHEY_SIMPLEX, 0.5, COLOR_RED)
else:
cv.putText(frame, '%.2f s, Qr found: %d' % (after - before, 0), (20, 20), cv.FONT_HERSHEY_SIMPLEX, 0.5, COLOR_RED)
cv.imshow(template_name, frame)decode("test.jpg", "l1.json")
decode("test.jpg", "l2.json")
decode("test.jpg", "l3.json")
decode("test.jpg", "l4.json")
decode("test.jpg", "l5.json")
cv.waitKey(0)

Training a QR Code Detector with YOLOv4

  1. Get the public dataset with QR codes from boofcv.
  2. Annotate the QR images with labelImg.
  3. Download yolov4-tiny.conv.29
  4. Customize configuration file based on darknet/cfg/yolov4-tiny-custom.cfg:
batch=64              # line 6
subdivisions=16 # line 7
width=640 # line 8
height=640 # line 9

max_batches = 6000 # line 20

steps=4800,5400 # line 22

filters=18 # 212
classes=1 # 220

filters=18 # 263
classes=1 # 269
QR_CODE
classes = 1
train = data/train.txt
valid = data/test.txt
names = data/obj.names
backup = backup/
import os
import re
from shutil import copyfile
import argparse
import math
import random


def iterate_dir(source, ratio):
source = source.replace('\\', '/')
train_dir = 'data/obj/train'
test_dir = 'data/obj/test'

if not os.path.exists(train_dir):
os.makedirs(train_dir)
if not os.path.exists(test_dir):
os.makedirs(test_dir)

images = [f for f in os.listdir(source)
if re.search(r'([a-zA-Z0-9\s_\\.\-\(\):])+(?i)(.jpg|.jpeg|.png)$', f)]

num_images = len(images)
num_test_images = math.ceil(ratio*num_images)

image_files = []

for i in range(num_test_images):
idx = random.randint(0, len(images)-1)
filename = images[idx]
image_files.append("data/obj/test/" + filename)
copyfile(os.path.join(source, filename),
os.path.join(test_dir, filename))
txt_filename = os.path.splitext(filename)[0]+'.txt'
copyfile(os.path.join(source, txt_filename),
os.path.join(test_dir, txt_filename))

images.remove(images[idx])

with open("data/test.txt", "w") as outfile:
for image in image_files:
outfile.write(image)
outfile.write("\n")
outfile.close()

image_files = []

for filename in images:
image_files.append("data/obj/train/" + filename)
copyfile(os.path.join(source, filename),
os.path.join(train_dir, filename))
txt_filename = os.path.splitext(filename)[0]+'.txt'
copyfile(os.path.join(source, txt_filename),
os.path.join(train_dir, txt_filename))

with open("data/train.txt", "w") as outfile:
for image in image_files:
outfile.write(image)
outfile.write("\n")
outfile.close()


def main():
parser = argparse.ArgumentParser(description="Partition dataset of images into training and testing sets",
formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument(
'-i', '--imageDir',
help='Path to the folder where the image dataset is stored. If not specified, the CWD will be used.',
type=str,
default=os.getcwd()
)
parser.add_argument(
'-r', '--ratio',
help='The ratio of the number of test images over the total number of images. The default is 0.1.',
default=0.1,
type=float)
args = parser.parse_args()
iterate_dir(args.imageDir, args.ratio)

if __name__ == '__main__':
main()
python partition_dataset.py -i ../images -r 0.1
darknet detector test data/obj.data yolov4-tiny-custom.cfg backup/yolov4-tiny-custom_last.weights sample/test.png 
darknet detector test data/obj.data yolov4-tiny-custom.cfg backup/yolov4-tiny-custom_last.weights sample/test.png
import cv2 as cv
import numpy as np
import time
from dbr import *
import os
# Initialize Dynamsoft Barcode Reader
reader = BarcodeReader()
# Apply for a trial license: https://www.dynamsoft.com/customer/license/trialLicense
license_key = "LICENSE-KEY"
reader.init_license(license_key)
# Load YOLOv4-tiny model
class_names = open('obj.names').read().strip().split('\n')
net = cv.dnn.readNetFromDarknet('yolov4-tiny-custom.cfg', 'yolov4-tiny-custom_last.weights')
net.setPreferableBackend(cv.dnn.DNN_BACKEND_OPENCV)
model = cv.dnn_DetectionModel(net)
width = 640
height = 640
CONFIDENCE_THRESHOLD = 0.2
NMS_THRESHOLD = 0.4
COLOR_RED = (0,0,255)
COLOR_BLUE = (255,0,0)
def decode(filename, template_name):
frame = cv.imread(filename)
if frame.shape[1] > 1024 or frame.shape[0] > 1024:
width = 1024
height = 1024
model.setInputParams(size=(width, height), scale=1/255, swapRB=True)
template_path = os.path.dirname(os.path.abspath(__file__)) + os.path.sep + template_name
settings = reader.reset_runtime_settings()
error = reader.init_runtime_settings_with_file(template_path, EnumConflictMode.CM_OVERWRITE)
# YOLO detection
yolo_start = time.time()
classes, scores, boxes = model.detect(frame, CONFIDENCE_THRESHOLD, NMS_THRESHOLD)
yolo_end = time.time()
print("YOLO detection time: %.2f s" % (yolo_end - yolo_start))
index = 0
dbr_found = 0
total_dbr_time = 0
for (classid, score, box) in zip(classes, scores, boxes):
label = "%s : %f" % (class_names[classid], score)
tmp = frame[box[1]:box[1] + box[3], box[0]: box[0] + box[2]]
# Set parameters for DBR
settings = reader.get_runtime_settings()
settings.expected_barcodes_count = 1
settings.barcode_format_ids = EnumBarcodeFormat.BF_QR_CODE
reader.update_runtime_settings(settings)
before = time.time()
results = reader.decode_buffer(tmp)
after = time.time()
total_dbr_time += after - before if results != None:
found = len(results)
for result in results:
text = result.barcode_text
dbr_found += 1
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]]])
cv.drawContours(image=tmp, contours=[data], contourIdx=-1, color=(0, 0, 255), thickness=2, lineType=cv.LINE_AA)
cv.putText(frame, text, (box[0], box[1] + 10), cv.FONT_HERSHEY_SIMPLEX, 0.5, COLOR_RED)
else:
found = 0
index += 1
cv.rectangle(frame, box, COLOR_BLUE, 2)
cv.putText(frame, label, (box[0], box[1] - 10), cv.FONT_HERSHEY_SIMPLEX, 0.5, COLOR_BLUE, 2)
cv.putText(frame, 'DBR+YOLO %.2f s, DBR found: %d, YOLO found: %d' % (yolo_end - yolo_start + total_dbr_time, dbr_found, len(classes)), (0, 15), cv.FONT_HERSHEY_SIMPLEX, 0.5, COLOR_RED)
cv.imshow(template_name, frame)
decode("test.jpg", "l1.json")
decode("test.jpg", "l2.json")
decode("test.jpg", "l3.json")
decode("test.jpg", "l4.json")
decode("test.jpg", "l5.json")
cv.waitKey(0)

Benchmark for Boofcv QR Image Set

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

Dialogflow Chatbot with ML and AWS DevOps

Alone in the Woods: Anomaly Detection using Isolation Forests

[Behind the ML] Singular Value Decomposition, part2

Ask Wikipedia ELI5-like Questions Using Long-Form Question Answering on Haystack

Using Logistic Regression for Image Classification

Leveraging satellite imagery for machine learning computer vision applications

Can machine learning help us improve stroke rehabilitation? A step towards personalized therapy

One poetic function for .wav files

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

MNIST image classification models from scratch

Photo Sketching using Open CV

IPL SCORE PREDICTION WITH FLASK APP — WITH SOURCE CODE

Lane Detection using Hough Transformation