Google Vision API の手書き文字認識(英語)を試す
経緯
どこかのニュースサイト(英語)でGoogle Nextで発表された新機能として"hand wrtten"(手書き)という文字があったのでググってみたところ、 Google Vision APIのドキュメント(英語の方)にさり気なく"Detecting Handwriting"という記述を発見。
下記のリンク先のページで一番下までスクロールすると言語の切り替えボタンがあります。
Optical character recognition (OCR) | Cloud Vision API Documentation | Google Cloud
文字認識の際に指定するFeature typeは2種類ありますが、手書き文字認識に対応するのはDOCUMENT_TEXT_DETECTION
。
日本語非対応な上にβ版ですがせっかくなので試してみました。
コードと画像
サンプル画像とJupyter Notebookを以下のリポジトリにおいてみました。興味があればどうぞ。
GitHub - atuyosi/VisionAPI_Trial: Tiny sample for Google's Cloud Vision API
環境構築
GCPのアカウントおよびAPIの有効化はすでに完了済みとします。
Web APIなのでJSONでリクエストを組み立てればい良いのですが、怠惰なのでgoogle-cloud-vision
というライブラリを使います。
$ python3 -m venv venv $ source venv/bin/activate $ pip install google-cloud-vision google-cloud-core google-cloud-storage
だってJSON、地味に面倒じゃないですか。しかも画像をJSONエンコードしなくていいというメリットもあります。
名前が名前だけにググったときにサクッと意図したページを見つけにくいというのが欠点です。
コード
基本的な使い方
$ export GOOGLE_APPLICATION_CREDENTIALS=/path/to/your-credential.json
環境に合わせて修正して下さい。
オプション指定なしでVision APIによる文字認識の最低限のスクリプトは以下になります(DOCUMENT_TEXT_DETECTION
)。
from google.cloud import storage from google.protobuf import json_format from google.cloud import vision_v1p3beta1 as vision client = vision.ImageAnnotatorClient() filename = 'sample.jpg' response = client.document_text_detection(image=open('sample.jpg','rb'))
document_text_detection))
をtext_detection()
に変更するとFeature TypeがTEXT_DETECTION
になります。
参考?:a244.hateblo.jp
手書き文字認識のテスト
手書き文字として非常に適当な漢字の画像を用意しました。字が汚くてすいませんって感じですが。
※ 画像は縮小済みです。
API側のバージョンは別にv1p3beta1
でなくてもいいかも。
通常の文字認識との違いは、手書き用のヒントを指定するかどうか。ドキュメントのサンプルコードによれば以下の2種のいずれか。
- en-t-i0-handwrit
- mul-Latn-t-i0-handwrit
# Language hint codes for handwritten OCR: # en-t-i0-handwrit, mul-Latn-t-i0-handwrit # Note: Use only one language hint code per request for handwritten OCR.
上記を踏まえたサンプルコード。
filename = 'handwritten.png' client = vision.ImageAnnotatorClient() image = vision.types.Image() # image.source.image_uri = uri # uri: The path to the file in Google Cloud Storage (gs://...) image.content = open(filename, 'rb').read() image_context = vision.types.ImageContext( language_hints=['en-t-i0-handwrit'] # language_hints=['mul-Latn-t-i0-handwrit'] ) response = client.document_text_detection(image, image_context=image_context) if response.error.code == 0 : print(response.text_annotations[0].description) else: print("Error code: {}".format(response.error.code))
認識結果
出力は以下のようになります。今回の画像については'en-t-i0-handwrit'指定しないほうが結果は良好でした……。
手書き用のヒントあり('en-t-i0-handwrit')
Hello, would Happy Hacking Thank you 2018 Aug. 10 012345 6289 Q
"World"と感嘆符、それに数字の7、末尾のα、βなど認識できていないという結果。
手書き用のヒントなし
上記のコードを修正してimage_context
オプションを指定しない場合の結果です。
Hello, World, Happy Hacking Thank you. 2018 Aug. 10, 012345 6789 ap
これはちょっとどういうことなの……。筆記体*2じゃないとダメなのか。
参考:TEXT_DETECTION
の場合
ドキュメントにある通り、手書きは非対応のようです。
language_hit
に'en-t-i0-handwrit'をセットしてもエラーにはなりませんが、出力は変わりませんでした。
print(response.full_text_annotation.text) Hells, world Thank yo 208 Aug 6s
明らかに手書きはダメダメ。
これまでTEXT_DETECTIONと
DOCUMENT_TEXT_DETECTION`に明確な差があるのかよくわからない状況でしたが、ここにきて差別化を図ってきたということでしょうか。
個人的にはTEXT_DETECTION
の方を手書き対応させる方が名称の点では自然だと思った。
どちらかというとDOCUMENT_TEXT_DETECTION
は名前からして(フォーマルな)文書イメージからの文字認識という印象だったのでちょっと意外。
TEXT_DETECTION
なら情景画像認識でも違和感ないし、壁の落書きのような手書き文字に対応するのは違和感がない。
Googleの技術陣の考えることはよくわかりません。
そのほか
上記のコードは違う書き方もできます。
filename = 'handwritten.png' client = vision.ImageAnnotatorClient() response_d = client.annotate_image({ 'image': {'content': open(filename, 'rb').read() }, 'features': [{'type': vision.enums.Feature.Type.DOCUMENT_TEXT_DETECTION}], 'image_context': { 'language_hints': ['en-t-i0-handwrit']}, })
中途半端にJSON風味。
ドキュメントへのリンク
- Optical character recognition (OCR) | Cloud Vision API Documentation | Google Cloud ※ 英語の方
- Vision — google-cloud 4256b47 documentation
- python-docs-samples/beta_snippets.py at master · GoogleCloudPlatform/python-docs-samples · GitHub
結論
ちょっとテスト用の画像が残念だったのかなと反省しています。
(TEXT_DETECTION
は手書き文字を受け付けないが)DOCUMENT_TEXT_DETECTION
は手書き文字(英語)を認識できる。
現状は英語とラテン文字のみ手書き文字認識対応。他の言語にも将来対応するんでしょうけど。
正直に言うと、はじめからデジタルで入力すればいいのに、というのが私の見解です。
なお、Microsoftの文字認識APIもいつのまにかアップデートしていて、そっちも英語は手書きに対応しているらしいのでそのうち試す予定。
Google Cloud Vision APIとPythonで文字認識
- 作者: machine powers
- 発売日: 2018/09/14
- メディア: Kindle版
- この商品を含むブログを見る
書評:『逆引きPython標準ライブラリ』
図書館にあったので借りてみました。読んだというより何が書いてあるのか眺めたという感じですが。
結論:微妙。
はっきり言っておすすめしません。3,000円出せるなら他の本が良いでしょう。
読み始めて最初のうちは役に立つと思いますが、すぐに物足りなくなると思います。
概要
逆引きPython標準ライブラリ 目的別の基本レシピ180+! (impress top gear)
- 作者: 大津真,田中賢一郎
- 出版社/メーカー: インプレス
- 発売日: 2018/02/19
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る
あまりPythonでコードを書かない人が書いているという印象を受けた。
対象となっているPythonのバージョンは3.6.3。
対象読者は「Pythonの文法を知っている人」と記載がある。
オライリーの「入門Python3」のそれぞれの後半部分をダイジェスト化して3で割ったような本*1。
標準ライブラリ限定なので必然的にNumpyやPandasの機能は紹介されていない。
購入してよかったと思うユーザーは限られると思和ざるを得ない。
説明そのものは基本的に丁寧な文章で読みやすいです。ただ、関数なりメソッドの使い方が丁寧に紹介されている箇所とそうでない箇所の差が激しいので入門書読んだだけのレベルでは混乱しかねないという印象です。
そのままサクッとコピーできるようなレシピ集ではありません。
内容について
標準ライブラリというより基本データ型に対する解説が多いので非常に中途半端な感じになっている。 全体的に駄目なポイントをいくつか。
- 目次の「やりたいこと」のレベルが雑(粒度が細かすぎる)
- ページレイアウト、特に各ページの見出しがいまいち(インポートするモジュール名がぱっとみてわからない)
- 入門書に書いてあるレベルの事柄にページを使いすぎ
- 索引がしょぼい
ページ数の配分も疑問。第1章から第3章はまともなPythonの解説書なら書いてあるレベル。
些細なことではあるけど関数とメソッドの違いは意識して欲しいと思った。
以下、各章別の疑問点。
Introduction
Pythonの文法を知っている人が対象読者と明記しているのにPythonのインストール方法を解説している。コンセプトがぶれ過ぎではないか。
pip freeze
をインストール済みパッケージの表示コマンドとして紹介している(普通はpip list
)- 標準ライブラリを対象にしているのに
pip
コマンドやAnacondaの解説をしている
Atomエディタの解説は悪くない。
第1章〜第3章
まともなPythonの入門書なら書いてあるレベルの内容*2。
逆引きスタイルの書籍にするからこういう初歩的な内容にページを割く必要が出てくるのではないか。
文字コードの話が出てこないのは残念。ユニコードのコードポイントと文字の変換のトピックがあるのに……。
参考:7.2. codecs --- codec レジストリと基底クラス — Python 3.6.6 ドキュメント
ついでにいうと改行コードの変換の話も無い。
新しい機能である正規表現のmatch
オブジェクトのインデックス表記(Ruby風)の記載もない。
第4章、第5章
ファイル操作と時刻、数学関数、乱数など。入門書によっては解説がないので有益ではある。
pathlib
も紹介してほしかった。
第6章
普通の入門書でネットワークがらみの機能解説はないので役に立つかも。ただし、オライリーの「[入門Python3](https://amzn.to/2ONjl6f9」には解説があったはず。
実際問題としてはこういうトピックを扱うなら標準ライブラリにこだわらずにFlaskの初歩を解説してくれたほうがありがたい。
- 作者: Michal Jaworski,Tarek Ziade,稲田直哉,芝田将,渋川よしき,清水川貴之,森本哲也
- 出版社/メーカー: KADOKAWA
- 発売日: 2018/02/26
- メディア: 単行本
- この商品を含むブログを見る
第7章
タートルグラフィックスのためのモジュールの使い方を「逆引き」で知りたい状況はちょっと想像がつかない。
ここにページを割くなら第8章を充実させた方が良かったのでは。
- 作者: Mark Summerfield,斎藤康毅
- 出版社/メーカー: オライリージャパン
- 発売日: 2015/12/01
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る
第8章
わずか18ページ……。
ここでは、知っておくと便利なクラス、関数などをランダムに取り上げます。
流石にランダムは困るよ、ランダムは。カテゴリにとらわれないといいたいんだろうけど。
それとこの章の組版は疑問。他の章とこの章はレイアウトが違うのだから組版も変えてほしかった。 モジュールの一部の機能だけ紹介する内容なのだから、まずモジュール名なりクラス名を知りたい。そこでメソッドの名前なりクラスのコンストラクタをデカデカと強調されてもありがたくない。
argparse
は解説少なすぎ。
まとめ
パラパラと眺めた結果、他の本の良さを再認識しました。
プログラム未経験で「プログラミング未経験者向けのPython入門書」を読んだだけの状態なら役に立つかも。
グーグル検索なりQiitaの記事から必要な情報を読み取れるレベルなら無駄。標準ライブラリに限定されているせいで中途半端。
やや古いけど、冒頭で紹介したオライリーのPython本のほうが買ってから永く間役に立つと思う。
退屈なことはPythonにやらせよう ―ノンプログラマーにもできる自動化処理プログラミング
- 作者: Al Sweigart,相川愛三
- 出版社/メーカー: オライリージャパン
- 発売日: 2017/06/03
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (6件) を見る
PythonのWebスクレイピング解説書の比較メモ
全部買ったわけではないですが、購入検討ように比較したメモ。
初歩的なレベルであればブログやQiitaに記載されている記事でなんとかなる場合が多いですが、クローラーを作成してがっつりやるなら一冊買って持っておいたほうがいいはず。
意識したポイント
残念ながら網羅できていないです。
- Javascript対策の有無
- ログインの必要なページへの対処方法が記載されているか
- Selenium WebDriver
- Xpath、CSSによる要素の絞り込みの解説
- サンプルコードのライセンス
- 環境構築の方法と解説
現在発売されている本で紹介されているPhantom.jsは開発が終了しているので非推奨。また、基本的にどの本もコマンド操作によるスクレイピング方法も紹介している。
オライリー
- 作者: Ryan Mitchell,嶋田健志,黒川利明
- 出版社/メーカー: オライリージャパン
- 発売日: 2016/03/18
- メディア: 大型本
- この商品を含むブログ (2件) を見る
出版社サイト:O'Reilly Japan - PythonによるWebスクレイピング
オライリーのスクレイピング本。サンプルコードについての扱いは他のオライリー本と同様、自由にして良い。
基本的に対象のPythonのバージョンは3系。Scrapyのサンプルのみ2.7。
- BeautifulSoup
- Scrapy (python 2.7)
- Phantom.js
- TesseractでCAPTCHAを突破する事例(不完全?)
- クッキー、入力フォーム対策
- Xpathはコラムで解説
- スクレイピングについての倫理に関する説明あり(+付録も)
- pdfniner3kが紹介されているが、個人的には
pdfminer.six
を推奨。
240ページ強と薄い。ちょっと古いのが難点。付録にPythonの文法解説あり。
『Pythonクローリング&スクレイピング』
Pythonクローリング&スクレイピング -データ収集・解析のための実践開発ガイド-
- 作者: 加藤耕太
- 出版社/メーカー: 技術評論社
- 発売日: 2016/12/16
- メディア: 大型本
- この商品を含むブログ (3件) を見る
出版社サイト:Pythonクローリング&スクレイピング ―データ収集・解析のための実践開発ガイド―:書籍案内|技術評論社
環境構築の解説は最も丁寧。
動作環境はPython 3.5 (macOS)/ Python 3.4 (Ubuntu)。 簡単なPythonの文法の解説あり。
- Vagrand(VirtualBox)
- Beautifulsoup4
- Scrapy
- PDFのパース(PDFminer)
- OpenCVで顔認識
- クラウド連携
著作権などの注意はこちらが詳しい。CSSセレクタおよびXPathについての解説はないが、解説なしにサンプル内で使用されている。
『Pythonによるクローラー&スクレイピング入門』
Pythonによるクローラー&スクレイピング入門 設計・開発から収集データの解析・運用まで
- 作者: 加藤勝也,横山裕季
- 出版社/メーカー: 翔泳社
- 発売日: 2017/10/23
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (3件) を見る
出版社サイト:Pythonによるクローラー&スクレイピング入門 設計・開発から収集データの解析・運用まで(加藤勝也 横山裕季)|翔泳社の本
明らかにプログラマ、エンジニア向け。
特にあまりネットで記事にならないような、業務での運用向けのノウハウが知りたい人が対象。
環境としてMacを前提にしている。Pythonによる並列処理の勉強にも役に立つ。
Pythonのバージョンは3.6。Homebrew+pyenvでインストールすることを前提にしている*1。
並列処理、データ収集とその後の活用に重点をおいている本。簡単なPythonの解説あり。
クローラーの作成だけでなく運用までフォローしているところがポイント。
少し変わったトピックとしては自作スクリプトへのScrapyの組み込み方法が紹介されている。
MacユーザーでなくてもLinuxが使えるなら問題なく読めるはず。
書いてないこと
- ログイン処理の必要なページへの対処
- セレクタの解説
- BeautifulSoup
『Pythonによるスクレイピング&機械学習 開発テクニック』
Pythonによるスクレイピング&機械学習 開発テクニック BeautifulSoup,scikit-learn,TensorFlowを使ってみよう
- 作者: クジラ飛行机
- 出版社/メーカー: ソシム
- 発売日: 2016/12/06
- メディア: 単行本
- この商品を含むブログ (4件) を見る
スクレイピングの本としては中途半端。
おすすめしない。
補足
Selenium WebDriverに関してはPython経由で使うよりJavaのライブラリの方が有利かも。ブラウザ側の変更への対応がJavaのライブラリが一番早いので。
どの本もXPathやCSSセレクタの解説はあまり詳しくない。ブラウザの開発ツールで取得した値そのままでは上手くいかないときがあるので注意が必要。
まとめ
技術評論社の本が一番バランスがいい。スクレイピング自体の知識があって業務でがっつりやろうとしているなら翔泳社の『Pythonによるクローラー&スクレイピング入門』。
技術評論社の本と翔泳社の本はどちらも特色があって甲乙つけがたい。あとはライブラリの公式ドキュメント。
*1:Homebrewはセットアップ済みという前提
今週のふりかえり(2018年8月第1週)
体重を増やそうと思うときに限って体重が増えない……。ジムに通うとかしないとダメかな。
調子があがってきたかと思ったけど見事に暑さにやれられてペースダウン。
某コンテスト用のラズパイの部品が届いたのでがんばりましょう。
続きを読むAmazon Advertise API 関連メモ書き
AmazonのProduct Advertising APIに関するメモ書き。備忘録なので非常に雑です。
APIの概要
Amazonの商品データベースから各種情報をXMLで取得できるAPI。
商品の詳細や在庫情報など、取得できる情報は幅広い。
商品データベースに関する操作とカートに関する操作がある。
この記事では商品データベースに関するAPIのみ。
- Search(検索)
- ItemSearch:キーワード(またはASINなどのID)でItem(商品情報)検索
- Lookup(特定の項目の参照)
- BrowseNodeLookup:ブラウズノード(カテゴリあるいは出品者、メーカー)について情報を得る
- ItemLookup:ASINやISBNのようなIDでItemを検索
- SimilarityLookup:類似商品を探す
公式ドキュメント
Welcome - Product Advertising API
2013年8月1日付けが最新。
Amazon.co.jpではなくdocs.aws.amazon.com
のドキュメントをたどる。
使用するには
Amazon Product Advertising API関連リンク集
注意事項
目的外の使用に対して非常に厳しくなっているので注意が必要。
Product Advertising API (PA-API) の利用ガイドライン
月に最低一回、「(改変なしの)APIからのレスポンスに含まれるURL」から売上が発生していれば最低1秒1回の呼び出しは可能。
APIからのレスポンスに含まれるURLを改変無しで使用しろ、というのはかなり厳しい気がする。
転売用の価格調査用のDB系のとばっちりということなんだろう。
APIに指定するパラメータについて
すべての国で共通
- Search Indices and Locales - Product Advertising API
- Locale Reference for the Product Advertising API - Product Advertising API
カテゴリのリスト
SearchIndexを使う場合に必要。
- Locale Information for the JP Marketplace - Product Advertising API
- Amazonカテゴリ一覧 23,420 件(BrowseNodeデータ収集結果)
- SearchIndexとBrowseNode一覧 - 前人未踏の領域へ
Python用ライブラリ
bottlenoseというライブラリがあるのでこれを使う。
- lionheart/bottlenose: A Python wrapper for the Amazon Product Advertising API.
- 【Python】サクッとAmazonの商品情報を検索してみる - Qiita
以下はAPIの挙動の確認に作ったもの。キーワード検索結果を取得するサンプル。
APIからのレスポンスそのものはXMLで保存している。後半部分で結果をパースしてPythonのリストにしている。
APIキーはdotenv
経由で環境変数から。
#! /usr/bin/env python3 # coding: utf-8 import bottlenose from bs4 import BeautifulSoup from retry import retry import os import sys import pathlib from time import sleep from dotenv import load_dotenv from string import Template from datetime import datetime # [GitHub - theskumar/python-dotenv: Get and set values in your .env file in local and production servers.](https://github.com/theskumar/python-dotenv) # [GitHub - lionheart/bottlenose: A Python wrapper for the Amazon Product Advertising API.](https://github.com/lionheart/bottlenose) load_dotenv('./django_project/.env') AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID') AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY') AWS_ASSOCIATE_TAG = os.environ.get('AWS_ASSOCIATE_TAG') amazon = bottlenose.Amazon(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_ASSOCIATE_TAG, Region='JP') response_group = 'Images, ItemAttributes' # response_groupに何も指定しないと画像のURLは取得できない? response_text = None cached = False if cached : path = pathlib.Path("./dump7.xml") with path.open('rt') as fp: response_text = fp.read() else : for i in range(10) : try: response = amazon.ItemSearch( Keywords="フルメタル・パニック", SearchIndex="All", ResponseGroup=response_group ) response_text = response.decode('utf-8') break except: print("got 503 error, retry!") sleep(3) else: sys.exit(-1) # path = pathlib.Path("./dump7.xml") filename = "./dump_" + datetime.today().strftime("%Y-%m-%d-%H%M%S") + ".xml" path = pathlib.Path(filename) with path.open( mode="wt") as op : op.write(response_text) soup = BeautifulSoup(response_text,'lxml') # lxmlを使う場合はタグ名はすべて小文字。 itemList = soup.find_all("item") item_data = list() for item in itemList : print(item.name) author_list = [node.text for node in item.find_all('author')] creator_list = list() for tag in item.find_all('creator'): role = tag['role'] text = tag.text creator_list.append((text, role)) # publisher or manufacture studi or author ? どれか temp = { 'title' : item.find('title').text, 'detail_url' : item.find('detailpageurl').text, 'asin' : item.find('asin').text, 'manufacturer' : item.find('manufacturer').text if item.find('manufacturer') else None, # Kindle版はManufacture なし? 'authors' : author_list, 'creators' : creator_list, 'small_image_url' : item.find('smallimage').find('url').text if item.find('smallimage') else None, 'medium_image_url': item.find('mediumimage').find('url').text if item.find('mediumimage') else None } if item.find('format') : temp['format'] = item.find('format').text if item.find('binding') : temp['binding'] = item.find('binding').text print(temp) item_data.append(temp) # author, creatorは複数の可能性がある。 print(itemList) print(item_data)
書籍や動画以外は画像の縦横比がバラバラだったりするので注意が必要。
参考情報
Response Groups関連
商品に関するXML属性
下記のリンクから"Ancestry: ItemAttributes"という項目を確認する。
Response Elements - Product Advertising API
参考URL
検索時の制約
「Amazon API」の使い方![最終回]-実際に作ってみよう- | HPcode
カテゴリ別のランキング
BrowseNodeを指定するらしい。
システム管理者さんの憂鬱 : [C#] Amazon Product Advertising API を使用する