はじめまして。株式会社シムネット、エンジニアアルバイトの和室です。
今回、FlutterとML Kitを使用して賞味期限を光学認識(OCR)するAndroidアプリを開発しました。
この記事では、本スマホアプリをどのように開発したのか、開発に用いたパッケージ、躓いたところをざっくり書いていきたいと思います。
はじめに
今回開発したのは、スマホのカメラで素早く、食料品のバーコードと賞味期限を正確に読み取ることが可能なアプリです。
このアプリによって、当社の健康専門店のような物流倉庫での、アナログな食品管理が簡易できるようになります。
アプリ概要とUX
どんなアプリかをざっくり見てもらうため、メインとなるスマホ画面を4枚ほどスクショしてきました。
このアプリでは、商品バーコードと賞味期限の読み取り、編集が可能です。
(商品バーコードスキャン)⇒賞味期限のOCR⇒データ編集&送信で1つのフローとなります。
多量の商品を管理する場面を考慮し、最短2タップで1つの商品情報を送信可能なUXとしました。
また、薄暗い倉庫での使用を想定しているため、カメラ使用時にはデフォルトでフラッシュライトがOnになっています。
製作工程
次のセクションでは、アプリを開発するに至った経緯と実装方法を記しておきます。
1. 現状の商品管理手法とそのボトルネック
業務最適化アプリを作る際に最初に行わければならない工程です。
現在の当社の倉庫では、商品が搬入される度に商品コード、現在の日時、賞味期限、個数の4つのパラメータを用いて、商品を管理しています。
この作業でボトルネックと考えられるのは、以下の通りです。
- 商品を確認しながら、賞味期限を手打ちする必要がある
- 大きな商品の場合、PCと商品の間を行き来する必要がある
- 打ち間違いや記憶違いなどのヒューマンエラーが起こりやすい
これらの問題を解決するため、今回のアプリ開発では「スマートフォンを利用して商品コード、現在の日時、賞味期限の光学文字認識(OCR)を実現すること」を目標としました。
2. 技術選定
上記を実現する際に重要となるポイントは、以下の2つです。
(a) OCRの正確さと迅速さの両立
(b) 多量の商品をテンポよく処理可能であること
⇒ ユーザに要求される操作を最小限とする(ストリーミング画像からのOCRの実現)
この2つを考慮して、今回の目玉となるOCR(光学文字認識)の実装手法について調査と検討を行いました。
候補として挙げられたのは、以下の3つです。
2. 自作OCR用機械学習モデル(このリポジトリのTBPPモデルを改造)を利用する手法
3. ML Kitの無料モデルを利用する
それぞれ試してみると、1つめは商品パッケージの様な色や書式が複雑な写真の場合だと認識精度が大きく低下すること、2つめは開発に時間がかかる割に認識速度がかなり低速であること、3つめは日本語が認識不可能なものの1, 2と比べて非常に高速&高精度かつ開発の手間なく認識が可能であることがわかりました。
そのため今回は、候補3のML Kit(無料のデバイス内蔵軽量OCRモデル)を使用することに。
また、開発コストを最小化するため、ML Kitと相性のよいFlutterを利用しました。
3.実装
ここでは、実装にあたって使用したパッケージや注意するポイントを示したいと思います。
OCRパッケージ
今回用いたflutter_camera_ml_visionは、ML Kitを利用したOCR & QRコード読み取り、ライブラリを提供するパッケージです。
これを動かすまでのdependencyを適切に記述する作業が、私にとっては最初の躓きポイントでした。
さまざまな記事が出回っていますが、きちんとpub.devの公式ページの手順通りに進めることで、なんとか動作までこぎつけることができました。ちなみに、ML Kitを用いてOCRを行う場合、クラウドコンピューティングを利用する従量課金制APIで実装する手法と、スマホ本体で計算させる無料の手法が利用可能です。
もちろん今回はストリーミング画像からの認識のため、APIの利用はコスト的に許されません。動作してからの注意点としては、ストリーミング映像に対してスマホ内蔵OCRモデルを動作させる場合、CameraMLVisionのプロパティでresolutionを” low”としておかないと、頻繁にアプリが落ちるようになってしまいます。
ただし、以上の設定はスマホの機種によってはうまく効果しないこともあるようです。当方の環境では”middle”としたときは動作しませんでした。バーコードリーダー
barcode_scanはバーコード読み取りパッケージです。私が試した限りでは、凹凸の激しいパッケージや暗すぎる場合を除いて、ほぼ正確にバーコードを読み込んでいました。
多様な書式の賞味期限の認識
OCRパッケージが読み込んだ文字列の中から、賞味期限を抜き出して認識しなければなりません。
賞味期限の表記方法は商品によって千差万別で「2021/04/15」「15. apr. 21」「21-apr」「21. 4. 15 」など、多様な表記手法があります。
正規表現と日付のバリデーションを行えば、ある程度の「年月日」は認識できますが、100%正確な「年月日」のタグを振ることは困難なため、「年月日を入れ替えるボタン」を採用しました。
このボタンを押すと、認識した賞味期限において「年月日」のタグ入れ替えが可能な場合のみタグを入れ替えます。
例: 2021/07/11 ⇒ 2021/11/07, 2021/12/23 ⇒ 2023/12/21また、認識される日付の正確性を向上させるため、過去13回の日付認識のうち4回以上同じ日付が現れた場合にのみ、賞味期限として認識しています。
フラッシュライト切り替え機能の追加
薄暗い倉庫での利用が想定される今回の開発では、必須となる機能の1つです。
とても簡単に見えるこの機能追加なのですが、
今回の実装で最も時間を取られたポイントでした。Flutterを用いると第三者の公開したパッケージを利用することで、爆速でアプリ開発が可能になります。
これはFlutterの大きな利点ですが、各外部パッケージに対して細かいカスタマイズをしようとすると、工数が一気に跳ね上がります。その理由は、Flutterパッケージがツリー状のdependencyの上に成り立っているからです。
つまり、外部パッケージはさらに他の外部パッケージを利用していることが多いため、やりたいことはイプパッケージの小さい修正だとしても、トレースしなければいけないプログラムが一気に増大してしまい、工数が一気に持っていかれるのです。
今回の場合、flutter_camera_ml_visionとCameraパッケージの2つのパッケージが関与していたことや、Androidネイティブを操作する必要があったため、DartとJava, Kotlinのコードに編集を加えることが不可欠でした。
4. 賞味期限OCR性能テスト
実際に当社の倉庫に搬入された商品パッケージの画像を用いて、賞味期限OCRの認識速度・精度を確認しました。
なお、速度は対象をカメラの中央に始めから捉えていた場合のスキャン開始~認識終了までの時間(s)となっています。
結果:およそ3秒程度で賞味期限を読み取り可能なことがわかりました。
読み取りが苦手なものとしては、凸凹のある表面に書かれた文字や読み取りにくいフォントで書かれた文字、イタリック体で書かれた文字などです。
また、缶やアルミなどの金属パッケージの場合、光の反射の影響で読み取り速度の低下や失敗が発生しやすくなります。
同じ商品で複数回試行した場合、9割程度の確率で同じ結果が返ってくることを確認しています。
画像 | 結果 | 認識速度(秒) | 所感 |
---|---|---|---|
2021/8/31 | 2.9 | 正解! | |
2020/2/7 | 2.7 | 正解! | |
2021/1/14 | 2.8 | 正解! | |
認識なし | - | 正解は2021/08/26だが、 文字フォントが見にくいためかうまく認識できていない | |
2021/9/26 | 2.2 | 正解は、2021/9/25惜しい! | |
認識なし | - | 凹凸による陰影が強すぎるためか 読み込めていない |
開発してみての所感と今後の予定
今回はFlutter+ML Kitを利用して、賞味期限と商品バーコードをOCRするスマホアプリを製作しました。
初のFlutterアプリでしたが、きちんと要求された仕様を満たせるアプリに仕上げられたので一安心しています。
ML Kitはスゴイというのが、率直な感想です。
また、Flutterはアプリ自体は非常に早く作れるものの、それをカスタマイズしたり少し変更したりする保守の観点からすると、運用が面倒くさいプラットフォームかと思いました。
(特に外部パッケージを多用すると、運用の際にバージョンの問題が大きな影響を及ぼしてしまうので、最小限の仕様に控えたいところです)
このアプリを実用化するための残りの工程としては、商品管理用DBの構築と操作用APIを作る。もしくは、取得した賞味期限や商品番号を登録用PCに無線送信する。
などの方法で、倉庫毎の管理者と相談のうえ、ソリューションを作る必要があると考えています。
以上、和室よりお送りしました!
後日……開発の内容は、シムネットのエンジニアチームに共有しました。