Cloud Vision API を使って画像のラベル検出と OCR (光学文字認識)を行なう

この記事は個人ブログと同じ内容です

www.ritolab.com


GCP の Cloud Vision API を使って画像のラベル検出と OCR(光学式文字認識)を行なってみます。

Cloud Vision API

cloud.google.com

画像ラベリング・顔検出・光学式文字認識・不適切なコンテンツへのタグ付けなど、画像検出機能を揃えたもの。

画像を理解し、画像から情報を引き出すことができる。

画像認識についてトレーニング済みのモデルを利用できるのが大きな強み。

事前準備

Vision API を使えるようにするには事前に以下の作業が必要です。

  • プロジェクトの作成
  • Cloud Vision API の有効化
  • 支払い情報の登録
    • 新規なら無料トライアル使える
  • サービスアカウントの設定
    • キーの作成
      • json ファイルが払い出されるのでダウンロード。これを用いて API へリクエストすることになります。

GCP 慣れてないとわりと面倒ですが、公式ドキュメントに一通りの手順が解説されているのでそちらを見てみるとわかりやすいと思います。

cloud.google.com

環境作成

Cloud Vision API を使う環境を作っていきます。

今回は Cloud SDK の Docker イメージを使ってコンテナ環境を作ります。

cloud.google.com

そしてその中に Vision クライアントライブラリをインストールして使っていきます。

cloud.google.com

ちなみに分析の実装は python で行ないます。

Dockerfile

FROM google/cloud-sdk:latest

# python コマンドに python3 へのリンクを設定(必須ではない)
RUN update-alternatives --install /usr/bin/python python /usr/bin/python3 1

# vision クライアント ライブラリのインストール
RUN python -m pip install --upgrade google-cloud-vision

docker-compose.yml

version: '3.8'
services:
  google_cloud_sdk:
    build: .
    container_name: google_cloud_sdk
    working_dir: /root/src
    tty: true
    volumes:
      - ./src:/root/src
    environment:
      GOOGLE_APPLICATION_CREDENTIALS: /root/src/key.json

環境変数 GOOGLE_APPLICATION_CREDENTIALS に設定しているのは、事前準備でサービスアカウント設定のところでダウンロードしたキーの json ファイルへのパスです。

2 つのファイルを作成後、docker compose build を行い、docker compose up で環境の出来上がりです。

ディレクトリ構成は以下になっています

.
├── Dockerfile
├── docker-compose.yml
└── src/
    ├── resources/ <- 画像ファイルを設置
    ├── key.json
    └── script.py

src ディレクトリにスクリプトと画像を入れていきます

ラベル検出

まずはラベル検出を行ってみます。

ラベル検出は、「画像には何が写っているか」を検出するものです。

cloud.google.com

動物の識別

今回は実験として、以下の画像を用意してみました。

上からそれぞれ 犬・猫・馬・にわとり・アルパカ です。これらのラベル検出を行ってみます。

つまり、これらの画像 1 つ 1 つに対して、「犬」や「猫」といったラベルが検出できればこの実験は成功です。

実装します。

label_detection.py

import io
import os

from google.cloud import vision

def label_detection(image):
    # ラベル検出
    response = client.label_detection(image=image)
    labels = response.label_annotations

    print('Labels:')
    for label in labels:
        print(label.description)

image_list = [
    {
        'type': '犬',
        'file_name': 'dog.jpg'
    },
    {
        'type': '猫',
        'file_name': 'cat.jpg'
    },
    {
        'type': '馬',
        'file_name': 'horse.jpg'
    },
    {
        'type': 'にわとり',
        'file_name': 'chicken.jpg'
    },
    {
        'type': 'アルパカ',
        'file_name': 'alpaca.jpg'
    },
]

client = vision.ImageAnnotatorClient()

for im in image_list:
    print('検証タイプ:' + im['type'])

    file_name = os.path.abspath('resources/animals/' + im['file_name'])

    with io.open(file_name, 'rb') as image_file:
        content = image_file.read()

    image = vision.Image(content=content)

    label_detection(image)

画像を読み込んで Cloud Vision API を通じて分析、ラベル検出を行い出力しています。

結果は以下になりました。(左からスコアの高い順)

検証画像:犬

Glasses, Dog, Dog breed, Carnivore, Orange, Companion dog, Fawn, Toy dog, Snout, Sporting Group
label_annotations {
  mid: "/m/0bt9lr"
  description: "Dog"
  score: 0.9633671045303345
  topicality: 0.9633671045303345
}

スコアも 0.96 とほぼ犬と判断して良い結果になっています。

Glasses のスコアの方が若干高いのですが、これはおそらく犬が入っている青いやつのことを判定しているのでしょうか。

検証画像:猫

Cat, Carnivore, Whiskers, Felidae, Ear, Small to medium-sized cats, Snout, Close-up, Fur, Domestic short-haired cat
label_annotations {
  mid: "/m/01yrx"
  description: "Cat"
  score: 0.9540761709213257
  topicality: 0.9540761709213257
}

検証画像:馬

Nose, Horse, Eye, Plant, Working animal, Stable, Liver, Sorrel, Eyelash, Horse tack
label_annotations {
  mid: "/m/03k3r"
  description: "Horse"
  score: 0.9794358611106873
  topicality: 0.9794358611106873
}

検証画像:にわとり

Phasianidae, Beak, Comb, Chicken, Neck, Galliformes, Bird, Feather, Poultry, Livestock
label_annotations {
  mid: "/m/09b5t"
  description: "Chicken"
  score: 0.8774992227554321
  topicality: 0.8774992227554321
}

検証画像:アルパカ

Hair, Llama, Eye, Alpaca, Camelid, Sheep, Fawn, Terrestrial animal, Wood, Snout
label_annotations {
  mid: "/m/0pcr"
  description: "Alpaca"
  score: 0.931623101234436
  topicality: 0.931623101234436
}

画像に対して複数の要素があればそれだけ検出するので複数のラベルが返りますが、きちんと動物を認識してくれていますね。

アルパカだけ、ラマの方がスコアが高かったので結果がしっくりこなかったですが、ラベル検出はこれらを使って何をどう判断するかっていうのが結構難しいなと思いました。 (そこに在る要素が全て出てくる・近似しているものも出てくるので、この結果を使って何がしたいのかは明確にしないと上手に使いこなせなさそう)

鮎と鮎の塩焼き

続いてこんな画像を用意しました。

鮎と、鮎の塩焼きです。

おそらく「鮎」っていう検出はされないんだろう(鮎って世界で広く認知があるのか知らない)とは思いますが、シンプルに生魚と焼き魚ってどう区別されるのかという、個人の興味です。

結果はこうなりました。(上からスコアが高い順)

検証画像:鮎

  • Vertebrate(脊椎動物
  • Fin(フィン)
  • Fish(魚)
  • Marine biology(海洋生物学)
  • Fish products(魚製品)
  • Ray-finned fish(条鰭類)
  • Tail(しっぽ)
  • Feeder fish(フィーダーフィッシュ)
  • Cyprinidae(コイ科)
  • Oily fish(脂ののった魚)

検証画像:鮎の塩焼き

  • Food(食べ物)
  • Ingredient(成分・食材)
  • Seafood(シーフード)
  • Fish(魚)
  • Recipe(レシピ)
  • Fish supply(魚の供給)
  • Fish products(魚製品)
  • Tail(しっぽ)
  • Ray-finned fish(条鰭類)
  • Cuisine(料理)

いまいちよくわからない感じになりましたが、「生物としての魚」と「調理済みの魚」の区別はなんとかつきそうです。

さきほどの動物の例と同じように、ラベル検出は一定の目的を持った上で行わないと、こういうごちゃった結果になったときにそこから何を洞察したいんだっけっていうことになりそうです。

ということで、それではもう少し目的を持った上でのラベル検出を行ってみたいと思います。

それは身分証明書であるか

「それは身分証明書たりうる」の定義って、結構自治体や何らかのサービスによっても違うかもしれないし、それ以前に日本だけの証明書もあると思うので、どこまでそのオブジェクトが「身分証明書」というラベルで検出されるか。を見てみたいと思います。

ということで、日本国内において、日常では身分証明書として十分に通用する以下の 4 つを撮影し、その画像を解析にかけてみます。

  • 運転免許証
  • マイナンバーカード
  • 健康保険証
  • パスポート

結果は以下になりました。(左からスコアが高い順)

検証画像:運転免許証

Product, Identity document, Font, Rectangle, Material property, Suit, Ticket, Blazer, License, Eyelash
label_annotations {
  mid: "/m/01_v7j"
  description: "Identity document"
  score: 0.8999442458152771
  topicality: 0.8999442458152771
}

検証画像:マイナンバーカード

Identity document, Rectangle, Font, Material property, Ticket, Paper, License, Paper product, Electric blue, Number
label_annotations {
  mid: "/m/01_v7j"
  description: "Identity document"
  score: 0.8900585770606995
  topicality: 0.8900585770606995
}

検証画像:健康保険証

Font, Ticket, Rectangle, Number, Screenshot

スコア 0.75 で「もしかしたらチケットかもね」くらいの判定しかされませんでした。

検証画像:パスポート

Identity document, Font, Line, Material property, Eyelash, Ticket, Signature, Paper, License, Paper product
label_annotations {
  mid: "/m/01_v7j"
  description: "Identity document"
  score: 0.9106850028038025
  topicality: 0.9106850028038025
}

「運転免許証」「マイナンバーカード」「パスポート」に関しては「Identity document(身分証明書)」というラベル検出が行われました。

一方で「健康保険証」は身分証明書であるという判断はされなかったようです。この中では唯一顔写真が無かったのでそこも要因なのでしょうか。

Cloud Vision API の精度の良さは認めつつも、独自の慣習や文化を加味したいなら、最終的には自分でモデルを作り上げていく必要があるのかもしれません。

OCR光学文字認識

OCR(Optical Character Recognition, 光学文字認識)は、画像のテキスト情報を検出し抽出する技術です。

いわゆる標識や看板などのプリントされた文字だったり、手書きの文字だとかのテキスト情報を画像から検出して抽出します。

cloud.google.com

プリントされたテキストの検出

まずは活字印刷された看板などがある写真を用意してテキストを検出してみます。

用意したのはこちらの写真です。

岡山県にある日本三名園の一つ「後楽園」に設置されている「池田綱政」という人の解説板です。

長々とした解説、微妙に難しい漢字、そして日本語だけでなく英語の解説もあり、どこまで検出してくれるのでしょうか。

では実装です。

text_detection.py

import io
import os

from google.cloud import vision

def text_detection(image):
    response =  client.document_text_detection(image=image, image_context={'language_hints': ['ja']})

    print(response.full_text_annotation.text)

image_list = [
    {
        'type': '岡山後楽園',
        'file_name': '岡山後楽園.jpg'
    },
]

client = vision.ImageAnnotatorClient()

for im in image_list:
    print('検証画像:' + im['type'])

    # The name of the image file to annotate
    file_name = os.path.abspath('resources/' + im['file_name'])

    # 画像をメモリにロードします
    with io.open(file_name, 'rb') as image_file:
        content = image_file.read()

    image = vision.Image(content=content)

    text_detection(image)

そしてこちらが実行結果です。検出したテキスト情報は以下でした。

検証画像:岡山後楽園
岡山後楽園 歴史ものがたり The history of Okayama Korakuen
いけ
だ
つなまさ
池田綱政が築いた、 やすらぎの庭園「岡山後楽園」 Okayama Korakuen : a leisure garden built for Lord Ikeda Tsunamasa
つなまさ
ちゃくし
池田綱政 Ikeda Tsunamasa (1638-1714)
岡山後楽園を築いた岡山藩二代目藩主池田綱政は、藩祖池田光政の嫡子と
して江戸で誕生。 新田開発や閑谷学校の完成など、父から受け継いだ岡山藩
の基盤を固めた。 また、 能や和歌、 書画に巧みで、 家臣からは 「英断の君」「仁愛
の君」と評されている。
貞享4年(1687) に築庭を開始。 園内中央は大きく開け、 平坦地の一部が芝生
で、残りの大半はもとの田畑をそのまま取り込んだ明るく広々とした庭園で
あった。 綱政は 「あまり手をかけない景色」と喜び、 毎日のように訪れた。 元禄13年
(1700) には敷地が今とほぼ同じ姿となる。 歴代藩主も政務の合間を過ごす
やすらぎの場として利用し、 庭園や建物には藩主の好みやその時々の社会
事情で手が加えられた。 城の後ろにあることから 「御後園」 と呼ばれた庭園は、
明治4年(1871) に後楽園と改称され、明治17年 (1884)に岡山県に譲渡され
一般公開が始まった。 その後、水害や戦災にも見舞われたが、江戸時代の絵
図や古写真にもとづいて復興され、今日にいたっている。
ごこうえん
Ikeda Tsunamasa was the second feudal lord of Okayama, an enlightened ruler
who excelled at both the literary and military arts.
The construction of Okayama Korakuen Garden started in 1687 under his orders.
The initial project featured a wide, open central area covered more in fields than in
lawns, depicting a countryside landscape, which future Ikeda Clan lords were able to
enjoy. As the years passed, various lords slightly modified some of the landscape and
architectural aspects of the garden in order to comply with their taste and with the
current fashion. The garden received its current name "Korakuen" in 1871, and in
1884 the Ikeda Clan ceded it to Okayama Prefecture, which opened the garden to
the general public. Severe damages caused by floods during the 20th century and
fires of World War II have luckily been repaired by using old illustrations called "ezu"
and photographs as references.
「池田綱政像 狩野常信筆」 部分 (曹源寺所蔵)/写真提供 岡山県立博物館
岡山藩主池田家略系図 Ikeda Clan family tree
綱政— 継政
宗政
光政
治政 斉政
(1609-1682) (1638-1714) ( 1702-1776) (1727-1764) (1750-1818) (1773-1833)
Mitsumasa
Tsunamasa
Tsugumasa
Munemasa
Harumasa
Narimasa
斉敏
政
茂政
章政
(1811-1842)
(1823-1893) (1839-1899)
(1836-1903)
= 養子
Adopted child
Naritoshi.
Yoshimasa
Mochimasa
Akimasa
=

全てのテキスト情報が検出され書き出されていました。

手書き文字の抽出

では手書きの文字はどうか。ということでこちらの画像を用意しました。

ホワイトボードに書いた文字を撮影したものです。

雑に書かれた文字でも検出できるのでしょうか。

実行した結果はこちら

検証画像:手書き
手書きってどこまで検出してくれるんでしょうか。
山田太郎

ばっちり検出できていますね。

これ以外にも色々とやってみたのですが、例えばパスポートって自分の名前(サイン)を手書きで書きますが、それもきちんと検出してくれていました。

まとめ

Cloud Vision API を使って画像のラベル検出と OCR を行いましたが、どれも精度高く検出されていました。

そして、こうしてトレーニングされたモデルを使えるのはとても便利でした。

Cloud Vision API は毎月最初の 1000 ユニットまでは無料なので、学びや理解のための利用なら課金も発生しないで利用もできそうです。

ラベル検出ですが、その画像に写っているものを検出できるだけする。というものになるので、例えば「犬」を撮影したとしても、背景に色々写り込んでいればそれらも検出されることになります。

この場合、「この写真は犬がメインの画像です」と判断したい場合にどうやっていけば良いのかっていうところが気になります。

Cloud Vision API では物体検出もできるようなので、ラベル検出というよりはそれを利用して位置や画像に占める割合(面積)とかを見ていったら判断できるだろうか。

cloud.google.com

もしくは Cloud AutoML Vision を使って追加でトレーニングを行なうか。

いずれにしても、目的を明確にした上で手段は検討する必要がありそうです。

もっと理解を深めて改めて色々チャレンジしてみたいと思います。


現在 back check 開発チームでは一緒に働く仲間を募集中です。

herp.careers

herp.careers

herp.careers

herp.careers

herp.careers

herp.careers