作成日: 2023-4-2 更新日: 2023-4-25
カテゴリ- : ITブログ
OCRのCode
 

OCRのCode

 

以下のコードは、文字のバウンディングボックスのリストを行単位でソートし、それらを含む行のリストを返す関数 get_sorted_lines です。

コードをいくつかの処理単位に分割し、それぞれの目的を説明します。

関数定義と、bounds という空のリストの初期化:

def get_sorted_lines(response):
    document = response.full_text_annotation
    bounds = []

入力された responsefull_text_annotation を用いて、各ページ、ブロック、段落、単語、そして記号をイテレートするためのネストされたループの構造:

    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:

各記号の左上の頂点の座標とテキストを取得し、それらとバウンディングボックスを bounds リストに追加:

                        x = symbol.bounding_box.vertices[0].x
                        y = symbol.bounding_box.vertices[0].y
                        text = symbol.text
                        bounds.append([x, y, text, symbol.bounding_box])

bounds リストを y 座標に基づいてソート:

    bounds.sort(key=lambda x: x[1])

各バウンディングボックスを処理し、行に分割するための変数の初期化:

    old_y = -1
    line = []
    lines = []
    threshold = 30

バウンディングボックスをイテレートし、行に分割する:

    for bound in bounds:
        x = bound[0]
        y = bound[1]
        if old_y == -1:
            old_y = y
        elif old_y - threshold <= y <= old_y + threshold:
            old_y = y
        else:
            old_y = -1
            line.sort(key=lambda x: x[0])
            lines.append(line)
            line = []
        line.append(bound)

最後の行を処理し、行単位でソートされたリストを返す:

    line.sort(key=lambda x: x[0])
    lines.append(line)
    return lines

このコードは、入力された response のテキストアノテーションに基づいて、バウンディングボックスのリストを行に分割し、行単位でソートして返す関数です。

 

これをわかりやすくより抽象的に書き直す。

def extract_bounds(document):
    bounds = []
    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:
                        x = symbol.bounding_box.vertices[0].x
                        y = symbol.bounding_box.vertices[0].y
                        text = symbol.text
                        bounds.append([x, y, text, symbol.bounding_box])
    return bounds


def sort_bounds_by_y(bounds):
    return sorted(bounds, key=lambda x: x[1])


def is_in_same_line(y1, y2, threshold=30):
    return y1 - threshold <= y2 <= y1 + threshold


def split_bounds_into_lines(bounds):
    old_y = -1
    line = []
    lines = []

    for bound in bounds:
        x, y = bound[0], bound[1]

        if old_y == -1:
            old_y = y
        elif is_in_same_line(old_y, y):
            old_y = y
        else:
            line.sort(key=lambda x: x[0])
            lines.append(line)
            line = []
            old_y = -1

        line.append(bound)

    line.sort(key=lambda x: x[0])
    lines.append(line)
    return lines


def get_sorted_lines(response):
    document = response.full_text_annotation
    bounds = extract_bounds(document)
    sorted_bounds = sort_bounds_by_y(bounds)
    lines = split_bounds_into_lines(sorted_bounds)
    return lines

このリファクタリングでは、以下のような関数に分割しました。

  1. extract_bounds: 文書からバウンディングボックスのリストを抽出します。
  1. sort_bounds_by_y: バウンディングボックスをy座標でソートします。
  1. is_in_same_line: 2つのy座標が同じ行にあるかどうかを判定します。
  1. split_bounds_into_lines: ソートされたバウンディングボックスを行に分割します。
 

お気軽にお問い合わせください

必須項目を全て入力してください (入力後、送信ボタンが表示されます) 24時間以内にご連絡を差し上げます。

※税理士に対する営業は業務の妨げになり迷惑です。やめてください。