MoreBeerMorePower

Power Platform中心だけど、ノーコード/ローコード系を書いてます。

Computer Vision Read APIで読み取ったレシート画像の行構造をLogic Apps上で再構成する

はじめに

先日Power AutomateとAI Builderを使って、レシート画像を読み取った方法のAzure版です。

mofumofupower.hatenablog.com

https://cdn-ak.f.st-hatena.com/images/fotolife/m/mofumofu_dance/20220202/20220202230658.png

この画像にあるように、ある程度の精度でレシートの行の構造を再現してみるという取り組みです。

ポイントになるのは、読み取り結果のテキストを、座標の左から右に、上から下になるように並び替えすることです。

Power Automateと同様に、Logic Appsにも配列のソート(並び替え)機能がないため、何らかのデータ置き場に一度読み取り結果を格納し、2つの軸で並び替えて取り出す必要があります。

https://cdn-ak.f.st-hatena.com/images/fotolife/m/mofumofu_dance/20220202/20220202000815.png

今回は、そんな2つの軸で並び替えて(Order Byして) 取り出し可能なデータ置き場として、Cosmos DBを採用することにしました。

リソース作成~複合インデックス (2軸で並び替えするための設定) については備忘録として以下の投稿で書いていますので、参考にしてください。

mofumofupower.hatenablog.com

全体の流れ

Logic Apps上のフローと各ブロックで大体何をしているのかを図示したものが以下になります。

f:id:mofumofu_dance:20220208225929p:plain
フローの全体と処理

フローのほうは小さくて見えないので、どのくらいの長さ・分量なのかの参考程度に。

また、今回のフローにはCosmos DBに登録したアイテムの削除処理が入っていません。通常は結果を返したあとにループやバッチで削除処理をいれますが、Cosmos DBでは自動削除機能 (Time to Live) がありますので、こちらを利用して、60分で消滅するようにします。

f:id:mofumofu_dance:20220208230503p:plain

では各部詳細にみていきます。

1. 画像取得~Read API実行

このフローはLINE Botに画像を送って結果を送り返すことを念頭においていますが、今回は簡単のために適当なURLから画像取得をして、Read APIに渡してあげます。

https://raw.githubusercontent.com/mofumofu-dance/PowerApps365/master/media/ocr_source.jpg

Read API 特に画像ファイルを渡す場合の手続きは過去の投稿を参考にしてください。

mofumofupower.hatenablog.com

このブロックのフローは以下の通りです。

f:id:mofumofu_dance:20220208234736p:plain

2. Cosmos DBへのアイテム登録~ソートして取得

Read APIの結果は下図のような構造になっています。ほとんどAI Builderと同じですが、座標を表すboundingBoxの構成が少し違いますね。

f:id:mofumofu_dance:20220208235448p:plain

ここはXY座標の組x4がずらずらっと並んでいます。読み方は以下を参照してください。

f:id:mofumofu_dance:20220208235615p:plain

今回使うのはTopLeftのX座標、Y座標、TopRightのX座標です。それぞれboundingBoxの0番、1番、2番が対応しています。

読み取り結果の登録にはFor eachのループを使います。

first(body('HTTP_2')?['analyzeResult']?['readResults'])?['lines'] をFor eachの入力とします。

Cosmos DBへのアイテム登録には "Create or update document (V3)" のアクションを利用します。

f:id:mofumofu_dance:20220208235953p:plain

"Document"のところには以下のJSONを設定してます。

{
  "id": "@{guid()}",
  "runId": "@{outputs('Compose')}",
  "text": "@{items('For_each')?['text']}",
  "txtLeft": @{item()?['boundingBox']?[0]},
  "txtRight": @{item()?['boundingBox']?[2]},
  "txtTop": @{item()?['boundingBox']?[1]}
}

このJSONを指定することで、読み取ったテキスト、その左上のXY座標、右上のX座標が保存されます。

登録した結果を取り出すには、”Query documents V5”のアクションを使います。

f:id:mofumofu_dance:20220209000348p:plain

どの値をとってくるか、並び替えをどうするかを指定するための SQL Syntax Queryには以下を指定します。

select c.text, c.txtTop, c.txtLeft, c.txtRight from c order by c.txtTop asc, c.txtLeft asc

これで登録~並び替え結果の取得までできました。このブロックのフローは以下の通りです。

f:id:mofumofu_dance:20220208234901p:plain

結果を見てみると、

なかなかいい感じで並び替え結果をとれましたね。(この時点ではあまりわからないけど)

f:id:mofumofu_dance:20220209000637p:plain

3. 条件付きで文字列結合

さて、並び替えができたので、あとは文字列結合をしていくだけです。

配列の中で隣接しているアイテムのtxtRighttxtLeftを比べて、折り返し判定を行っていきます。

https://cdn-ak.f.st-hatena.com/images/fotolife/m/mofumofu_dance/20220202/20220202000815.png

ここからは完全にPower Automateの場合と同じです。

For eachループには range(0,sub(length(body('Query_documents_V5')?['value']),1)) を指定します。これは [0,1,2,..] という連続した長さが 元の配列の要素数-1 の整数配列を生成しています。

あとは body('Query_documents_V5')?['value']?[item()]?['text'] 並び替えして取得した結果のN番目を取り出して、テキストを変数に追加していきます。

f:id:mofumofu_dance:20220209001021p:plain

条件分岐は、結果のN番目の右端 (txtRight)とN+1番目の左端 (txtLeft)を比べています。

ループの外側では並び替えて取得したの最終行を追加しています。

f:id:mofumofu_dance:20220209001406p:plain

これで条件付きで文字列結合ができました。

実際に実行してみる

サンプルの画像で読み取り~再構成の結果を見てみましょう。

https://raw.githubusercontent.com/mofumofu-dance/PowerApps365/master/media/ocr_source.jpg

結果は以下のようになりました。

@189x 3 *567
アソートドーナツ4個入り *298
白いわらびバニラ
@118x 2 *236
*195
森永inゼリー マルチミネラル *323
明治 アーモンドガンダムコラボ 200
ドウブツノモリ キャラマグネッツ 53
レジ袋特大1枚
レジ袋大1枚 ¥2,767
計(税抜 8%)
小 ¥221
消費税等(8%) ¥208
計(税抜10%)
小 ¥20
消費税等(10%) ¥3,216
計
合 ¥2,988)
(税率 8%対象 ¥228)
(税率10%対象

いかがでしょう。ちょっとヨレている箇所で、ずれがありますが、まっすぐ写真取れているところはうまく行を再構成できていますね。

ということで、一応はノーコードの範囲でレシートの画像から文字を読み取り、それっぽく構造を再現することができました。

今回のフローはちょっと入り組んでいますので、以下からダウンロードいただけます。Logic Appsでコード表示してコピペするためのJSONです。

github.com

使い方はReadmeを読んでみてください。