Long Distance QR Code Scanning: Resolution

Let’s continue discussing scanning QR codes at a distance. In this article, we’ll talk about resolution.

Using the camera’s highest resolution

Most of the current smartphones’ video stream resolution can be set to 1080P (Full HD) and many of them support 4K (Ultra HD) video capturing. The higher the resolution we choose, the clearer the code can become so that it is easier to read.

However, although the native camera app can shoot a 4K video, a third-party camera app may only be able to shoot a 1080P one on many devices. The resolution of the video stream is not high enough to do a live scan of QR codes afar.

In such a case, we can take a photo first and then decode it. The resolution of a photo can be several times higher than the supported video stream resolution. This can significantly increase the scanning distance.

A QR code in video stream:

A QR code in a taken photo:

Image enhancing

We can enhance the images to improve the resolution for a higher successful decoding rate.

Scale-Up

The code afar detected often has a low image resolution and the module size is very small.

We can scale up the image to increase the module size so that DBR can successfully read it.

In Dynamsoft Barcode Reader, there is a scaleUpModes parameter to do this.

PublicRuntimeSettings rs = dbr.getRuntimeSettings();
rs.scaleUpModes[1] = EnumScaleUpMode.SUM_LINEAR_INTERPOLATION;
dbr.updateRuntimeSettings(rs);
dbr.setModeArgument("ScaleUpModes",1,"ModuleSizeThreshold",20);
dbr.setModeArgument("ScaleUpModes",1,"TargetModuleSize",10);

Using scale-up, it is possible to read the code below.

Super Resolution

Super Resolution can be used to recover details of images.

Here, we use TensorFlow’s super resolution example to process a blurry QR code image.

Code:

import tensorflow as tf
import cv2

lr = tf.io.read_file("small.jpg")
lr = tf.image.decode_jpeg(lr)
lr = tf.expand_dims(lr, axis=0)
lr = tf.cast(lr, tf.float32)
interpreter = tf.lite.Interpreter(model_path="ESRGAN.tflite")
interpreter.allocate_tensors()
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
interpreter.set_tensor(input_details[0]['index'], lr)
interpreter.invoke()
output_data = interpreter.get_tensor(output_details[0]['index'])
sr = tf.squeeze(output_data, axis=0)
sr = tf.clip_by_value(sr, 0, 255)
sr = tf.round(sr)
sr = tf.cast(sr, tf.uint8)
cv2.imwrite("4x.jpg",sr.numpy())

Before:

After:

The image is scaled up four times and the code becomes sharper.

It is possible to integrate it in an Android mobile app with TensorFlow-Lite.

But based on my personal experience, this super resolution model is not very useful as it limits the size of input images to 50x50. In addition, the default model is not trained against QR code datasets. Further works can be done like training a QR code super resolution model.

Experiment

I used my Sharp Aquos S2 to scan a QR code displayed on my monitor to do an experiment. The size of the code displayed is 2x2cm. We can get a rough idea of the effects of the methods mentioned above.

Longest Distance (cm) Condition Resolution
65 live scan without zoom 1920x1080
70 live scan with 4x digital zoom 1920x1080
80 live scan with super resolution 1920x1080
130 photo 3024x3024

We can use tangent to calculate the distance for different code sizes.

Camera and code

Distance calculation

For example, if the code size is 6x6cm, then the longest distance of live scan is 65*6/2=195cm.

Source Code

https://github.com/xulihang/Faraway_Scan