目的
Webページ上に<img>
で表示した画像に含まれたバーコードを解読し、その値を文字列として表示します。こんな感じです。
![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F2712175%2Fc8e1c0a2-572c-9005-ebe7-0d1ad760d7ec.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=e5b4db4f8e3c0c3a1295bb517e440a81)
処理には、画像処理ライブラリの定番OpenCVを使います。JavaScript版なので、OpenCV.jsと呼ばれます。
JavaScriptなので、<script src="opencv.js">
で読み込むだけでWebページ上で動作させられます。HTML5やCSSでは達成できない、顔認識や機械学習など高度な画像処理を扱うWebアプリケーションの構築に利用できます。
OpenCV.jsを始めるなら、まずはOpenCV公式ドキュメントのOpenCV.js Tutorialsがおすすめです。英語はちょっと... という向きには、『OpenCV.jsで作る画像・ビデオ処理Webアプリケーション』という書籍もあります(2024年6月刊)。
注意
本記事のコードをローカル(file:///
)から実行すると、CORS(Cross-Origin Resource Sharing)絡みのエラーが発生します。Webサーバから実行するなどの措置が必要です。
コード
HTMLコードは次のとおりです。
<!DOCTYPE html>
<html lang="ja-JP">
<head>
<meta charset="UTF-8">
<script async src="https://docs.opencv.org/master/opencv.js"></script>
</head>
<body>
<h1>バーコードを読む</h1>
<div><img id="imgTag" src="IMG_1090.png"></div>
<div><span id="spanTag" width="100">解読結果</span></div>
<script>
let imgElem = document.getElementById('imgTag');
let spanElem = document.getElementById('spanTag');
function imgProc() {
let src = cv.imread(imgElem);
let gray = new cv.Mat();
cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY);
let detector = new cv.barcode_BarcodeDetector();
let pointsMat = new cv.Mat();
let ret = detector.detect(gray, pointsMat);
console.log(`Detection: Success=${ret}.`);
let text = detector.decode(gray, pointsMat);
spanElem.innerHTML = `解読結果: ${text}`;
}
var Module = {
onRuntimeInitialized: imgProc
}
</script>
</body>
</html>
解題
OpenCVのクラスや関数の用法は、C++あるいはPython版とおおむね同じです。公式APIドキュメントにJavaScript版の説明はないので、たいていはC++のものを参考にします。
OpenCV.jsの読み込み
<script async src="https://docs.opencv.org/master/opencv.js"></script>
あらかじめダウンロードしておいて、<script src="libs/opencv.js">
のようにローカル(相対)指定することもできます。
ファイルが読み込まれれば、以降、OpenCV.jsの関数および定数群はcv
を経由してアクセスできます。
画像の読み込み
<div><img id="imgTag" src="images/IMG_1090.png"></div>
let imgElem = document.getElementById('imgTag');
let src = cv.imread(imgElem);
HTMLの<img>
に取り込んだ画像をOpenCVで扱う構造体に読み込むには、cv.imread()
を使います。引数には<img>
のオブジェクトを指定します。
戻り値はピクセルデータとメタデータを収容した構造体(クラス)のcv.Mat
です。C++ならcv::Mat
クラス、Pythonならnumpy.ndarray
に相当します。
色変換
let gray = new cv.Mat();
cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY);
画像はいったんグレースケールに変換します。バーコード検出関数はカラーも受け付けるのですが、OpenCVのカラーは順序が異なるBGRなので、どのみち色変換は必要です。
色空間変換のcv.cvtColor()
は第1引数に入力画像を、第2引数には出力画像を、第3引数には変換方式を指定します。画像はどちらもcv.Mat
オブジェクトです。
第3引数の変換方式はOpenCVの定数から指定します。cv.COLOR_RGBA2GRAY
はRGBAをグレースケールに変換します。アルファ入りなところに注意してください。<img>
で読み込んだ画像は、もとがRGBだっとしても、内部で完全非透明のアルファが補完されるからです。
バーコードクラスのインスタンス化
let detector = new cv.barcode_BarcodeDetector();
バーコード解析クラスをcv.barcode_BarcodeDetector()
からインスタンス化します。C++版だとcv::barcode::BarcodeDetector
という名称のコンストラクタですが、JavaScript版ではもとのクラス名とコンストラクタ名を_
で連結した命名になっています。引数にはなにも指定する必要はありません。
バーコードの検出
let pointsMat = new cv.Mat();
let ret = detector.detect(gray, pointsMat);
console.log(`Detection: Success=${ret}.`);
BarcodeDetector.detect()
メソッドは、第1引数に指定した画像から検出したバーコードの位置(4隅の座標)を第2引数に返します。受け手の第2引数がcv.Mat
なところがポイントです。収容される値のデータ型は32ビット浮動小数点数です。
メソッドは検出の成否をBoolean
で返します。
バーコードの解析
let text = detector.decode(gray, pointsMat);
spanElem.innerHTML = `解読結果: ${text}`;
BarcodeDetector.decode()
メソッドでバーコードを解析します。第1引数には検出時の画像を、第2引数にはdetect()
で得た座標値リストをそれぞれ指定します。
メソッドは検出結果を文字列で返すので、ここでは、結果をそのまま<span>
のところに書き込んでいます。
ちなみに、BarcoceDetector
には検出と解析を一気に行うdetectAndDecode()
メソッドもあります。画像中の複数のコードを一気に検出するのなら、detectAndDecodeMulti()
を使います。
OpenCV.jsの準備ができたことを確認
var Module = {
onRuntimeInitialized: imgProc
}
JavaScript版固有な注意点の中でも最も重要なのは、非同期処理です。OpenCV.jsライブラリが準備完了するまでは、OpenCVの機能は使えません。完了前にcv....
を呼び出すと、そんなメソッドや定数はないというエラーが上がります。
そこで、OpenCV.jsの準備が完了したら処理関数を呼び出すように、コールバックを設定します。これが、コード末尾にあるonRuntimeInitialzied: imgProc
です。
onload()
は利用できません。スクリプトファイルが読み込まれた時点で発火してもらっても、その時点ではまだOpenCVが利用可能ではないからです。使えるようになるのはさらにそのあと、内部のバイナリ(WebAssembly)の展開が完了してからです。
おわりに
話を簡単にするため、画像は<img src="...">
でハードコードしています。<input>
からアップロードできるようにしたり、カメラ映像を使えるようにするともっとアプリケーションらしくなりますが、割愛しています。検出個所を四角いフレームで囲うとさらによいですが、それも省いています。
そうした付加機能は、『OpenCV.jsで作る画像・ビデオ処理Webアプリケーション』(秀和システム, 2024年6月)のサンプルでは加えてあります。取り上げているのはQRコードの検出と解読ですが、1次元、2次元ともにcv.GraphicalCodeDetector
の子なので、要領は同じです。
ご購入はこちらから【 honto(電子のみ) | amazon.co.jp | ヨドバシカメラ | Rakuten 】。
蛇足ですが、OpenCV.jsはNode.jsでも使えます。簡単なサンプルは「GaussianBlur のカーネルを調べる」にあります。