Web Barcode Detector with OpenCV.js

OpenCV is an open-source computer vision and machine learning software library and has a basic barcode reading ability. It has a QR Code detector added in 2018 and a barcode detector added in 2021 which supports detecting and decoding of EAN-13, EAN-8, and UPC-A barcodes.

It has a JavaScript version based on WebAssembly which can run in the browser. In this article, we are going to build a web barcode detecter with OpenCV.js.

Online demo

Include the OpenCV Library in a Web Page

Include OpenCV with the following tag:

<script async src="https://docs.opencv.org/4.8.0/opencv.js" type="text/javascript"></script>

We can know its loading status in the onRuntimeInitialized event.

<!DOCTYPE html>
<html>
  <head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0" />
  <title>Web Barcode Detector with OpenCV.js</title>
</head>
<body>
  <p id="status">OpenCV.js is loading...</p>
  <script type="text/javascript">
    var Module = {
      // https://emscripten.org/docs/api_reference/module.html#Module.onRuntimeInitialized
      onRuntimeInitialized() {
        document.getElementById('status').innerHTML = 'OpenCV.js is ready.';
      }
    };
  </script>
  <script async src="https://docs.opencv.org/4.8.0/opencv.js" type="text/javascript"></script>
</body>
</html>

Then we can use the cv namespace to perform related functions.

Read Barcodes from an Image

  1. Initialize a barcode detector for reading 1D barcodes or a QR code detector for reading 2D barcodes.

    let 1DDetector = new cv.barcode_BarcodeDetector();
    let QRDetector = new cv.QRCodeDetector();
    
  2. Use the detector to read barcodes from an image element or a canvas element. We use the detect function to get the location of the barcode and then use the decode function to read the barcode content.

    let mat = cv.imread(imageSource);
    let points = new cv.Mat();
    detector.detect(mat,points);
    let result = detector.decode(mat,points);
    mat.delete();
    points.delete();
    

Read Barcodes from the Camera

We can use getUserMedia to open a camera and perform live barcode scanning.

  1. Add a video element and a canvas element in the HTML.

    <canvas id="hiddenCanvas" style="display: none;"></canvas>
    <video class="camera fullscreen" muted autoplay="autoplay" playsinline="playsinline" webkit-playsinline></video>
    
  2. Open the camera with getUserMedia.

    function loadDevicesAndPlay(){
      var constraints = {video: true, audio: false};
      navigator.mediaDevices.getUserMedia(constraints).then(stream => {
        localStream = stream;
        var cameraselect = document.getElementById("cameraSelect");
        cameraselect.innerHTML="";
        navigator.mediaDevices.enumerateDevices().then(function(devices) {
          var count = 0;
          var cameraDevices = [];
          var defaultIndex = 0;
          for (var i=0;i<devices.length;i++){
              var device = devices[i];
              if (device.kind == 'videoinput'){
                  cameraDevices.push(device);
                  var label = device.label || `Camera ${count++}`;
                  cameraselect.add(new Option(label,device.deviceId));
                  if (label.toLowerCase().indexOf("back") != -1) { //select the back camera as the default
                    defaultIndex = cameraDevices.length - 1;
                  }
              }
          }
    
          if (cameraDevices.length>0) {
            cameraselect.selectedIndex = defaultIndex;
            play(cameraDevices[defaultIndex].deviceId);
          }else{
            alert("No camera detected.");
          }
        });
      });
    }
    
    function play(deviceId) {
      stop(); // close before play
      var constraints = {};
    
      if (!!deviceId){
        constraints = {
          video: {deviceId: deviceId},
          audio: false
        }
      }else{
        constraints = {
          video: true,
          audio: false
        }
      }
    
      navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
        localStream = stream;
        var cameraVideo = document.getElementsByClassName("camera")[0];
        // Attach local stream to video element
        cameraVideo.srcObject = stream;
      }).catch(function(err) {
        console.error('getUserMediaError', err, err.stack);
        alert(err.message);
      });
    }
    
    function stop(){
      try{
        if (localStream){
          localStream.getTracks().forEach(track => track.stop());
        }
      } catch (e){
        alert(e.message);
      }
    }
    
  3. Add a function to capture a frame from the camera using canvas.

    function capture(){
      let video = document.getElementsByClassName("camera")[0];
      let canvas = document.getElementById("hiddenCanvas");
      let w = video.videoWidth;
      let h = video.videoHeight;
      canvas.width  = w;
      canvas.height = h;
      let ctx = canvas.getContext('2d');
      ctx.drawImage(video, 0, 0, w, h);
    }
    
  4. Start an interval to capture frames and read barcodes from the frames.

    function startDecodingLoop(){
      stopDecodingLoop();
      interval = setInterval(captureAndDecode,200);
    }
    
    async function captureAndDecode(){
      if (decoding) {
        return;
      }
      if (!cv) {
        return;
      }
      decoding = true;
      try {
        capture();
        let cvs = document.getElementById("hiddenCanvas");
        let results = decodeWithOpenCV(cvs);
        console.log(results);
      } catch (error) {
        console.log(error);
      }
      decoding = false;
    }
    
    function stopDecodingLoop(){
      clearInterval(interval);
      decoding = false;
    }
    

Other Usage

As OpenCV provides a rich collection of image processing methods, we can build our own barcode reader like this one or control the reading behavior using things like motion detection.

Limitations

Compared to commercial barcode reading SDKs like Dynamsoft Barcode Reader, OpenCV’s barcode detection has some limitations.

  1. Limited barcode types.

      OpenCV Dynamsoft Barcode Reader
    1D Types EAN-13
    EAN-8
    UPC-A
    Code 128
    EAN-8
    EAN-13
    UPC-A
    UPC-E
    Code 39 (including Code 39 Extended)
    Code 93
    Interleaved 2 of 5
    Industrial 2 of 5
    Codabar
    GS1 DataBar
    Postal Codes
    Patch Code
    GS1 Composite Code
    MSI (Modified Plessey)
    Code 11
    2D Types QR Code QR Code (including Micro QR Code)
    Data Matrix
    PDF417 (including Micro PDF417)
    Aztec Code
    MaxiCode (mode 2-5)
    DotCode
  2. Less robust.

    Dynamsoft Barcode Reader can read barcodes in various conditions, like damaged barcodes, shadowed barcodes, and wrinkled barcodes. Go to this dataset website to see what tough barcodes Dynamsoft Barcode Reader can read.

  3. Less customizability.

    Dynamsoft Barcode Reader provides rich parameters to tune the decoding process (arthitecture).

  4. Lack of commercial support.

Getting started with Dynamsoft Barcode Reader

Source Code

Get the source code of the demo to have a try. You can compare the performance of Dynamsoft Barcode Reader and OpenCV using this demo:

https://github.com/tony-xlh/web-barcode-detector-opencvjs