AI Cloud GCP Python Python 活用 プログラミング

【python できること】Google Vision API OCRで帳票画像のデータ化

 

2015年前後から、クラウドサービスが色々と出てきました。

簡単に、AI、チャットボットが使えたり、データベースやストレージを借りることもできます。

今回は、画像のAIで画像の中から文字を検出してくれるOCRについて紹介します。

 

本記事はこんな方におすすめです。

hituji
OCR認識をして、帳票処理を自動化したい

お客様アンケートの集計を自動化したい

 

本記事の内容

  • GCPでのAPI設定
  • 方法その1 ウェブリクエスト
  • 方法その2 ライブラリ
  • 検出したデータを処理

 

この記事を読むと、Google Cloud PlatformのAPIの設定から、Vision APIでOCRが使えるようになります。

今回は、左の画像を右のようにデータ化します。


*データは一部

 

 

サンプルコード

 

スポンサーリンク

GCP VisionAPIの価格

まず、気になるのは利用料金ではないでしょうか?

価格は次のリンクの公式にのっています。

>> 料金表

データ1000までは無料ですね。

そのあと、1000ごとに$1.50かかりますが、200円もしないので、ほとんど気にする必要はないでしょう。

 

このように、簡単にすぐ使える上に、とても安く提供されています。

 

GCPでのAPI設定

VisionAPIをGCPで有効にしていきます。

 

GCPについて

GCPはGoogleCloudPlatformの略です。

AmazonのAWSやIBM Cloud、WindowsのAzureと同じクラウドサービスです。

サーバーが簡単に構築できたり、AIの処理の実装などを手伝ってくれます。

まず、GCPにアクセスします。

>> Google Cloud Platform

 

プロジェクトの作成

GCPではプロジェクト単位で使うサービスなどを管理できます。

まず、プロジェクトを作成します。

GCPのダッシュボードの「プロジェクト選択」から「新しいプロジェクト」を選択します。

もしくは、下記のリンクに直接飛びます。

>> 新規プロジェクト作成

 

適当な名前でプロジェクトを作成します。

 

これで、新しいプロジェクトが作成され、次のようなダッシュボードがもらえます。

ここで、色々なサービスを管理します。

 

Vision APIを有効にする

VisionAPIを使えるようにします。

 

ナビゲーションメニューより、APIライブラリを選択します。

 

次に、Vision APIを検索します。

「vition api」を入力して、Vision APIを選びます。

 

APIを有効にします。

 

 

これで必要なAPIを有効にしたので、接続するための認証情報を作っていきます。

Google APIの認証を取得

ナビケーションメニューから、API>認証情報へいきます。

 

認証情報を作成から、サービスアカウントを作成します。

 

サービスアカウント名説明を入力して、作成を押します。

 

サービスアカウントができるので、リンクを押します。

 

キーの項目から、鍵を追加から新しい鍵を作成を押します。

 

JSONを作成します。

 

ダウンロードしましょう。

 

このJSONファイルはpythonのライブラリを使う場合に使用します。

 

APIキーの取得

APIキーはpythonだけでなく、ウェブのリクエストでOCR認識の結果を受け取るときに使います。

再度、認証情報のところに行きます。

 

次は、APIキーを選択します。

 

APIキーが発行されます。

このAPIキーを使うと、python以外でもウェブのリクエストを飛ばすことでOCR認識できます。

必要に応じて、右下のキー制限でアクセス制限をつけると良いでしょう。

 

方法その1 ウェブリクエスト

ウェブのリクエストの方法では、取得したAPIキーを使います。

特に、新しいライブラリのインストールが必要ということはありません。

API_KEY = ''に取得したAPIキーを入れます。

import requests
import base64
import json
API_KEY = ''
GOOGLE_CLOUD_VISION_API_URL = 'https://vision.googleapis.com/v1/images:annotate?key='

# TEXT_DETECTION:比較的短い文字
# DOCUMENT_TEXT_DETECTION:文章
DETECTION_TYPE = "DOCUMENT_TEXT_DETECTION"

def request_cloud_vison_api(image_base64, type="DOCUMENT_TEXT_DETECTION"):
    """ http のリクエストでVisionAPIにアクセス """
    api_url = GOOGLE_CLOUD_VISION_API_URL + API_KEY
    req_body = json.dumps({
        'requests': [{
            'image': {
                'content': image_base64.decode('utf-8')
            },
            'features': [{
                'type': type,
                'maxResults': 10,
            }]
        }]
    })
    res = requests.post(api_url, data=req_body)
    return res.json()


def img_to_base64(filepath):
    """ 画像データをエンコード """
    with open(filepath, 'rb') as img:
        img_byte = img.read()
    return base64.b64encode(img_byte)


def render_doc_text(file_path):

    result = request_cloud_vison_api(image_base64=img_to_base64(file_path),
                                     type=DETECTION_TYPE)

    data_list = []
    # データの取得 textAnnotationsに座標とテキスト fullTextAnnotationにテキスト
    result_list = result["responses"][0]["textAnnotations"]
    for d in result_list:
        data_list.append([d['boundingPoly']['vertices'], d['description']])

    # 1つ目除外
    data_list = data_list[1:len(data_list)]
    return data_list

 

render_doc_text関数に画像ファイルを渡すことで、検出した文字と座標を取得します。

このコードを「google_ocr_api.py」として保存します。

 

方法その2 ライブラリ

次に、google-cloud-visionライブラリを使った方法です。

こちらでは、先ほどのJSONファイルを使います。

 

ライブラリのインストール

pipを使って、ライブラリをインストールしましょう

pip install google-cloud-vision

 

環境変数の設定

先ほど取得した、jsonファイルは環境変数に登録します。

UbuntuやMacの場合

export GOOGLE_APPLICATION_CREDENTIALS="jsonファイルパス"

 

Windowsの場合、コントロールパネル>システム>環境変数から設定しましょう。

 

設定が終われば、あとはコードです。

from pathlib import Path
from google.cloud import vision

def render_doc_text(filein):

    client = vision.ImageAnnotatorClient()

    p = Path(__file__).parent / filein
    with p.open('rb') as image_file:
        content = image_file.read()

    image = vision.Image(content=content)

    data_list = []
    response = client.document_text_detection(image=image)
    document = response.full_text_annotation
    for page in document.pages:
        for block in page.blocks:
            for paragraph in block.paragraphs:
                for word in paragraph.words:
                    box = [{'x':v.x, 'y':v.y} for v in word.bounding_box.vertices]
                    text = [symbol.text for symbol in word.symbols]
                    data_list.append([box, ''.join(text)])
    return data_list

 

このrender_doc_text関数は、ウェブリクエストの時と同じデータを取得します。

ですので、どちらを使ってもOKです。

このコードを「google_ocr_lib.py」として保存します。

 

検出したデータの処理

ここからは、個人的にこういう処理するかなといったイメージになるので、参考にしていただけたらと思います。

 

紹介した各方法で、render_doc_text関数を使うと、検出した文字と検出した箇所が四角の座標で取得できます。

次のようなイメージです。

左が検出前、右が検出後です。

 

最終的に取得したいデータは、四角の各ポイントではなく、中心座標と文字とします。

これは個人的に処理しやすいと思ったからです。

 

課題点

検出した文字を見ると以下のような課題があります。

ポイント

文字の区切りがおかしい。例、商品1は「商品」「1」となっている

検出できない文字、検出文字が違う

2つ目は動かしてもらって、中身を見るとわかりますが、これはどうしようもないので、少なくとも1つ目は解決していきます。

 

サンプルコード

render_doc_textで取得したデータを最終的にx,y,文字のpandasのDataFrameにします。

いくつか関数を用意しています。

関数名 機能
rect_to_point 座標の中心を算出
rect_ave_height_degree 検出した四角の平均高さ、傾きを算出
高さは、文字が近接しているかの判断に使っています。
文字高さ分に近ければ、近接文字扱いするとかです。
傾きは画像の傾き補正に使おうと思いましたが、使っていません。
join_nearest 近接文字を結合します。

 

実際のコードを紹介します。

from google_ocr_lib import render_doc_text
# from google_ocr_api import render_doc_text

import numpy as np
import math
import pandas as pd

def rect_to_point(rect):
    """ 文字rectの中心座標 """
    x = []
    y = []
    for d in rect:
        if 'x' in d:
            x.append(d['x'])
        if 'y' in d:
            y.append(d['y'])
    return sum(x)/len(x), sum(y)/len(y)

def rect_ave_height_degree(data_list):
    """ 平均高さ、傾き """
    height = []
    degree = []
    for rect in data_list:
        x = []
        y = []
        for d in rect[0]:
            if 'x' in d:
                x.append(d['x'])
            if 'y' in d:
                y.append(d['y'])
        # データ不足しているのは無視します。
        if len(x)==4 and len(y)==4:
            height.append(((y[3]-y[0])+(y[2]-y[1]))/2)
            if (x[1]-x[0]) == 0:
                tan = 0
            else:
                tan = (y[1] - y[0]) / (x[1] - x[0])
            atan = np.arctan(tan) * 180 / math.pi
            degree.append(atan)
    # 平均値を返す。場合によっては中央値でもよい。
    return sum(height)/len(height), sum(degree)/len(degree)


def join_nearest(data_list, height):
    """ 近接の文字結合 """
    ret_data = []
    data_list.reverse()
    # データなくなるまで
    while data_list:
        d = data_list.pop()
        most_near = 0

        # 近接文字なくなるまで
        while most_near!=-1:
            rect = d[0]
            most_near = -1
            if ('x' in rect[1]) and ('y' in rect[1]):
                curent_x = rect[1]['x']
                curent_y = rect[1]['y']

                # 右に文字高さの 1/2 以内の近さがあれば
                temp_data = data_list.copy()
                for ind2, d2 in enumerate(temp_data):
                    rect2 = d2[0]
                    if ('x' in rect2[0]) and ('y' in rect2[0]):
                        other_x = rect2[0]['x']
                        other_y = rect2[0]['y']
                        # 距離の近いところ
                        if (abs(other_x-curent_x)<height/2) and (abs(other_y-curent_y)<height/2): most_near = ind2 break # 文字連結 if most_near>0:
                # 連結
                new_rect = []
                new_rect.append(rect[0])
                new_rect.append(rect2[1])
                new_rect.append(rect2[2])
                new_rect.append(rect[3])
                new_str = d[1] + d2[1]
                d = [new_rect, new_str]
                # 連結したデータも削除
                del data_list[ind2]
            else:
                ret_data.append(d)
                break

    return ret_data


if __name__ == '__main__':
    # OCR検知
    data_list = render_doc_text('sample.png')

    # 高さ、角度
    height, degree = rect_ave_height_degree(data_list)

    # 近接文字結合
    data_list = join_nearest(data_list, height)

    # 中央座標に変換して、DataFrameに変更
    new_data_list = []
    for d in data_list:
        x, y = rect_to_point(d[0])
        new_data_list.append([x, y, d[1]])
    df = pd.DataFrame(data=new_data_list, columns=['x', 'y', 'text'])

    print(df)

 

このコードを「main.py」として、1,2行目でgoogle_ocr_libかgoogle_ocr_apiを読んでいます。

使いたいほうを使ってください。

 

実行すると、DataFrameにデータが入りますので、CSVにデータ保存したら、他にも処理を追加したりすると良いでしょう。

近接文字をするしないでは次のように差が出ます。

左が、何もしない状態、右が近接文字をつけた場合。

これは、データによっては役に立たないかもしれませんが、帳票の画像からデータを抜き取るときはこういった工夫がいるのではないでしょうか?

 

他の活用方法は「python 活用 できることまとめ」も参考にしてください。

>> python 活用 できることまとめ

Pythonスキルが身に付いたら、ぜひスキルを生かして稼いでいきましょう!

>> Pythonでの副業の始め方紹介【隙間時間 で可能】

-AI, Cloud, GCP, Python, Python 活用, プログラミング