🦊

Google Meet仮想背景のAIモデルを参考に開発した高速高精度なバーコードスキャナ

2021/05/19に公開2

こんにちは。

前回のブログでGoogle Meetの仮想背景用のAIモデルをwasm化したTensorflow Lite(TFLite)で動かす方法についてご紹介しました。今回は、この技術の活用先の一つとして、軽量、高速なバーコードスキャナを作成してみたのでご紹介したいと思います。

動作としてはこのような感じになります。様々の向きを向いている複数のバーコードを高速に読み取れています。
image

軽量Semantic Segmentationモデル

仮想背景で使われているAIモデルはSemantic Segmentationモデルと呼ばれます。このモデルは、写真などの画像のピクセル毎に何が写っているかを分類し、対象物が写っている領域を特定してくれます。例えば、下図のように、左の可愛い猫様の画像を入力すると真ん中のように猫様と背景の領域を特定した出力を出してくれます。これを人間に使って人間と背景の領域を特定して、背景の領域を別の画像に入れ替えることで仮想背景が実現されます。

image

AIモデルはその精度が重要視されることが多い印象ですが、仮想背景などのようにリアルタイムでの処理を必要とされる場合や、計算リソースが限られたデバイス上で動かす場合にはその軽量さも重要になります。現在もAIモデルの精度を上げたり軽量化をするために各所で研究が行われ、新しいAIモデルのアーキテクチャが考案されています。
Semantic Segmentationモデルのアーキテクチャは、大きく2つのコンポーネント(エンコーダとデコーダ)からなることが多いです。Google AI Blogによると、Google Meetでは下図のようにMobileNetV3-smallという軽量なモデルをエンコーダに用いたアーキテクチャを採用しているようです。デコーダ側はSynmetricということでMobileNetV3-smallと逆の処理を行っているように読めますが、詳細は書かれていません。

image

そこでエンコーダに使用されているMobileNetV3の論文を参照してみると、Semantic Segmentationについても言及されていました。そこにはデコーダについての記載もあり、Lite R-ASPPというモジュールを使って高速化しているという記載があります。なお、論文内ではエンコーダをバックボーンと呼んでおり、デコーダをセグメンテーションヘッドと呼んでいます。

image

これらを参考にすれば軽量なSemantic Segmentationモデルを作成できそうです。

仮想背景用の自作軽量Semantic Segmentationモデル

ということで、上記の情報を参考にアーキテクチャを設計しトレーニングを行いました。
セグメンテーションの精度は下図のような感じです。(1)が今回作成した軽量Semantic Segmentationモデルの結果です。(2)(3)はGoogle Meetの仮想背景用のモデルです。(4)はGoogleが公開しているSelfie Segmentationのモデルです。(4)と(2)(3)のモデルはほぼ同じアーキテクチャになっています。カッコ内はモデルへの入力画像の解像度です。

image

(1)は他に比べて体の一部がぼやけており精度が少し悪いことがわかります。一般にAIモデルの精度はトレーニングに使用する教師データの質と量に大きく依存すると言われています。今回はかなり頑張って人物の画像を集めてアノテーション(とAugmentation)を行いましたが、それでもやはりGoogleが用意できるものとは比較にはならない少なさだと思います。精度が悪いのはこの影響が大きいと思っています。
また、アーキテクチャにもある程度のGoogleの秘伝のタレがあるのかもしれません。後は、今回作ったモデルにバグがある可能性も。

次に1フレームあたりの処理時間を下に示します。処理の中にはモデルによる推論以外にも描画処理等も含まれています。カッコ内はsimdを有効化した場合の処理時間です。
解像度から考えると、ほぼGoogle Meetのモデルと同等の処理時間で動いているかなと思います。(simdで(1)と(2)が逆転しているのが謎ではありますが。)
image

以上、簡単にまとめると次のようになると思います。

  • 精度はGoogle Meetのモデルより数段劣っている。(定量評価してないざっくり感覚です)
  • 処理速度はほぼ同等を実現できている。

仮想背景の主要な目的はユーザのプライバシを守ることだと思います。これを鑑みるとSemantic Segmentationモデルの精度は一定の高いレベルのものが求めらると思います。高品質の教師データを大量に集められる見込みがないようであれば、上記(3)のSelfie SegmentationモデルがApache-2.0のライセンス(model card)となっていますので、おとなしくこちらを使ったほうが良さそうです[1]

なお、このデモは次のURLで公開しています。
https://flect-lab-web.s3-us-west-2.amazonaws.com/P01_wokers/tfl001exp_google-meet-segmentation/index.html

自作軽量Semantic Segmentationモデルのバーコードスキャナへの適用

自作の軽量Semantic Segmentationモデルを仮想背景に用いるのは、より精度の高い他の選択肢があるため得策ではないことがわかりました。しかし一方でかなり高速に処理できることもわかりました。このため、ある程度精度が低くてもその高速さが大きなメリットとなるユースケースなら十分に活用できそうです。

その一例として今回考えたのがバーコードスキャナへの適用です。
Github等で公開されている各種バーコードスキャナのソースコードを見た限り[2]、バーコードスキャナは画像の左上からシーケンシャルにエッジを検出して行き、エッジを検出するとそこからバーコードのデコードを行うという処理を行っているようです。このため、大きな画像からバーコードを読み取ろうとすると処理時間が増大してしまうと考えられます。単一のバーコードを読み取る想定であればバーコードを読み取った段階でアーリーリターンできますが、複数のバーコードを読み取る場合には画像の最後まで走査する必要があるのでこの影響が出やすいと予想されます(下図)。

image

今回のアイデアは、この前処理として自作の軽量Semantic Segmentationモデルを使用してバーコードが存在している可能性の高いエリアを切り出すことで、バーコードが存在しない部分でのバーコード検出処理を省くというものです(下図)。少し見方を変えて言うと、シーケンシャルに行っていたエッジ検出処理の一部を、Tensorflow Lite(+XNNPACK)で最適化された行列演算で一気に計算してバーコードの領域を検出する処理に置き換えるイメージになるかと思います(参考)。今回はブラウザ上で動かすことを想定しているので、複数の計算を同時に実行できるsimdを有効にすると特に効果が期待できそうです[3]。精度の面では、仮にバーコードがない部分を切り出したとしても、最終的にはバーコードスキャナが読み取れるか否かでバーコードの存在を確定できるのである程度の低くても大丈夫だろうという想定です。

image

評価・検証

自作軽量Semantic Segmentationを前処理にとして使ったバーコードスキャナ(Web版)を作成してみました。バーコードスキャナはOSSのZBarをwasm化したものを使用しています。
また、バーコードスキャナが読み取りしやすいようにSemantic Segmentationで検出したエリアの傾きを補正する処理も前処理として追加しています。

FullHDの画像を対象として動かした場合の挙動はこんな感じです。
左が(1)Semantic Segmentationを前処理として入れたバージョン、真ん中が(2)SIMDを有効化したSemantic Segmentationを前処理として入れたバージョン、右が(3)前処理を入れなかったバージョン(ZBarを単純にwasm化したもの)です。アニメーションの下にある'processing time'は1フレームあたりの処理時間(msec)です。使用しているデバイスはPixel4です。
なお、ZBar単体だとバーコードのエリアを検出できないのでオーバーレイ処理をしていません[4]

(1),(2)のほうがかなり精度高く、高速に動いています。バーコードのスキャン自体は同じソフトウェア(Zbar)を使っているので、(1)(2)の精度が高い理由はバーコードの角度を補正しているからと考えられます。
ezgif-7-e9957c3a895a

(Youtubeでも確認できます。https://youtu.be/Lv5dr2KD0H8)

HDだとこのようになります。処理速度は上がりますが少し検出精度が落ちています。これは、解像度が落ちているためで、一般的にバーコードをスキャンをするためには必要なサイズ(解像度)があります(参考)。これに近づくほどスキャンが難しくなります。HDで精度が落ちているのはこの理由と考えられます。

ezgif-7-71f35d519816

(Youtubeでも確認できます。https://youtu.be/2aYugJze0UE)

次に1フレームあたりの処理時間を下に示します。
FullHD, HDともに(1), (2)のほうが(3)より高速に処理できています。そして、simdを有効にした(2)がより高速に処理できています。なお、(1)(2)はバーコードの傾きを補正する処理が追加で入っているにもかかわらずに高速であることに注意が必要です。(3)については、FullHDとHDの処理時間を見ると予想通りほぼ総ピクセル数に比例する形で処理時間が伸びています。一方、(1),(2)はHDからFullHDに対してそこまで処理時間は増えてないです。外挿できるかは検証が必要ですが、おそらくより解像度の大きな画像を処理すると(1)(2)の優位性が増大するのではないかと考えられます。

image

以上より、軽量Semantic Segmentationを使って前処理を行うことで、従来のバーコードスキャナ(wasm版)より高速かつ精度の高いバーコード読み取り機能が作れたと言えそうです。つまり、ユースケースによっては、ある程度精度が低くても軽量Semantic Segmentationのアーキテクチャを用いたモデルが活躍できる場合がありそうです。

なお、このデモは次のURLで公開しています。
https://flect-lab-web.s3-us-west-2.amazonaws.com/P01_wokers/t12_barcode-scanner/index.html

議論

今回、バーコードスキャナの前処理として軽量Semantic Segmentationを用いてバーコードがありそうな領域を切り出すことで、後に続くバーコードスキャナのバーコード検出処理の一部を省き、処理全体の高速化を実現することができました。これは、シーケンシャルに行われていたエッジ検出処理を、最適化された行列演算処理によるバーコード検出処理に置き換えた効果だと考えています。もしこれが正しいのであれば、わざわざ前処理でAI(DNN)を使わなくても、バーコードスキャナ側を行列計算でバーコード検出をするように修正すればよいのではないかとも考えられます。私の考えでも、もしそれができるのであればそれは正しいと思います。ただ、バーコードスキャナのように既に枯れた技術として存在しているソフトウェアの内部処理を書き換えるのはかなりコストがかかり、デグレードのリスクが高いです。であるならば、今回のようにフレームワークとして最適化された行列演算処理が提供されているTensorflow Lite(+XNNPACK)を用いた軽量な処理を前処理として置くほうがコストやリスクが低く現実的ではないかと考えています。

またZBarをsimd化すると高速化するのではないかという疑問もあります。これは実際にsimdオプションをつけてビルドしてみましたが、ほぼ効果がなかったため今回は割愛しました。極力自力でSIMD化するなという話もあるようですが、本当にsimdの効果を発揮させるためにはある程度それを意識したコードを書く必要があるからだと思われます。

纏め

Googleが太っ腹にも軽量なSemantic Segmentationモデルの作り方を公開してくれていることに気づいたので、自作してみました。結果として、精度がイマイチですがかなり高速なモデルを作れることがわかりました。このモデルの適用先は仮想背景のような精度の高いモデルが必要とされるユースケースより、バーコードスキャナの前処理のようにある程度の精度で十分なユースケースに適すると考え、実験してみました。結果として、従来のバーコードスキャナより高速かつ高制度なバーコードスキャナを実現することができました。
バーコードスキャナへの適用は、自作軽量Semantic Segmentationの適用先の一例です。他にもある程度の精度で高速に動くSemantic Segmentationが活躍できる場があると思います。今後もなにか思いついたら試しに使っていきたいと思います。

リポジトリ

上記バーコードスキャナのデモは、次のリポジトリに格納してあります。

https://github.com/w-okada/image-analyze-workers

謝辞

人物の画像、人物の動画、背景画像はこちらのサイトの画像を使わせていただきました。
https://pixabay.com/ja/
https://www.pakutaso.com/

脚注
  1. Google MeetのSegmentationモデルのライセンスがApache-2.0から変更になった経緯があります。こちらもいつまでApache-2.0で公開され続けられるかわかりませんので、利用の際はご注意ください。 ↩︎

  2. 例えばZBarは、画像全体を左上から逐次的に微分フィルタを使用しながらエッジを検出を行っていき、エッジを検出した場合にバーコードのデコードを行っているようです(画像の走査(src1)エッジ検出とデコード呼び出し(src2))この処理は縦向き横向きそれぞれで行われています。(ちょっと難解なコードだったので理解が間違ってたらすみません)。 ↩︎

  3. SIMDによる高速化についてはこちらのブログを参照してくださいSupercharging the TensorFlow.js WebAssembly backend with SIMD and multi-threading↩︎

  4. 参考. この理由でバーコードの傾きも取得できず、ZBarについてはバーコードの角度を補正する処理を実装できませんでした。 ↩︎

Discussion

こーのいけこーのいけ

もう試されているかもしれませんが、ChromeブラウザのBarcode Detection APIだとどうでしょう?
wasm側から傾き補正したRGBAデータを作って返せばImageDataが作れてdetect()に渡せる気がします。

wokwok

コメントありがとうございます。実は、だいぶ前(出始めの頃)に試したのですが、当時は結構精度が悪く、そこまで高速でなかった記憶です。アップデートされているかもしれないので、今度試してみたいと思います。