MLism

YomiToku Studioの帳票解析機能 — テンプレート作成からCLIによるバッチ解析まで

Tech/

給与所得の源泉徴収票を例に、YomiToku Studioで固定帳票のテンプレートと階層ヘッダーを作成し、YomiTokuのCLIで10件の帳票を一括解析する手順を、画面とJSONの出力例を交えて紹介します。

YomiToku StudioYomiTokuOCR帳票解析バッチ処理

MLism代表の木之下です。給与明細や申請書など、同じ様式の帳票から必要な情報を取り出すには、文字の読み取りに加えて、項目名と値の対応関係を定義する必要があります。

YomiToku v0.15.0では、YomiToku Studioで作成した帳票テンプレートを、YomiTokuのCLIから利用できるようになりました。

この機能を利用すると、GUI上で帳票を確認しながら抽出項目や階層構造を定義し、そのテンプレートを用いて、同じ形式の帳票をまとめて解析できます。

本記事では、給与所得の源泉徴収票を例に、YomiToku Studioでの帳票解析とテンプレート作成の方法を紹介します。さらに、作成したテンプレートをYomiToku(公開版)に読み込み、疑似データ10件をバッチ解析するまでの流れを、実際の画面と出力結果を交えながら紹介します。

記事内で使用する氏名や住所、番号、金額などは、説明用に作成した架空のデータです。

帳票解析とは

帳票をデータとして活用するには、文字を読み取るだけでなく、それぞれの文字がどの項目に対応しているかを把握する必要があります。

例えば、源泉徴収票には「支払金額」「源泉徴収税額」「氏名」などの項目があります。また、扶養親族の欄には同じ「氏名」が複数登場するため、何人目の扶養親族に対応する情報なのかも区別する必要があります。

YomiToku Studioの帳票解析では、こうした項目名と値の対応関係や、帳票内の階層構造を解析します。項目名と値の組み合わせをKey-Value、行と列で構成される表をGridとして扱い、帳票に記載された情報を構造化します。

さらに、解析結果を修正してテンプレートとして保存することで、レイアウトが決まっている固定帳票の処理に利用できます。抽出する項目やその位置を一度定義すれば、同じ様式の帳票へ繰り返し適用できます。

YomiToku Studioで帳票を解析する

まず、YomiToku Studioのトップ画面から「帳票解析」を選択します。

トップ画面で「帳票解析」を選択
トップ画面で「帳票解析」を選択

今回は、源泉徴収票の様式を画像にしたものを使用します。[Files]から[画像 / PDFを追加]を選択し、解析対象の画像を読み込みます。画面中央にファイルをドラッグ&ドロップして追加することもできます。

帳票画像の読み込み
帳票画像の読み込み

画像を追加したら、ページ一覧で対象を選択し、[選択したページを解析]を押します。

対象のページを選択して解析
対象のページを選択して解析

解析が完了すると、中央に帳票画像、右側に読み取り結果が表示されます。画像上には、検出されたセルや項目と値の対応関係が表示されるため、元の帳票と見比べながら結果を確認できます。

解析結果を修正してテンプレートを作成する

帳票解析では、項目と値の対応や表の構造を自動で推定します。ただし、源泉徴収票のように複雑なレイアウトを持つ帳票では、意図した構造と異なる結果になることもあります。

YomiToku Studioでは、解析結果を画面上で修正し、必要な構造に整えることができます。自動解析で検出したセル領域を利用できるため、すべての領域を一から定義する必要はありません。今回は、「16歳未満の扶養親族」の欄を例に修正方法を紹介します。

Gridとして認識された領域を修正する

今回の解析結果では、「16歳未満の扶養親族」の欄がGridとして認識されていました。この欄を、扶養親族ごとにフリガナや氏名を持つKey-Value構造として定義し直します。

まず、右パネルに表示された該当Gridの[削除]を押します。セルの領域情報は保持されるため、それらを使って項目と値の対応を設定できます。

Gridとして認識された扶養親族欄を修正
Gridとして認識された扶養親族欄を修正

親ヘッダーを追加する

次に、複数の項目をまとめる見出しとなる「親ヘッダー」を追加します。

[+ 親ヘッダーを追加]を押し、画像上の「16歳未満の扶養親族」のセルをドラッグ&ドロップで指定します。[追加先]には[最上位]を選択します。

「16歳未満の扶養親族」を親ヘッダーとして追加
「16歳未満の扶養親族」を親ヘッダーとして追加

続いて、1人目を表す「1」のセルを親ヘッダーとして追加します。今度は[追加先]に「16歳未満の扶養親族」を選択することで、その下に「1」という階層を作成できます。このように親ヘッダーを定義すると、同じ「氏名」という項目でも、1人目と2人目の扶養親族に属する情報を区別できます。

「1」を「16歳未満の扶養親族」の下に追加
「1」を「16歳未満の扶養親族」の下に追加

親ヘッダーは、帳票上のセルを指定する方法に加え、テキスト入力でも作成できます。帳票に印刷されている見出しを使う場合はセル指定、任意の名前で項目をまとめたい場合はテキスト入力を利用できます。

項目と値の対応を追加する

親ヘッダーを作成したら、その下にフリガナや氏名の項目を追加します。

[+ 項目(キーと値)を追加]を押し、キーとなる見出しのセルと、値を記入するセルを指定します。フリガナの場合は、「(フリガナ)」のセルをキー、その横の記入欄を値として設定します。

さらに、[帰属先の親ヘッダー]に「16歳未満の扶養親族 / 1」を選択します。これにより、1人目の扶養親族に属する項目として追加できます。

キーセル・値セルと帰属先の親ヘッダーを設定
キーセル・値セルと帰属先の親ヘッダーを設定

追加後は、画像上でも項目と値の対応関係を確認できます。同じ手順で氏名や区分を追加し、2人目以降の欄も設定します。

追加した項目の対応関係を確認
追加した項目の対応関係を確認

このように修正することで、次のような階層構造を定義できます。

16歳未満の扶養親族
├─ 1
│  ├─ フリガナ
│  ├─ 氏名
│  └─ 区分
├─ 2
│  ├─ フリガナ
│  ├─ 氏名
│  └─ 区分
…

すでに追加されている項目は、構造ツリー上で親ヘッダーへドラッグすることで所属を変更できます。また、画像上のセルをクリックすると右パネルの対応する項目へ移動するため、帳票を見ながら修正を進められます。

修正後の帳票は、以下のようになります。今回の源泉徴収票では112項目を抽出対象として設定し、テンプレートの作成にかかった時間は約10分でした。

修正後の帳票構造
修正後の帳票構造

帳票テンプレートを保存する

項目と値の対応を確認したら、[Template]からテンプレートを保存します。

保存対象の項目を選択し、テンプレート名を入力して[テンプレートを保存]を押すと、JSON形式のファイルが出力されます。

帳票テンプレートの保存
帳票テンプレートの保存

このファイルには、帳票のセル領域や項目の対応関係などが保存されます。以降は、このテンプレートを読み込むことで、同じ形式の帳票に定義した構造を適用できます。

作成したテンプレートで帳票を解析する

ここからは、作成したテンプレートを使って、記入済みの源泉徴収票を解析します。

まず、[Template]の[ファイルから読み込む]から、保存したJSONファイルを読み込みます。[一括解析で自動適用する]を有効にすると、追加した帳票の解析にテンプレートが使われます。

保存したテンプレートの読み込み
保存したテンプレートの読み込み

今回は、氏名や住所、金額などが異なる10件の疑似データを用意しました。画像を読み込み、[選択した10ページを解析]を押します。

疑似データ10件を読み込んで解析
疑似データ10件を読み込んで解析

以下は、作成したテンプレートを使用して解析している画面です。定義した項目に沿って、各帳票の住所や氏名、金額などが読み取られています。

テンプレートを使用した帳票解析
テンプレートを使用した帳票解析

テンプレートを利用することで、帳票ごとに項目の対応関係を設定することなく、同じ構造で結果を取得できます。

解析結果をJSONで取得する

解析結果は、画面上で確認・修正した後、エクスポートすることでJSON形式で取得できます。以下は、1件目の帳票からエクスポートした sample_001.json の一部です。説明に必要な項目のみを抜粋し、読み取った値はそのまま掲載しています。

{
  "tables": [
    {
      "id": "t0",
      "kv_items": {
        "支払を受ける者": {
          "住所又は居所": "東京都サンプル区架空町1丁目2番3号サンプルハイツ101号室"
        },
        "氏名": "(フリガナ)ヤマダタロウ\n山田太郎",
        "支払金額": "内千円4200000",
        "源泉徴収税額": "内千円52000",
        "16歳未満の扶養親族": {
          "1": {
            "(フリガナ)": "ヤマダソラ",
            "氏名": "山田空",
            "区分": ""
          }
        }
      }
    }
  ]
}

住所や氏名、金額が項目ごとに整理されているほか、Studioで設定した親ヘッダーの階層もJSONに反映されています。「16歳未満の扶養親族」の下に「1」があり、その中にフリガナや氏名が格納されていることが分かります。

このように、帳票上の項目と値の対応を保ったまま取得できるため、必要な情報をプログラムで取り出し、集計やシステムへの登録に利用できます。金額欄の「内」「千」「円」など、印刷済みの文字も含まれる場合は、用途に合わせて整形します。

なお、テンプレートは同じレイアウトの帳票への適用を前提としています。様式や画像の切り出し範囲が変わる場合は、テンプレートもそれに合わせて調整する必要があります。

YomiTokuのCLIと連携してバッチ解析する

Studioから保存したテンプレートには、セルの位置や、項目名と値の対応関係などが含まれています。

YomiTokuでは、このテンプレートに保存された構造を使用し、入力画像から読み取った文字を各欄へ割り当てます。帳票ごとに表やセルの構造を推定する処理を省き、あらかじめ定義した構造で情報を取り出せます。

今回の処理の流れは以下のとおりです。

  1. YomiToku Studioで帳票を解析する
  2. 項目と値の対応や階層構造を修正する
  3. 帳票テンプレートをJSON形式で保存する
  4. YomiTokuのCLIでテンプレートを読み込む
  5. 同じ形式の帳票をまとめて解析し、JSONとして出力する

CLIによる解析は、YomiTokuをインストールしたPCや自社で管理するサーバー上で実行できます。GUIで作成したテンプレートを処理環境へ配置し、定期的なバッチ処理や既存システムからの呼び出しに利用できます。

ここまでに作成したテンプレートを使い、次はCLIから解析を実行します。

解析対象の帳票を用意する

今回は、氏名や住所、給与額などを変えた源泉徴収票の疑似データ10件を使用します。配偶者や扶養親族の有無にも違いを付けていますが、帳票のレイアウトは共通です。

解析に使用する源泉徴収票の疑似データ
解析に使用する源泉徴収票の疑似データ

各画像は、テンプレートを作成した帳票と同じ範囲で切り出しています。画像サイズは1754×2480pxです。氏名・住所・番号・金額は、いずれも記事用に作成した架空のデータです。

CLIからテンプレートを指定して解析する

YomiTokuの導入方法は、公式のインストールガイドを参照してください。

Studioのテンプレートを利用するには、yomitoku_table コマンドの --studio-template に、保存したJSONファイルを指定します。入力には画像ファイルだけでなく、フォルダを指定することもできます。

例えば、画像を input フォルダにまとめ、テンプレートを template.json として配置した場合は、次のコマンドで解析できます。

yomitoku_table ./input \
  --studio-template template.json \
  --tr_name parseq-middle-dynw-v5 \
  --simple \
  -d cuda \
  -o results

ここでは、文字認識モデルに parseq-middle-dynw-v5 を指定し、GPUで実行しています。--simple は、座標などのメタ情報を省き、読み取った文字とその構造をJSONで出力するためのオプションです。

実行すると、入力フォルダ内の帳票が順に処理され、ページごとにJSONファイルが出力されます。今回の実行では、10件すべての帳票について出力を確認できました。

sample_001_p1.json
sample_002_p1.json
sample_003_p1.json
…
sample_010_p1.json

オプションの詳細や、座標を含む出力形式については、Table Semantic ParserのCLIドキュメントで紹介しています。

解析結果を確認する

以下は、3件目の帳票の解析結果から、氏名・金額・扶養親族に関する部分を抜粋したものです。値は実際の出力のまま掲載しています。

{
  "氏名": "(フリガナ)スズキケンイチ\n鈴木健一",
  "支払金額": "内千円5400000",
  "源泉徴収税額": "内千円114000",
  "16歳未満の扶養親族": {
    "1": {
      "(フリガナ)": "スズキソラ",
      "区分": "",
      "氏名": "鈴木空"
    },
    "2": {
      "(フリガナ)": "スズキリン",
      "区分": "",
      "氏名": "鈴木凛"
    },
    "3": {
      "(フリガナ)": "",
      "区分": "",
      "氏名": ""
    },
    "4": {
      "(フリガナ)": "",
      "区分": "",
      "氏名": ""
    }
  }
}

Studioで設定した「16歳未満の扶養親族 → 1 → 氏名」という階層が、JSONにも反映されています。同じ「氏名」という項目でも、1人目と2人目の扶養親族を区別して取得できます。

Pythonで1人目の氏名を取り出す場合は、次のように記述できます。

import json

with open(
    "results/sample_003_p1.json",
    encoding="utf-8",
) as f:
    result = json.load(f)

items = result["tables"][0]["kv_items"]
name = items["16歳未満の扶養親族"]["1"]["氏名"]
print(name)
# 鈴木空

このように、画面上で定義した項目の対応関係や階層構造を、そのままプログラムから利用できます。出力されたJSONから必要な項目を取り出し、CSVへの変換やデータベースへの登録など、後段の処理につなげられます。

金額や番号を扱う際の確認

今回の結果では、支払金額が 内千円5400000 として出力されています。これは、金額の欄に印刷されている「内」「千」「円」も、数値と一緒に読み取られているためです。集計などに利用する場合は、帳票の表記に合わせてこれらを整理し、数値へ変換する必要があります。

実行後、氏名・支払金額・給与所得控除後の金額・所得控除の額の合計額・源泉徴収税額・16歳未満扶養親族の数の6項目を確認しました。空白や印刷済みのラベルを整理したうえで、10件すべてについて、疑似データに設定した値と一致することを確認しています。これは6項目×10件の計60個の値を確認した結果であり、帳票内の全項目に対する認識精度を示すものではありません。

一方で、すべてゼロで作成したダミー個人番号には、桁の欠落などの誤認識がありました。また、タイトルにも文字の重複が見られました。テンプレートによって構造を定義した場合も、読み取り値の確認は必要です。実際の運用では、番号の桁数や必須項目の有無などをチェックする処理を組み合わせることができます。

今回の処理時間

今回の実行では、GPUにNVIDIA GeForce RTX 3090を1台使用しました。ページ単位の処理時間は初回が2.66秒、2件目以降が0.85〜0.93秒で、10件の合計は約10.5秒でした。

この値は、モデルの初期化や画像の読み込みを除いたページ処理時間です。処理速度は画像の内容や実行環境によって変わりますが、今回のように同じ形式の帳票をまとめて処理する流れを確認できました。

まとめ

本記事では、YomiToku Studioで源泉徴収票のテンプレートを作成し、YomiTokuでバッチ解析するまでの流れを紹介しました。

Studioでは、自動解析した結果をもとに、項目と値の対応や親ヘッダーの階層を画面上で修正できます。作成した構造はテンプレートとして保存し、同じ形式の帳票に繰り返し適用できます。

さらに、保存したテンプレートをCLIから利用することで、複数の帳票をまとめて構造化し、後段のデータ処理につなげることも可能です。GUIによるテンプレート作成とCLIによるバッチ処理を組み合わせ、固定帳票の情報を活用する方法として、ぜひ試してみてください。

文字認識モデルv5の改善内容については、YomiToku文字認識モデルv5へのアップデートレポートでも紹介しています。YomiToku Studioの概要は製品ページをご覧ください。

まずはブラウザでお試しください

無料Web版はインストール不要です。高速・高精度な解析には、 お客様の環境で稼働するYomiToku Proを接続できます。

ご利用前にYomiToku Studio利用規約をご確認ください。