DEV Community

Xiao Ling
Xiao Ling

Posted on • Originally published at dynamsoft.com

Dynamsoft Barcode Reader vs Google ML Kit: A Comprehensive Accuracy Comparison for Android Developers

When building Android applications that require barcode scanning capabilities, developers have several SDK options to consider. Two commonly used solutions are Google ML Kit Barcode Scanning and Dynamsoft Barcode Reader. ML Kit is a free, general-purpose machine learning SDK from Google, while Dynamsoft Barcode Reader is a commercial SDK specialized in barcode recognition. Both offer barcode scanning capabilities, but their approaches and performance characteristics differ.

This article provides a hands-on comparison of these two SDKs, with emphasis on detection accuracy across various real-world conditions. We'll walk through creating a reproducible benchmark suite that you can use to evaluate both SDKs with your own test data.

Demo Video: Dynamsoft vs. Google MLKit Barcode Scanner

Prerequisites

Why Barcode Detection Accuracy Matters

In enterprise environments, barcode detection accuracy is non-negotiable. Consider these scenarios:

  • Warehouse Management: Missing even one barcode during inventory scanning can lead to stock discrepancies and fulfillment errors
  • Healthcare: Failing to scan medication barcodes can have serious patient safety implications
  • Retail: Incomplete product scanning at checkout results in revenue loss and customer frustration
  • Logistics: Undetected shipping labels cause package routing failures and delivery delays

While scanning speed is important, accuracy takes precedence. An SDK that scans slightly faster but misses 20% of barcodes is far less valuable than one that reliably detects 95%+ of codes, even if it takes marginally more time.

Understanding the SDKs

Google ML Kit Barcode Scanning

ML Kit is Google's machine learning SDK for mobile applications, offering barcode scanning among other vision capabilities:

  • Licensing: Free to use with no licensing costs
  • Integration: Simple API with minimal setup required
  • Support: Community-based support through documentation and forums
  • Customization: Preset configurations with limited tuning options
  • Use Cases: Consumer applications, prototyping, projects with budget constraints

Dynamsoft Barcode Reader

Dynamsoft Barcode Reader is a specialized SDK focused specifically on barcode recognition:

  • Licensing: Commercial licensing model with free trial period available
  • Integration: Comprehensive API with extensive configuration options
  • Support: Direct technical support from engineering team
  • Customization: Fine-grained control over recognition parameters and algorithms
  • Use Cases: Enterprise applications, scenarios requiring high detection rates, challenging scanning conditions

Setting Up the Benchmark Environment

Let's create a comprehensive benchmark application that tests both SDKs side-by-side. This approach ensures fair, objective comparison.

Prerequisites

dependencies {
    // Dynamsoft Barcode Reader
    implementation 'com.dynamsoft:dynamsoftbarcodereader:11.2.10'

    // Google ML Kit
    implementation 'com.google.mlkit:barcode-scanning:17.2.0'

    // For web server benchmark (optional)
    implementation 'org.nanohttpd:nanohttpd:2.3.1'
}
Enter fullscreen mode Exit fullscreen mode

Project Structure

mlkit-dbr-benchmark/
├── app/
│   ├── src/main/java/
│   │   ├── fragments/
│   │   │   ├── ImageBenchmarkFragment.java
│   │   │   ├── VideoBenchmarkFragment.java
│   │   │   └── BenchmarkResultFragment.java
│   │   ├── server/
│   │   │   └── BenchmarkWebServer.java
│   │   └── BenchmarkConfig.java
│   └── res/layout/
└── README.md
Enter fullscreen mode Exit fullscreen mode

Benchmark Methodology

Our benchmark suite includes three comprehensive testing modes:

1. Image Benchmark

  • Test with individual images containing various barcode types
  • Evaluate detection under different conditions (blur, rotation, lighting)
  • Compare detection counts and reliability

2. Video Benchmark

  • Process video files frame-by-frame
  • Test real-world scanning scenarios
  • Measure consistency across frames

3. Web Server Benchmark

  • Upload test images/videos from any device
  • Batch processing capabilities
  • Remote testing for team collaboration

Important: We intentionally exclude camera-based real-time scanning from this benchmark because live camera tests cannot provide objective, repeatable comparisons. Environmental factors (lighting, hand stability, device variations) introduce too many variables.

Image Benchmark: Step-by-Step Guide

Image Benchmark

Implementation

First, create a global configuration class to manage SDK settings:

public class BenchmarkConfig {
    // Control whether to use custom Dynamsoft template
    public static boolean USE_CUSTOM_TEMPLATE = false;

    // Dynamsoft template for optimized performance
    public static final String DYNAMSOFT_TEMPLATE_JSON = "{ /* template config */ }";
}
Enter fullscreen mode Exit fullscreen mode

Initialize Both SDKs

public class ImageBenchmarkFragment extends Fragment {
    private CaptureVisionRouter cvRouter; // Dynamsoft
    private BarcodeScanner mlkitScanner;  // ML Kit

    private void initializeScanners() {
        // Initialize Dynamsoft
        cvRouter = new CaptureVisionRouter(requireContext());
        if (BenchmarkConfig.USE_CUSTOM_TEMPLATE) {
            cvRouter.initSettings(BenchmarkConfig.DYNAMSOFT_TEMPLATE_JSON);
        }

        // Initialize ML Kit
        BarcodeScannerOptions options = new BarcodeScannerOptions.Builder()
                .setBarcodeFormats(Barcode.FORMAT_ALL_FORMATS)
                .build();
        mlkitScanner = BarcodeScanning.getClient(options);
    }
}
Enter fullscreen mode Exit fullscreen mode

Run the Benchmark

private void runBenchmark() {
    if (selectedBitmap == null) return;

    // Test Dynamsoft
    BenchmarkResult dynamsoftResult = testDynamsoft(selectedBitmap);

    // Test ML Kit
    BenchmarkResult mlkitResult = testMLKit(selectedBitmap);

    // Display comparison
    displayResults(dynamsoftResult, mlkitResult);
}

private BenchmarkResult testDynamsoft(Bitmap bitmap) {
    BenchmarkResult result = new BenchmarkResult("Dynamsoft");

    CapturedResult capturedResult = cvRouter.capture(
        bitmap, 
        EnumPresetTemplate.PT_READ_BARCODES
    );

    if (capturedResult != null) {
        DecodedBarcodesResult barcodesResult = 
            capturedResult.getDecodedBarcodesResult();
        if (barcodesResult != null && barcodesResult.getItems() != null) {
            for (BarcodeResultItem item : barcodesResult.getItems()) {
                result.barcodes.add(new BarcodeInfo(
                    item.getFormatString(),
                    item.getText()
                ));
            }
        }
    }

    return result;
}

private BenchmarkResult testMLKit(Bitmap bitmap) {
    BenchmarkResult result = new BenchmarkResult("MLkit");

    InputImage image = InputImage.fromBitmap(bitmap, 0);
    List<Barcode> barcodes = Tasks.await(mlkitScanner.process(image));

    if (barcodes != null) {
        for (Barcode barcode : barcodes) {
            result.barcodes.add(new BarcodeInfo(
                getBarcodeFormatName(barcode.getFormat()),
                barcode.getRawValue()
            ));
        }
    }

    return result;
}
Enter fullscreen mode Exit fullscreen mode

Testing Different Scenarios

Test with various image types to evaluate real-world performance:

  1. High-Quality Images: Perfect lighting, sharp focus, direct angle
  2. Blurred Images: Motion blur, out-of-focus scenarios
  3. Low Light: Dark environments, shadows
  4. Rotated/Skewed: Angled barcodes, perspective distortion
  5. Damaged Codes: Partially obscured, worn labels
  6. Multiple Barcodes: Several codes in one image
  7. Small Barcodes: Codes from distance or low resolution

Video Benchmark: Real-World Scenarios

Video testing simulates continuous scanning scenarios like conveyor belt scanning or mobile scanning workflows.

video Benchmark

Implementation

public class VideoBenchmarkFragment extends Fragment {
    private static final long FRAME_INTERVAL_MS = 500; // 2 frames per second

    private void processVideo(Uri videoUri) {
        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
        retriever.setDataSource(requireContext(), videoUri);

        String durationStr = retriever.extractMetadata(
            MediaMetadataRetriever.METADATA_KEY_DURATION
        );
        long videoDurationMs = Long.parseLong(durationStr);

        // Extract frames at regular intervals
        List<Bitmap> frames = new ArrayList<>();
        for (long time = 0; time < videoDurationMs * 1000; 
             time += FRAME_INTERVAL_MS * 1000) {
            Bitmap frame = retriever.getFrameAtTime(
                time, 
                MediaMetadataRetriever.OPTION_CLOSEST
            );
            if (frame != null) frames.add(frame);
        }
        retriever.release();

        // Run benchmark on all frames
        BenchmarkResult dynamsoftResult = testDynamsoftVideo(frames);
        BenchmarkResult mlkitResult = testMLKitVideo(frames);

        displayVideoResults(dynamsoftResult, mlkitResult, frames.size());
    }

    private BenchmarkResult testDynamsoftVideo(List<Bitmap> frames) {
        BenchmarkResult result = new BenchmarkResult("Dynamsoft");
        Set<String> uniqueBarcodes = new HashSet<>();

        for (int i = 0; i < frames.size(); i++) {
            CapturedResult capturedResult = cvRouter.capture(
                frames.get(i), 
                EnumPresetTemplate.PT_READ_BARCODES
            );

            if (capturedResult != null) {
                DecodedBarcodesResult barcodesResult = 
                    capturedResult.getDecodedBarcodesResult();
                if (barcodesResult != null && barcodesResult.getItems() != null) {
                    for (BarcodeResultItem item : barcodesResult.getItems()) {
                        String key = item.getFormatString() + ":" + item.getText();
                        if (!uniqueBarcodes.contains(key)) {
                            uniqueBarcodes.add(key);
                            result.barcodes.add(new BarcodeInfo(
                                item.getFormatString(),
                                item.getText(),
                                i // frame index
                            ));
                        }
                    }
                }
            }
        }

        result.framesProcessed = frames.size();
        return result;
    }
}
Enter fullscreen mode Exit fullscreen mode

Video Test Scenarios

  • Conveyor Belt Simulation: Items moving past camera
  • Handheld Scanning: Natural movement and rotation
  • Batch Scanning: Multiple items in sequence
  • Varying Distance: Objects moving closer/farther from camera

Web Server Benchmark: Remote Testing at Scale

The web server mode enables team-wide testing and batch processing without requiring Android device access.

Server Implementation

public class BenchmarkWebServer extends NanoHTTPD {
    private CaptureVisionRouter cvRouter;
    private BarcodeScanner mlkitScanner;

    public BenchmarkWebServer(Context context, int port) {
        super(port);
        this.context = context;
        initializeScanners();
    }

    @Override
    public Response serve(IHTTPSession session) {
        String uri = session.getUri();

        if (uri.equals("/api/benchmark") && 
            session.getMethod() == Method.POST) {
            return handleBenchmarkRequest(session);
        }

        if (uri.equals("/")) {
            return newFixedLengthResponse(
                Response.Status.OK, 
                "text/html", 
                getIndexHtml()
            );
        }

        return newFixedLengthResponse(
            Response.Status.NOT_FOUND, 
            "text/plain", 
            "Not Found"
        );
    }

    private Response handleBenchmarkRequest(IHTTPSession session) {
        // Parse uploaded file
        Map<String, String> files = new HashMap<>();
        session.parseBody(files);

        String filePath = files.get("file");
        File uploadedFile = new File(filePath);

        // Process with both SDKs
        JSONObject result = processFile(uploadedFile);

        return newFixedLengthResponse(
            Response.Status.OK,
            "application/json",
            result.toString()
        );
    }

    private JSONObject processFile(File file) throws Exception {
        Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());

        JSONObject result = new JSONObject();
        result.put("dynamsoft", runDynamsoftBenchmark(bitmap));
        result.put("mlkit", runMLKitBenchmark(bitmap));

        bitmap.recycle();
        return result;
    }
}
Enter fullscreen mode Exit fullscreen mode

Web Interface Features

The benchmark includes a responsive web interface accessible from any browser:

  • Drag & Drop Upload: Upload single images or entire folders
  • Batch Processing: Test multiple files automatically
  • Real-time Results: See detection counts as files are processed
  • Cross-Platform: Test from desktop, tablet, or mobile

Usage Steps

  1. Enable web server in the app
  2. Note the displayed IP address and port (e.g., http://192.168.1.100:8080)
  3. Open the URL in any browser on your network
  4. Upload test images or videos
  5. Review comprehensive results showing barcode detection for both SDKs

    dynamsoft-mlkit-barcode-scanner-benchmark

Choosing Between the SDKs

Google ML Kit May Be Appropriate When:

  • Cost is a primary factor (no licensing fees)
  • Building prototypes, proofs-of-concept, or personal projects
  • Scanning environment is controlled (good lighting, stable positioning)
  • Barcode quality is consistently high
  • Integration simplicity is prioritized
  • Detection rates in the 75-90% range meet requirements

Dynamsoft Barcode Reader May Be Appropriate When:

  • Higher detection accuracy is required (90%+ range)
  • Scanning conditions vary (lighting, angles, distances)
  • Processing worn, damaged, or partially obscured barcodes
  • Missed scans have operational or safety implications
  • Advanced customization is needed
  • Direct technical support is valuable
  • Cross-platform deployment is planned

Source Code

https://github.com/yushulx/android-camera-barcode-mrz-document-scanner/tree/main/examples/mlkit-dbr-benchmark

Top comments (0)