Google Vision API の手書き文字認識(英語)を試す


スポンサーリンク

経緯

どこかのニュースサイト(英語)でGoogle Nextで発表された新機能として"hand wrtten"(手書き)という文字があったのでググってみたところ、 Google Vision APIのドキュメント(英語の方)にさり気なく"Detecting Handwriting"という記述を発見。

f:id:atuyosi:20180809215901j:plain

下記のリンク先のページで一番下までスクロールすると言語の切り替えボタンがあります。
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エンコードしなくていいというメリットもあります。

名前が名前だけにググったときにサクッと意図したページを見つけにくいというのが欠点です。

コード

基本的な使い方

クレデンシャルファイル*1のパスを環境変数を設定しておく。

$ 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

手書き文字認識のテスト

手書き文字として非常に適当な漢字の画像を用意しました。字が汚くてすいませんって感じですが。

f:id:atuyosi:20180809215817j:plain:w480
※ 画像は縮小済みです。

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_DETECTIONDOCUMENT_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風味。

ドキュメントへのリンク

結論

ちょっとテスト用の画像が残念だったのかなと反省しています。

TEXT_DETECTIONは手書き文字を受け付けないが)DOCUMENT_TEXT_DETECTIONは手書き文字(英語)を認識できる。

現状は英語とラテン文字のみ手書き文字認識対応。他の言語にも将来対応するんでしょうけど。

正直に言うと、はじめからデジタルで入力すればいいのに、というのが私の見解です。

なお、Microsoftの文字認識APIもいつのまにかアップデートしていて、そっちも英語は手書きに対応しているらしいのでそのうち試す予定。

*1:APIキーを記載したJSONファイル

*2:筆記体は覚えてないです

広告