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.
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
-
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();
-
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 thedecode
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.
-
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>
-
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); } }
-
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); }
-
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.
-
Limited barcode types.
OpenCV Dynamsoft Barcode Reader 1D Types EAN-13
EAN-8
UPC-ACode 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 112D Types QR Code QR Code (including Micro QR Code)
Data Matrix
PDF417 (including Micro PDF417)
Aztec Code
MaxiCode (mode 2-5)
DotCode -
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.
-
Less customizability.
Dynamsoft Barcode Reader provides rich parameters to tune the decoding process (arthitecture).
-
Lack of commercial support.
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: