高密度ドキュメントのテキスト検出のチュートリアル

オーディエンス

このチュートリアルの目的は、Google Cloud Vision API のドキュメント テキスト検出機能を使用してアプリケーションを開発する方法を学ぶことです。このチュートリアルは、基本的なプログラミング構成やテクニックの知識があることを前提としていますが、プログラミングの初心者の方にも簡単に操作できるように設計されています。Cloud Vision API リファレンス ドキュメントを参照しながらチュートリアルに従うことで、基本的なアプリケーションを作成できるようになります。

前提条件

Python

ドキュメント テキスト OCR を使用して画像にアノテーションを付ける

このチュートリアルでは、DOCUMENT_TEXT_DETECTION リクエストを使用して fullTextAnnotation レスポンスを処理する基本的な Vision API アプリケーションについて段階的に説明します。

fullTextAnnotation は、画像から抽出された UTF-8 テキストを階層構造で表現したレスポンスで、ページ→ブロック→段落→語→記号のように編成されています。

  • Page は、ブロックの集まりに、ページについてのメタ情報、つまりサイズ、解像度(X 解像度と Y 解像度が違う場合がある)を付加したものです。

  • Block は、ページの 1 つの「論理的」要素を表します。たとえば、テキストで埋め尽くされている領域や、列と列の間にある図や区切りなどです。テキスト ブロックとテーブル ブロックには、テキスト抽出に必要な主要な情報が含まれています。

  • Paragraph は、順序付けられた単語列を表すテキストの構造単位です。デフォルトで単語は、単語区切りで区切られているものとみなされます。

  • Word は、テキストの最小単位です。これは、記号の配列として表記されます。

  • Symbol は、文字または句読点記号を表します。

また、fullTextAnnotation は、リクエスト中の画像に部分一致または完全一致するウェブ画像を参照する URL を示すこともあります。

完全なコードリスト

Cloud Vision API Python リファレンスを参照しながらコードを読み進めることをおすすめします。

import argparse
from enum import Enum

from google.cloud import vision
from PIL import Image, ImageDraw

class FeatureType(Enum):
    PAGE = 1
    BLOCK = 2
    PARA = 3
    WORD = 4
    SYMBOL = 5

def draw_boxes(image, bounds, color):
    """Draws a border around the image using the hints in the vector list.

    Args:
        image: the input image object.
        bounds: list of coordinates for the boxes.
        color: the color of the box.

    Returns:
        An image with colored bounds added.
    """
    draw = ImageDraw.Draw(image)

    for bound in bounds:
        draw.polygon(
            [
                bound.vertices[0].x,
                bound.vertices[0].y,
                bound.vertices[1].x,
                bound.vertices[1].y,
                bound.vertices[2].x,
                bound.vertices[2].y,
                bound.vertices[3].x,
                bound.vertices[3].y,
            ],
            None,
            color,
        )
    return image

def get_document_bounds(image_file, feature):
    """Finds the document bounds given an image and feature type.

    Args:
        image_file: path to the image file.
        feature: feature type to detect.

    Returns:
        List of coordinates for the corresponding feature type.
    """
    client = vision.ImageAnnotatorClient()

    bounds = []

    with open(image_file, "rb") as image_file:
        content = image_file.read()

    image = vision.Image(content=content)

    response = client.document_text_detection(image=image)
    document = response.full_text_annotation

    # Collect specified feature bounds by enumerating all document features
    for page in document.pages:
        for block in page.blocks:
            for paragraph in block.paragraphs:
                for word in paragraph.words:
                    for symbol in word.symbols:
                        if feature == FeatureType.SYMBOL:
                            bounds.append(symbol.bounding_box)

                    if feature == FeatureType.WORD:
                        bounds.append(word.bounding_box)

                if feature == FeatureType.PARA:
                    bounds.append(paragraph.bounding_box)

            if feature == FeatureType.BLOCK:
                bounds.append(block.bounding_box)

    # The list `bounds` contains the coordinates of the bounding boxes.
    return bounds

def render_doc_text(filein, fileout):
    """Outlines document features (blocks, paragraphs and words) given an image.

    Args:
        filein: path to the input image.
        fileout: path to the output image.
    """
    image = Image.open(filein)
    bounds = get_document_bounds(filein, FeatureType.BLOCK)
    draw_boxes(image, bounds, "blue")
    bounds = get_document_bounds(filein, FeatureType.PARA)
    draw_boxes(image, bounds, "red")
    bounds = get_document_bounds(filein, FeatureType.WORD)
    draw_boxes(image, bounds, "yellow")

    if fileout != 0:
        image.save(fileout)
    else:
        image.show()

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("detect_file", help="The image for text detection.")
    parser.add_argument("-out_file", help="Optional output file", default=0)
    args = parser.parse_args()

    render_doc_text(args.detect_file, args.out_file)

この簡単なアプリケーションでは次のタスクを実行します。

  • アプリケーションの実行に必要なライブラリをインポートする
  • 次の 3 つの引数を取得して main() 関数に渡します。
    • image_file - アノテーションを付ける入力画像ファイル
    • output_file - Cloud Vision が生成する、描画された多重ボックスを含む出力画像の出力ファイル名
  • サービスと対話する ImageAnnotatorClient インスタンスを作成する
  • リクエストを送信してレスポンスを返す
  • テキストの周囲にボックスが描画された出力画像を作成する

コードの詳細

ライブラリのインポート

import argparse
from enum import Enum

from google.cloud import vision
from PIL import Image, ImageDraw

標準ライブラリをインポートします。

  • argparse。アプリケーションが入力ファイルの名前を引数として受け入れます。
  • FeatureType 列挙型の enum
  • io。ファイル I/O 用

その他のインポート:

  • google.cloud.vision ライブラリ内の ImageAnnotatorClient クラス: Vision API へのアクセスを提供する
  • google.cloud.vision ライブラリ内の types モジュール: リクエストを作成する
  • PIL ライブラリの Image ライブラリと ImageDraw ライブラリ: 入力画像にボックスが描かれた出力画像を作成するために使用する

アプリケーションの実行

parser = argparse.ArgumentParser()
parser.add_argument("detect_file", help="The image for text detection.")
parser.add_argument("-out_file", help="Optional output file", default=0)
args = parser.parse_args()

render_doc_text(args.detect_file, args.out_file)

ここでは、渡された引数を解析し、それを render_doc_text() 関数に渡します。

API に対する認証

Vision API サービスと通信する前に、事前に取得した認証情報を使用してサービスを認証する必要があります。アプリケーション内で認証情報を取得する最も簡単な方法は、アプリケーションのデフォルト認証情報(ADC)を使用することです。デフォルトで、Cloud クライアント ライブラリは GOOGLE_APPLICATION_CREDENTIALS 環境変数から認証情報の取得を試みます。この環境変数はサービス アカウントの JSON キーファイル(詳しくはサービス アカウントの設定を参照)を指している必要があります。

API リクエストの作成とレスポンスからのテキスト境界の読み取り

Vision API サービスの準備ができたら、ImageAnnotatorClient インスタンスの document_text_detection メソッドを呼び出すことにより、サービスにアクセスできます。

API へのリクエストとそのレスポンスの詳細は、クライアント ライブラリによりカプセル化されています。リクエストの構造の詳しい情報については、Vision API リファレンスをご覧ください。

def get_document_bounds(image_file, feature):
    """Finds the document bounds given an image and feature type.

    Args:
        image_file: path to the image file.
        feature: feature type to detect.

    Returns:
        List of coordinates for the corresponding feature type.
    """
    client = vision.ImageAnnotatorClient()

    bounds = []

    with open(image_file, "rb") as image_file:
        content = image_file.read()

    image = vision.Image(content=content)

    response = client.document_text_detection(image=image)
    document = response.full_text_annotation

    # Collect specified feature bounds by enumerating all document features
    for page in document.pages:
        for block in page.blocks:
            for paragraph in block.paragraphs:
                for word in paragraph.words:
                    for symbol in word.symbols:
                        if feature == FeatureType.SYMBOL:
                            bounds.append(symbol.bounding_box)

                    if feature == FeatureType.WORD:
                        bounds.append(word.bounding_box)

                if feature == FeatureType.PARA:
                    bounds.append(paragraph.bounding_box)

            if feature == FeatureType.BLOCK:
                bounds.append(block.bounding_box)

    # The list `bounds` contains the coordinates of the bounding boxes.
    return bounds

クライアント ライブラリによるリクエスト処理後のレスポンスには、AnnotateImageResponse が含まれます。これは、リクエストで渡された各画像の画像アノテーション結果のリストで構成されます。今回はリクエストで画像を 1 つだけ送信したため、full TextAnnotation を扱い、指定されたドキュメント機能のための境界を収集します。

アプリケーションの実行

アプリケーションを実行するには、この receipt.jpg ファイルをダウンロードし(場合によってはリンクを右クリックすることが必要)、ローカルマシン上のファイルのダウンロード場所をチュートリアル アプリケーション(doctext.py)に渡します。

Python コマンドと、テキスト アノテーション出力画像を以下に示します。

$ python doctext.py receipt.jpg -out_file out.jpg

次の画像では、単語が黄色で、文が赤で示されています。

これで完了です。Google Cloud Vision のフルテキスト アノテーションを使用してテキスト検出を実行しました。