このライブラリは、画像ファイルだけでなくカメラを使ってリアルタイムでバーコードを読み取ることもできる。
今回はQuagga.jsを使って画像ファイルからバーコードを読み取れるようにする。
※ MBPのカメラだと認識率が悪いのでどうにかしたい。
Quagga.jsでバーコードを読み取る
<fieldset>
<label>バーコードの画像</label>
<input type="file" id="barcode">
</fieldset>
<div id="preview">
</div>
<fieldset>
<label>結果</label>
<input type="text" id="result" readonly>
</fieldset>
/* 画像用と認識場所を記したCanvasの2つが生成されるので重ねて表示する */
div#preview {
position: resolve;
width: 640px;
height: 480px;
> .imageBuffer {
position: absolute;
top: 0;
left: 0;
}
/* オーバーレイ */
> .drawingBuffer {
position: absolute;
left: 0;
}
}
// import Quagga.js
class BarcodeReader {
constructor() {
// 処理が完了したときに実行される
Quagga.onProcessed(this._onProcessed.bind(this));
// バーコードが読み取れたときに実行される
Quagga.onDetected(this._onDetected.bind(this));
}
get config() {
return {
// イメージソースの定義
inputStream: {
// イメージを表示する場所(デフォルトはid="interactive")
target: '#preview',
// Canvasのサイズ
size: 640,
singleChannel: false
},
locator: {
patchSize: "medium",
halfSample: true
},
// バーコードの種類
decoder: {
readers: [{
format: "code_128_reader",
config: {}
}]
},
// Web Workerの数
numOfWorker: navigator.hardwareConcurrency || 4,
// 画像内にバーコードの位置を示す(認識したときに枠で囲む)
locate: true,
// ↓ここにイメージソースを設置する
src: null
};
}
/**
* バーコードを読み込む
* @param {DOMString} src イメージソース
*/
decode(src) {
const config = Object.assign({}, this.config, { src: src });
return new Promise((resolve, reject) => {
Quagga.decodeSingle(config, result => {
resolve(result);
});
})
}
/**
* 処理が完了したときに実行される
*/
_onProcessed(data) {
const ctx = Quagga.canvas.ctx.overlay;
const canvas = Quagga.canvas.dom.overlay;
if (!data) { return; }
// 認識したバーコードを囲む
if (data.boxes) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
const hasNotRead = box => box !== data.box;
data.boxes.filter(hasNotRead).forEach(box => {
Quagga.ImageDebug.drawPath(box, { x: 0, y: 1 }, ctx, { color: 'green', lineWidth: 2 });
});
}
// 読み取ったバーコードを囲む
if (data.box) {
Quagga.ImageDebug.drawPath(data.box, { x: 0, y: 1 }, ctx, { color: 'blue', lineWidth: 2 });
}
// 読み取ったバーコードに線を引く
if (data.codeResult && data.codeResult.code) {
Quagga.ImageDebug.drawPath(data.line, { x: 'x', y: 'y' }, ctx, { color: 'red', lineWidth: 3 });
}
}
/**
* バーコード読み取りが成功したときに実行される
*/
_onDetected(data) {
}
getDataURL() {
return Quagga.canvas.dom.image.toDataURL();
}
}
function main() {
const barcodeReader = new BarcodeReader();
document.getElementById('barcode').addEventListener('change', async (e) => {
const file = e.target.files[0];
const src = window.URL.createObjectURL(file);
const result = await barcodeReader.decode(src);
document.getElementById('result').value = result.codeResult.code;
});
}
main();
画像ファイルを選択したときに、
Quagga.decodeSingle
を実行しデコードしている。Quagga.decodeSingleの第1引数で、バーコードの読み取り方や読み取った画像をCanvasに表示するための設定を行う。
基本的なプロパティは以下のとおり。
- inputStream: イメージやビデオのソースを定義する
- target: イメージやビデオを表示する要素のセレクター
- size: 表示する画像(Canvas)のwidth
- type: (ImageStream|VideoStream|LiveStream)などの指定
- decoder: バーコードを読み取るときの設定
- readers: バーコードの種類を指定
本来Class化する必要はないのだが、できればQuagga.jsをグローバルで持ちたくないのでスコープを狭くするために使っている(サンプルコードでは意味をなしておらず、本来は
import Quagga from 'quagga'
のように各ファイルでimportしたい)onProcessed
は、バーコードの読み込み処理が完了したときに実行される。callbackの引数の中には成功・失敗に関する情報が含まれている。
サンプルコードでは、callbackの引数に含まれる
box
, boxes
, line
を使って、オーバーレイ用のCanvasにバーコードを認識した印を描画している。onDetected
は、バーコードの読み込みが成功したとき(パターンを検出したとき)に実行される。callbackの引数にある
data.codeResult.code
にデコードされた文字列が格納されている。こんな感じにわりと簡単にバーコードを読み取ることができる。
ただdecodeSingleだと1画像に複数バーコードが入っていても1つしか読み取れない。
それを解消するためにはLiveStreamでビデオからバーコードを読み取る必要があるのだが、それはそれでバーコードの認識率が非常に悪かった。
もしかするとMacbook Proのインカメラの性能の問題な気もするけど…。
以上
written by @bc_rikko
ありがとう! 参考にさせてもらいます!
返信削除