ZXingでバーコードアプリ開発(2)

前回の投稿の続きです。

2値画像化してからのバーコード認識にトライしていましたが、ようやくできました! とりあえずは。

Xamarin.AndroidのコードなのでAndroid限定ですが、Android.Hardware.Camera2 のキャプチャ画面からByte配列の画像データを取得するところは、

https://github.com/vtserej/Camera2Forms

を参考にしました。

このサンプルの中にある CameraViewServiceRenderer.OnPhoto() にて、画像のバイト配列が取得できるようになっています。

private void OnPhoto(object sender, byte[] imgSource)
{
    //imgSourceにカメラビュー画像が入っているので、
    //ここで煮るなり焼くなり


    Device.BeginInvokeOnMainThread(() =>
    {
        _currentElement?.PictureTaken();
    });
}

AndroidのCamera2からシャッター音を鳴らさずに無音で画像を取得するには、このサンプルがちょうどいいかと思います。

画像はARGB画像です。ARGBの4種類がそれぞれ1バイト(256諧調)なので、1ピクセル4バイトになります。

2値化画像にする手順は、

  • グレースケール化(RGBの3色の数値を平均化する)
  • 閾値を決めて、1ピクセルごとに「0 or 255」にする

ということになります。

これも変換関数を作って何とかなりました。・・・が、肝心のバーコード認識率はほとんど変わりませんでした。

それぞれ、生画像、グレースケール、2値化画像を比較したのですが、2値化の段階で1次元バーコードの斜め線になったところが「ギザギザ」になっていました。

また、照明の当たり具合はバーコードの部分ごとに異なることが当然あります。すると、ハレーションのような現象が出て、バーコードが部分的につぶれてしまいます。

下の画像は桁数がまあまあ多いGS1-128のバーコードで、真ん中あたりが照明で明るく照らされていたものです。

2値化したことにより、バーコードそのものが部分的にかすれてしまっています。

つまり、単純な2値化の閾値設定では状況の変化に対応できず、意味がないことが分かりました。今まで画像処理に縁がなかったのですが、なかなか手ごわいです。

画像処理のサイトを検索すると、いろいろな画像処理のテクニックがあるようですが、今のところ有効そうなのは、

  • カメラビューまたはグレースケール化のタイミングで解像度を上げる
  • 閾値方式だけではなく、周囲のピクセルとの比較によって白 or 黒を決定し、なめらかな線を目指す
  • 1ピクセルあたりのバイト数を減らす (高速化のため)

といったところでしょうか。(自分にできるのか不安)

GooglePlayを漁っていると、GS1-128でアルファベットや桁数を多く含み、しかも撮影条件が悪くても高速に読み取るソフトが中には存在します。キーエンスのハンディターミナルと同等レベル? ってぐらい優秀です。

一体、どうやって実現しているんだろうか?

[追記 2020-09-11]

GS1-128の読み取りが悪いですが、逆に、GS1-128以外はそれなりの読み取り速度なので、画像処理は時間がかかりそうなのであきらめました。今後の努力課題として、取り急ぎGS1 DataMatrixの生成処理をすることにしました。