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
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
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
From 6 People Classroom Meetup to 100 People Regional Conference / FOSS4G Hiroshima 2026
furukawayasuto
0
110
Go を使い始めて 2 ヶ月の学び / My first two months with Go
contour_gara
0
420
AIを上手に使っていこうとしたら越境せざるを得なくなった話 〜実践1年で見えた境界を越えなければならない理由と進め方〜 / Crossing borders with AI
tomoyakitaura
3
1.1k
Webエンジニアなのにブラウザの仕組みがわからないので、Pythonで自作してみた
tatsuki12
4
1.7k
Swift愛好会100回記念 第1回を振り返る
jollyjoester
0
120
AI時代に学ぶ 好きなルール 嫌いなルール Linter編
shorty5121
0
860
私のClaude Code活用法 (個人開発編) - PHPerKaigi mini #4(2026/08/24)
panda_program
1
210
{ Android | Kotlin } Gradle Plugin in 2026
ryunen344
1
290
이 함수, 실패하면 어떻게 되나요? null부터 Rich Errors까지, Kotlin 에러 처리 15년
haeti2
0
140
Swift愛好会と私(ウホーイ) / Swift Fan Club and Uhooi
uhooi
0
140
業務時間外もAIに働いてもらう話
colorful12
3
10k
「AI時代、配布するPythonコードをどう守るか: 難読化の実験と判断軸」 #PyconJP2026
pkshadeck
PRO
2
170
Featured
See All Featured
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
920
Have SEOs Ruined the Internet? - User Awareness of SEO in 2025
akashhashmi
0
490
The #1 spot is gone: here's how to win anyway
tamaranovitovic
3
1.2k
Agile that works and the tools we love
rasmusluckow
331
22k
How to make the Groovebox
asonas
2
2.4k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
Heart Work Chapter 1 - Part 1
lfama
PRO
8
36k
Code Review Best Practice
trishagee
74
20k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
128
56k
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
120
120k
Google's AI Overviews - The New Search
badams
0
1.6k
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