NDLOCR-Lite は、国立国会図書館が公開している日本語OCRです。図書・雑誌等のデジタル化画像からテキストを抽出でき、レイアウト認識(DEIM)と文字認識(PARSeq)を組み合わせた構成になっています。

ndlocr-lite コマンドでCLIから使えますが、バッチ処理パイプラインに組み込んだり、認識結果をプログラム内で直接扱いたい場合には、Pythonからライブラリとして呼び出す方がやりやすいです。

ただし、NDLOCR-Lite はライブラリとしてのAPIが公開されておらず、CLIのエントリポイントを内部的に呼び出す形になります。この記事ではその方法を記録します。

環境構築

Python 3.10 以上が必要です。macOS の場合、システムの Python は 3.9 系のことがあるため、Homebrew 等で 3.12 をインストールしておきます。

brew install python@3.12

pip でのインストール時に externally-managed-environment エラーが出るため、venv 環境を使います。

python3.12 -m venv venv
source venv/bin/activate
pip install git+https://github.com/ndl-lab/ndlocr-lite.git

初回インストール時に ONNX モデル(約160MB)も含めてダウンロードされます。

CLIの構造

NDLOCR-Lite のCLIエントリポイント(ndlocr-lite コマンド)は、内部的には ocr.main() を呼んでいます。main()argparse で引数をパースし、ocr.process(args) に渡すだけのラッパーです。

ndlocr-lite コマンド
  → ocr.main()
    → argparse で Namespace を構築
    → ocr.process(args) を実行

つまり、argparse.Namespace を自前で組み立てれば、ocr.process() を直接呼び出せます。

スクリプトからの呼び出し

import argparse
import os
from pathlib import Path

import ocr

def run(image_path: str, output_dir: str, viz: bool = False):
    base_dir = Path(ocr.__file__).parent

    args = argparse.Namespace(
        sourcedir=None,
        sourceimg=image_path,
        output=output_dir,
        viz=viz,
        det_weights=str(base_dir / "model" / "deim-s-1024x1024.onnx"),
        det_classes=str(base_dir / "config" / "ndl.yaml"),
        det_score_threshold=0.2,
        det_conf_threshold=0.25,
        det_iou_threshold=0.2,
        simple_mode=False,
        rec_weights30=str(base_dir / "model" / "parseq-ndl-16x256-30-tiny-192epoch-tegaki3.onnx"),
        rec_weights50=str(base_dir / "model" / "parseq-ndl-16x384-50-tiny-146epoch-tegaki2.onnx"),
        rec_weights=str(base_dir / "model" / "parseq-ndl-16x768-100-tiny-165epoch-tegaki2.onnx"),
        rec_classes=str(base_dir / "config" / "NDLmoji.yaml"),
        device="cpu",
    )

    ocr.process(args)

if __name__ == "__main__":
    os.makedirs("output", exist_ok=True)
    run("input.jpg", "output")

モデルや設定ファイルのパスは、ocr.__file__(パッケージのインストール先)を起点に解決しています。これにより、venv の場所に依存しません。

出力ファイル

入力画像のファイル名が input.jpg の場合、出力ディレクトリに以下のファイルが生成されます。

ファイル内容
input.txt認識テキスト(行ごとに改行区切り)
input.xmlレイアウト構造付きXML(バウンディングボックス、クラス情報、認識テキスト)
input.jsonJSON形式(バウンディングボックス座標、テキスト、信頼度、縦書き判定フラグ)

viz=True にすると、検出領域を青枠で重ねた可視化画像 viz_input.jpg も出力されます。

JSON の構造は以下のようになっています。

{
  "contents": [
    {
      "boundingBox": [x1, y1, x2, y2],
      "text": "認識されたテキスト",
      "confidence": 0.95,
      "isVertical": true
    }
  ],
  "imginfo": {
    "img_width": 1024,
    "img_height": 768,
    "img_path": "input.jpg"
  }
}

バッチ処理で結果を後続のプログラムに渡す場合は、JSON 出力を読み込むのが扱いやすいです。

引数のカスタマイズ

主要な引数は以下の通りです。

引数デフォルト説明
sourceimg単一画像のパス
sourcedir画像ディレクトリのパス(配下の画像を一括処理)
output出力ディレクトリ
vizFalse可視化画像の出力
device"cpu""cuda" でGPU推論(要 onnxruntime-gpu
simple_modeFalse単一モデルでの認識(通常は文字数に応じて3モデルを切り替え)
det_score_threshold0.2検出スコアの閾値

sourcedir を指定すると、ディレクトリ内の画像(jpg, png, tiff, jp2, bmp)をまとめて処理できます。その場合 sourceimgNone にします。

注意点

  • ocr.process() は公開APIではなく、内部実装に依存した呼び出し方です。NDLOCR-Lite のバージョンアップで引数の構成が変わる可能性があります
  • テキスト出力(.txt)は、縦書き行が50%を超える場合に行順が反転される処理が入っています
  • 文字認識は、予測される文字数に応じて30文字・50文字・100文字用の3つのモデルが自動的に切り替わります(simple_mode=True で単一モデルに固定可能)