Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
CloudVisionAPIでOCRする
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
KosukeShimizu
October 03, 2023
Programming
210
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
CloudVisionAPIでOCRする
KosukeShimizu
October 03, 2023
More Decks by KosukeShimizu
See All by KosukeShimizu
Amazon Personalizeでやらかした話
thimi0412
0
890
Other Decks in Programming
See All in Programming
AI駆動開発にグラフDBを重ねてみた
satoshi256kbyte
2
760
GraphRAGのKnowledge Graphを 直接!見る/View-GraphRAG's-KnowledgeGraph-directly!
tyumugi1113
0
250
AWS Step Functions 大規模並列の壁を越える / jaws-sonic-2026-niigata-step-functions
kasacchiful
PRO
0
390
ALB ログから Trace を気合で繋げる技術
fohte
7
880
Hello, Hiroshima Geospatial Data! — Exploring DoboX with Python
ra0kley
0
180
書籍「プロフェッショナルAI駆動開発」紹介スライド
juntaromatsumoto
0
1.1k
新卒PdEのリアル
ryu1013
1
420
iOS開発×AI駆動開発 〜最近使って便利だったスキルの話〜
nogu66
0
140
Can LLMs Replicate 4 Years of Compose Migration? Exploring the boundaries of automation with 279 XML files from a real product
makun
0
130
新人はどこまで自力でやり、どこからAIに頼るべきか/エンジニア育成に向き合う_先輩たちの悩みと知見共有会
toppan_digital_dev
1
580
AWS DevOps Agentで インシデント対応をAIに任せたい
honmarkhunt
6
2.5k
kubernetes コンポーネント開発入門 / 新卒N年目の勉強会&交流会!〜〇〇への誘い〜 #n_study
mazrean
0
170
Featured
See All Featured
Unsuck your backbone
ammeep
672
58k
Evolving SEO for Evolving Search Engines
ryanjones
0
280
Site-Speed That Sticks
csswizardry
13
1.5k
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
370
Reality Check: Gamification 10 Years Later
codingconduct
0
2.3k
We Have a Design System, Now What?
morganepeng
55
8.3k
Jamie Indigo - Trashchat’s Guide to Black Boxes: Technical SEO Tactics for LLMs
techseoconnect
PRO
0
660
Bootstrapping a Software Product
garrettdimon
PRO
306
120k
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
820
How to Talk to Developers About Accessibility
jct
2
540
Getting science done with accelerated Python computing platforms
jacobtomlinson
2
470
職位にかかわらず全員がリーダーシップを発揮するチーム作り / Building a team where everyone can demonstrate leadership regardless of position
madoxten
69
65k
Transcript
© WED, Inc. WED株式会社 | Kosuke Shimizu CloudVisionAPIで OCRする
2 スライドのQRコード
CloudVisionAPIでOCRする 自己紹介 • Name: 清水 幸佑(Kosuke Shimizu) ◦ thimi0412 •
Language ◦ Python ◦ Go • Job: 2022-02 WEDにJOIN ◦ データエンジニア ◦ OCR周りの開発 ◦ データ基盤やデータパイプラインの作成 ◦ ML周りのインフラ基盤の作成 3
CloudVisionAPIと ONEのOCRについて 4
CloudVisionAPIでOCRする 5 VisionAPIの説明 • 顔検出 • 物体検出 • OCR(文字認識) •
ランドマーク検出 • etc… https://cloud.google.com/vision/docs/drag-and-drop
CloudVisionAPIでOCRする 6 ONEのOCRについて { "purchased_at": "2020-06-12", "address": null, "items": [
{ "name": "食パン", "quantity": 1, "price": 340 }, { "name": "塩レモン", "quantity": 1, "price": 350 } ], … } APIに画像を POSTしてJSON を取得する
CloudVisionAPIでOCRする 7 ONEのOCRについて Kubernetes Cluster GKE Multiple Instances Cloud Vision
API OCRサーバー 画像を送る OCR結果をもらう
CloudVisionAPIでOCRする • レシートをそれぞれの領域に分ける ◦ header ▪ 店名, 住所, TEL ◦
item ▪ 商品名, 値段, 個数 ◦ total ▪ 合計金額, 小計 ◦ footer ▪ sumより下部の領域 • おそらくheaderとtotalの部分に商品がある ◦ 商品名の右 or 右下に数字があるものを 商品名として抽出している ◦ 変なものも商品名として取得してしまう ことがある 8 商品名を取得する
CloudVisionAPIでOCRする 9 転生の時 OCRサーバーちょっと 根本的に書き換えたくない? 商品名にノイズがある 機械学習とかで いい感じにできないの? レシート以外もOCRすること あるし汎用的に作りたい
O S S
CloudVisionAPIでOCRする 10 清水の思考(土日) S • 機械学習のモデルとか組み込む からPythonで書くかぁ • PythonならFastAPIで書くかぁ •
どうせGKEで動かすから Dockerも必要かぁ • 多分商品名の抽出とかはML チームがやってくれるはず • まずは基盤となる OCR部分だけ作るかぁ
ここからは実装部分の話 11
CloudVisionAPIでOCRする 12 API呼び出し部分 from google.cloud import vision def text_detection( content:
str, vision_api_model: str ) -> vision.AnnotateImageResponse: image = vision.Image(content=content) client = vision.ImageAnnotatorClient(credentials=env.google_credentials) req = vision.AnnotateImageRequest( image=image, features=[ vision.Feature( type=vision.Feature.Type.TEXT_DETECTION, model=vision_api_model ), ], image_context={"language_hints": ["ja", "en"]}, ) response: vision.AnnotateImageResponse = client.annotate_image(req) return response
CloudVisionAPIでOCRする 13 API呼び出し部分 content: str = base64.b64encode(data).decode() response: vision.AnnotateImageResponse =
text_detection( content, "builtin/latest" ) • open関数でfile.read()したbytesをbase64で変換してデコードすれば使える • builtin/latestはVisionAPIで使用するmodelの名前 ◦ builtin/latest: 最新版 ◦ builtin/stable: 安定版 ◦ builtin/legacy: 古い版 ◦ 以前はbuiltin/stableを使っていたがbuiltin/latestにして 餃子という文字が鮫子と読んでしまう問題が解決した!
CloudVisionAPIでOCRする 14 レスポンスの中身を見てみる • response.text_annotations[0]には全てのOCR結果が入っている • index1以降はOCR結果が分割されたものが入っている • 基本的にはresponse.text_annotations[1:]を使用していく raw_text,
texts = response.text_annotations[0], response.text_annotations[1:] raw_lines = raw_text.description.split("\n")
CloudVisionAPIでOCRする 15 レスポンスの中身を見てみる { "description": "セブン", "bounding_poly": { "vertices" {
"x": 920, "y": 131 } "vertices" { "x": 1446, "y": 137 } "vertices" { "x": 1444, "y": 260 } "vertices" { "x": 919, "y": 254 } } } • bounding_poly.verticesに OCRされた文字を囲うx, y座標が格納されてい • 座標の順番は左下から反時計回り
CloudVisionAPIでOCRする 16 レスポンスの中身を見てみる [ "7 セブン-イレブン", "新宿余丁町店", "東京都新宿区余丁町10-10", "電話:03-3351-2122", "2023年09月10日
(日) 14:48", "領収書", "ダイソーキッチンペーパ-168枚", "ピルクル ミラクルケア", "195ml", "@135x 2", "炭火焼き豚丼", "小 計 (税抜 8%)", "消費税等 (8%)", "小計 (税抜10%)", "消費税等 (10%)", "合計", ... ] レスポンスはBlockという単位で分かれていて y座標でソートされていないので並び替えが必要 後ろのあるはずの 100がない
CloudVisionAPIでOCRする 1. 空のリストを作成 2. 各行の4点のX, Y座標の平均を計算 3. X, Y座標の平均と文字をリストに格納 4.
Y座標が近いもので1行を作成する a. Y座標の差が15以内だったら 同じ行と判定(勘) (p.s. ChatGPTに教えてもらいました) 17 Y座標で並び替える docs = [] for text in texts: vertices = [ {"x": vertex.x, "y": vertex.y} for vertex in text.bounding_poly.vertices ] # 頂点の座標の平均を取る average_x = sum([vertex["x"] for vertex in vertices]) / len(vertices) average_y = sum([vertex["y"] for vertex in vertices]) / len(vertices) docs.append( {"text": text.description, "vertex": {"x": average_x, "y": average_y}} ) # y座標でデータをソート sorted_data = sorted(docs, key=lambda x: x["vertex"]["y"]) # グループ分け groups = [] current_group = [] for i in range(len(sorted_data) - 1): current_group.append(sorted_data[i]) if ( sorted_data[i + 1]["vertex"]["y"] - sorted_data[i]["vertex"]["y"] > threshold ): groups.append(current_group) current_group = [] # 最後のグループを追加 current_group.append(sorted_data[-1]) groups.append(current_group) セブン ー イレブン 差が15以内
そして諸々作成したのが こちら(実演) 18
CloudVisionAPIでOCRする • 傾いた画像だとOCRしずらいので画像の傾きを補正する(済) ◦ MLチームの方が作ってくれた(あんまり理解してない) • 固有表現抽出等を使用して商品名などを抽出する ◦ T5(Text-to-Text Transfer
Transformer) で今いい感じに取れるらしい • レシート画像以外への対応 ◦ 新幹線の切符 ◦ そのほかチケットとか 19 今後やっていきたいこと
Thank You 20 今日使ったコード https://gist.github.com/thimi0412/d548cec8c132a0f299d1096cc4e908e0