developer.android.com/jetpack

QR Scanning using CameraX

Sasikanth
3 min readApr 19, 2020

This article was originally published here

Recently I had to implement QR code scanning in Simple using CameraX and zxing (we are using zxing to decode the image and read the QR code). Thanks to CameraX it is much easier to implement camera APIs and use it to read the QR code, you might be wondering “what are the benefits of using CameraX?” For starters consistent and easy to use camera APIs, well-tested library with various OEMs and devices.

Let’s Code

Before we jump into code let’s look at what we need to do.

  • Show camera preview
  • Analyse image to read the QR code with zxing

In this article, we will take a look setting up ImageAnalysis and using zxing to read the QR code. You can refer to CameraX official guide to see how to set up the camera preview using PreviewView.

Let’s start by adding zxing dependency. (We are using version 3.3.0 of the library because version 3.4.0 requires Java 8 and above)

implementation 'com.google.zxing:core:3.3.0'

Creating an Image Analyzer

The image analysis use case in CameraX provides the app with CPU accessible image to perform image processing, computer vision or machine learning.

We start by extending ImageAnalysis.Analyzer to create QrCodeAnalyzer.

ImageAnalysis.Analyzer#analyze is called for every frame and this is where we will analyse the image and let zxing detect and read the QR code. During analyze we get ImageProxy as a parameter, this will give us access to the image information like format, width, height, planes, rotation degrees. Internally ImageProxy uses ImageReader to get the Image, ImageReader uses YUV format unless changed. So first let’s verify that we are getting a YUV format image because based on that our zxing implementation may vary.

To decode the image and read the QR we need a Reader, we will be using MultiFormatReader. By default it supports reading all barcode formats, since we only want a QR code scanner we can use hints to tell the Reader which formats to decode.

Now that we have our reader, let’s set up the rest of the code that is required to decode the image. First, we need to get the Y plane from our image. (Since we our image format is YUV, it will be the first plane)

Then we use the data to create a PlanarYUVLuminanceSource it essentially gives us greyscale luminance values for any pixel format where Y channel is planar and appears first.

Now all we have to do is take this PlanarYUVLuminanceSource and construct a BinaryBitmap so that our Reader can decode the QR code. To construct a BinaryBitmap we need to pass it a Binarizer which takes in the luminance data and convert to 1 bit data. We are using HybridBinarizer (mainly because it’s recommended by zxing).

Finally we close the image so that further images can be processed. If we don’t close the image, further image may not be sent to analyse, this is an issue when the first frame camera recognises may not have a QR code. So we have to keep sending image frames until the QR code is recognised.

Here is the final code for the QrCodeAnalyzer

Now that we have our ImageAnalysis.Analyzer, we just need to set the use case to the ProcessCameraProvider . For that we create a ImageAnalysis use case and set our QrCodeAnalyzer. We are also setting a backpressure strategy incase image is not closed and a new frame is available.

That’s it, with just a few lines of code we have a working QR code scanner with CameraX and zxing.

Things to keep in mind

  • If you have issues with the image rotation, ImageProxy provides us with rotation degrees which can be used to adjust the frame/image before decoding.
  • If you use a different image format than YUV, you may need to switch to a different a LuminanceSource.
  • If you found a mistake or something to improve upon, please let me know.

You can find the source code here

--

--