2
0

バーコード画像を解読するWebアプリケーション

Posted at

目的

Webページ上に<img>で表示した画像に含まれたバーコードを解読し、その値を文字列として表示します。こんな感じです。

処理には、画像処理ライブラリの定番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 のカーネルを調べる」にあります。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0