はじめに
最近、自炊しているが食費が高く,食材費を把握したくなった.
キャッシュレスサービス等で支出全体は把握できるが食材費に限定するには,レシートをOCRする必要がある.
レシートOCRは数社がサービスを提供しているが、読み取り精度が自身の要件を満たしていないため自作することにした.
シリーズ構成
- アーキテクチャ編 (本記事)
- バックエンド編 Part1 https://qiita.com/Himajiro2/items/c646459f33101c9dd2ea
- バックエンド編 Part2 (編集中)
- バックエンド編 Part3 (編集中)
- フロント編 (編集中)
要件
- スマホでレシートの写真を取ったらすぐにOCR結果が出力されること
- よく行く店のOCR精度は上げたい
- サービスは低コストで運用
今回見送ったこと
- 全てのレシートには対応していない
- 特に品目と金額が改行されているレシートには対応しない (対応工数が多く取られることと、普段行く店舗にはあまりなかったため)
- また、全てのレシートを汎用的にOCRする手法は見当たらないため対応しない
技術選定の前提
- 基本的には普段自分が使う技術を中心に選定
- バックエンドはサーバレスにし, バックエンド間の通信をEventarcで実現した
- 最初にスマートフォンアプリの「Googleレンズ」 → スプレッドシートに手動コピー → GASで整形
というものを作ったが、手作業をなくしたいため別の方法を検討. - Webが好きなのでWebで実現することにした.
技術選定
- フロント: Angular (Firebase Hosting)
- APサーバ: Flask (Cloud Run)
- OCR: Google Cloud Vision API (非常に精度が良く無料枠で十分に運用できそうだったため)
- ホスティング、認証、オブジェクトストレージ、DB: Firebase
- その他: Cloud Run間の通信はEventarc
Eventarcとは
Google CloudのリソースからCloud Runのサービスでイベントを送信できる機能.
GCPの監査ログから特定のログを読み取り, CloudEvents形式のイベントとしてCloud Runへ送信しサービスを起動できる.
また, 既存のPub/Subからトピックを読み取りトリガーとすることもできる.
Cloud Events
CNCFが定めるクラウドのイベント通知の標準仕様.
各サービスの職責
- フロント:
- レシート画像を撮影し,original-bucketにアップロード
- OCR結果の保存先であるFirestoreを読み込み表示する
- image-preprocess:
- original-bucketのレシート画像をバイリニア補正をかけて解像度を向上させる
- 補正後の画像をresampled-bucketに保存する
(レシート画像はJavaScriptのMediaDevices API経由で取得した画像ではOCR精度が低かったため補正をかけている) - vision-formatter:
- resampled-bucketの画像をGoogle Cloud Vision APIに渡す
- db-writer:
- vision-formatterから受け取ったVision APIの結果をFirestoreに格納する
今後
- OCRの部分が汎用的ではないため、まだ認識できないレシートがある.
- 今後は整形部分のロジックに汎用性を持たせ、店舗を判別して最適な整形ロジックを適用するなどに挑戦したい.
- その際、フロントでOCR結果を複数表示させ、最も精度が良いものを選び、この店舗はこのロジックが適しているなどの実績が取れるとサービス満足度の向上が期待できる.
- 各サービスのコード解説は別記事でまとめる