Choosing the Best Tool for High-Density QR Code Scanning on Android: Google ML Kit vs. Dynamsoft Barcode SDK

The market offers numerous QR code tools and SDKs, but not all are created equal. For Android development, Google ML Kit is a popular and free option, providing reliable support for general QR code detection. However, it falls short when it comes to high-density QR code detection. On the other hand, Dynamsoft Barcode Reader, a commercial SDK, excels in handling specialized barcode types, including high-density QR codes. In this article, we’ll streamline the Google ML Kit sample and integrate it with Dynamsoft Barcode SDK to compare their performance in recognizing high-density QR codes.

high density QR code from Google

Prerequisites

  • ML Kit

    1. Add the following meta-data entry to your AndroidManifest.xml file:

       <meta-data
           android:name="com.google.mlkit.vision.DEPENDENCIES"
           android:value="barcode"/>
      
    2. Include the ML Kit Barcode Scanning library in your build.gradle file:

       dependencies {
           implementation 'com.google.mlkit:barcode-scanning:17.0.0'
           // Or comment the dependency above and uncomment the dependency below to
           // use unbundled model that depends on Google Play Services
           // implementation 'com.google.android.gms:play-services-mlkit-barcode-scanning:16.2.1'
       }
      

      Note: The model file is generated in the APK under apk/assets/mlkit_barcode_models/barcode_ssd_mobilenet_v1_dmp25_quant.tflite.

  • Dynamsoft Barcode Reader

    1. Configure the Maven repository and add the Dynamsoft Barcode Reader dependency in your build.gradle file:

       allprojects {
           repositories {
               google()
               jcenter()
               maven {
                   url "https://download2.dynamsoft.com/maven/aar"
               }
           }
       }
          
       dependencies {
           implementation 'com.dynamsoft:dynamsoftbarcodereader:9.6.40@aar'
       }
      
    2. Obtain a Dynamsoft Barcode Reader Trial License for testing.

Reading QR Codes from Still Images

QR Code Scanning with Google ML Kit

To get started with Google ML Kit, download the vision sample code, which demonstrates various features including object detection, face detection, text recognition, barcode scanning, image labeling, custom image labeling, pose detection, and selfie segmentation.

For the purpose of this article, we’ll focus on QR code scanning from still images. To streamline the app, we’ll retain only the StillImageActivity and set it as the launcher activity in the AndroidManifest.xml:

<activity
    android:name=".java.StillImageActivity"
    android:exported="true"
    android:theme="@style/AppTheme">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>
</activity>

QR Code Scanning with Dynamsoft Barcode SDK

Next, we create a dynamsoftbarcodescanner folder containing two class files: DynamsoftBarcodeGraphic.java and DynamsoftBarcodeProcessor.java.

  • DynamsoftBarcodeGraphic: This class is responsible for drawing the detection results on the screen. Here’s a snippet that shows how it works:

      @Override
      public void draw(Canvas canvas) {
          if (result == null) {
              throw new IllegalStateException("Attempting to draw a null barcode.");
          }
        
          // Draws the bounding box around the BarcodeBlock.
          Point[] points = result.localizationResult.resultPoints;
          int minx = points[0].x;
          int miny = points[0].y;
          int maxx = points[0].x;
          int maxy = points[0].y;
          for (int i = 1; i < 4; i++) {
              if (points[i].x < minx) {
                  minx = points[i].x;
              }
              else if (points[i].x > maxx) {
                  maxx = points[i].x;
              }
        
              if (points[i].y < miny) {
                  miny = points[i].y;
              }
              else if (points[i].y > maxy) {
                  maxy = points[i].y;
              }
          }
          RectF rect = new RectF(minx, miny, maxx, maxy);
          // If the image is flipped, the left will be translated to right, and the right to left.
          float x0 = translateX(rect.left);
          float x1 = translateX(rect.right);
          rect.left = min(x0, x1);
          rect.right = max(x0, x1);
          rect.top = translateY(rect.top);
          rect.bottom = translateY(rect.bottom);
          canvas.drawRect(rect, rectPaint);
        
          // Draws other object info.
          float lineHeight = TEXT_SIZE + (2 * STROKE_WIDTH);
          float textWidth = barcodePaint.measureText(result.barcodeText);
          canvas.drawRect(
                  rect.left - STROKE_WIDTH,
                  rect.top - lineHeight,
                  rect.left + textWidth + (2 * STROKE_WIDTH),
                  rect.top,
                  labelPaint);
          // Renders the barcode at the bottom of the box.
          canvas.drawText(result.barcodeText, rect.left, rect.top - STROKE_WIDTH, barcodePaint);
      }
    
  • DynamsoftBarcodeProcessor: This class handles the decoding of QR codes. When an image file is loaded, the processBitmap(Bitmap bitmap, final GraphicOverlay graphicOverlay) method is triggered. It then calls decodeBufferedImage(bitmap) to recognize the QR code:

      @Override
      public void processBitmap(Bitmap bitmap, final GraphicOverlay graphicOverlay) {
          try {
              long frameStartMs = SystemClock.elapsedRealtime();
              TextResult[] results = barcodeScanner.decodeBufferedImage(bitmap);
              long frameEndMs = SystemClock.elapsedRealtime();
        
              if (results != null) {
                  for (int i = 0; i < results.length; ++i) {
                      TextResult barcode = results[i];
                      graphicOverlay.add(new DynamsoftBarcodeGraphic(graphicOverlay, barcode));
                  }
                  graphicOverlay.add(
                          new InferenceInfoGraphic(
                                  graphicOverlay,
                                  frameEndMs - frameStartMs,
                                  frameEndMs - frameStartMs,
                                  null));
              }
        
          } catch (IOException e) {
              e.printStackTrace();
          } catch (BarcodeReaderException e) {
              e.printStackTrace();
          }
      }
    

Build and run

After integrating the necessary components, build and run the project in Android Studio. Here’s an example of high-density QR code detection in action:

high density QR code detection

High-Density QR Code Detection Performance

To evaluate the performance of ML Kit and Dynamsoft Barcode Reader for high-density QR codes, we conducted tests using the public image dataset provided by BoofCV.

The test images are located in the qrcodes_v3/qrcodes/detection/high_version directory. We selected six images from this dataset for the tests.

The results were quite revealing: Google ML Kit struggled with these high-density QR codes, taking longer to process and failing to recognize any of them. In contrast, Dynamsoft Barcode Reader successfully recognized all the high-density QR code images with greater speed and accuracy.

high density QR detection comparison

Source Code

https://github.com/yushulx/android-camera-barcode-mrz-document-scanner/tree/main/examples/9.x/dense_qr