お問い合わせ

ブログ

これまでに経験してきたプロジェクトで気になる技術の情報を紹介していきます。

PaddleOCR を PyInstaller で exe 化する徹底解説ガイド(Windows 対応)

Kitaru Kitaru 4 days
PaddleOCR を PyInstaller で exe 化する徹底解説ガイド(Windows 対応)

Python で表構造の OCR(光学文字認識)を行うために便利なライブラリ PaddleOCR
これを実行ファイル(.exe)として配布・運用したい場合、PyInstaller を使えば比較的簡単に変換できますが、そのままでは多くのエラーに直面します。

本記事では以下の内容を徹底解説します:

  • 環境構築とパッケージのインストール
  • PyInstaller による exe 化の基本と .spec ファイル活用術
  • 実行時エラー(例:.versionmklml.dll の不足)への具体的な対処法

PaddleOCR の exe 化には特有の注意点があり、PyInstaller の基本だけでは対応しきれません。
本記事では、コピペでそのまま使える .spec ファイルの具体例を交えながら、再現性の高い手順を紹介します。

Windows 環境で PaddleOCR を安全に単体実行形式に変換したい方は、ぜひ参考にしてみてください。

環境構築

# Python のインストール確認
PS> python --version
Python 3.13.3

# 仮想環境を作成
PS> python -m venv .venv

# 仮想環境を有効化
PS> .\.venv\Scripts\activate
(.venv) PS>

# pip のアップグレード
(.venv) PS> python -m pip install --upgrade pip

# PaddleOCR 関連のインストール
(.venv) PS> python -m pip install paddlepaddle==3.0.0 -i https://www.paddlepaddle.org.cn/packages/stable/cpu/
(.venv) PS> python -m pip install paddleocr
(.venv) PS> python -m pip install setuptools

# pandas のインストール
(.venv) PS> python -m pip install pandas

# PyInstaller のインストール
(.venv) PS> python -m pip install pyinstaller

OCRのサンプルスクリプトと検証画像

サンプルスクリプト(ocr.py)

表構造を含む画像ファイルを読み取り、Excel 形式で出力する簡単な OCR ツールです。

from paddleocr import PPStructureV3
import pandas as pd
import sys

# 表構造認識用の OCR エンジンを初期化
engine = PPStructureV3()

# 処理対象の画像パスを指定(表が写っている画像)
img_path = sys.argv[1]

# 画像から表構造を解析(表があると判断された領域ごとに結果が返る)
results = engine.predict(img_path)

# 最初の表領域の情報を取り出す(通常1画像に1表のケースが多いため)
res = results[0]

# 表の HTML 構造を取得(PPStructureV3 が出力する推定結果)
table_res_list = res.get('table_res_list', [])

# 表構造 HTML を取得(予測結果があれば1つ目を使用)
html = table_res_list[0].get('pred_html', '') if table_res_list else ''

# HTML 構造が取得できていれば、それをpandasで DataFrame に変換
if html:
    try:
        # pandas.read_html は HTMLの table タグを自動で解析して DataFrame に変換する
        dfs = pd.read_html(html)
        df = dfs[0]  # 最初のテーブルだけ取り出す(通常1つ)
        df.to_excel('output.xlsx', index=False)
    except Exception as e:
        print("HTML 解析中にエラーが発生しました:")
        print(e)
else:
    print("表のHTML構造が取得できませんでした。")

📘 コードの詳細な説明については、別のブログ記事 で詳しく解説していますので、そちらもぜひ参考にしてください。

検証画像(kintai.png)

勤怠画像(表形式)

PyInstaller による実行ファイル(.exe)の作成方法

実行ファイル(.exe)を作るコマンド:

(.venv) PS> pyinstaller --onefile ocr.py
  • Python スクリプトを1つの実行ファイル(.exe)に変換します。
  • --onefile オプションで必要なファイルをすべて1つにまとめます。
  • 実行ファイル(.exe)は dist フォルダ内に作成されます。

初回はこのようにコマンドでビルドすることが多いですが、2回目以降は自動生成される .spec ファイル(後述)を使ってビルドすることもできます。

(.venv) PS> pyinstaller ocr.spec

.spec ファイルを使えば、アイコンの設定やデータファイルの同梱、出力先フォルダの変更など、より細かいカスタマイズが可能になります。
複数回ビルドする場合や複雑な構成のアプリでは、.spec ファイルを使うほうが管理しやすくなります。

作成された構成とその意味

ビルドを実行すると下記のようなファイル、フォルダが作成されます。

フォルダ構成

C:\
├─ .venv          ← Python仮想環境
├─ build          ← 一時ビルドファイル(中間生成物)
│  └─ ocr         ← ビルド処理用の作業フォルダ
├─ dist           ← 実行ファイル (.exe) の出力先(最終成果物)
│  └─ ocr.exe     ← 生成された実行ファイル (.exe)(完成品)
├─ ocr.py         ← 元のPythonスクリプト
└─ ocr.spec       ← PyInstallerのビルド設定ファイル

各ファイル/フォルダの意味

ocr.spec(ビルド設定ファイル)

  • PyInstaller が自動生成するビルド設定ファイルです。
  • .py ファイルを .exe に変換する際のルール(含めるファイル、起動設定、データ追加、アイコン指定など)を記述します。
  • カスタマイズも可能で、再ビルド時にこのファイルを指定することで柔軟な設定が可能です。

build フォルダ(中間ファイル)

  • PyInstaller がビルド処理中に使用する一時的なファイルやログが格納されます。
  • 通常は配布に含める必要はありません。
  • 不具合が発生した場合や、.spec ファイルを修正した後には、クリーンビルドを行うことが推奨されます。
  • クリーンビルドの方法:
    • pyinstaller --clean ocr.spec

dist フォルダ(完成した実行ファイルの出力先)

  • 最終的に生成された実行ファイル(.exe)が出力されるフォルダです。
  • --onefile オプションを使うと、依存ファイルをすべて含んだ単一ファイル(1 つの .exe)が作成されます。
  • デフォルトでは複数ファイル構成で出力され、依存 DLL や Python 実行環境なども含まれます。

実行ファイル(.exe)の実行時に発生するエラーとその対処方法

PaddleOCR を PyInstaller で exe 化した直後に実行しようとすると、エラーが発生するケースが非常に多くあります。
これは、PyInstaller が生成した exe に PaddleOCR の動作に必要なファイルやパッケージがすべて含まれていないためです。
PyInstaller の仕組みとして、次のようなものは自動で収集されます:

  • Python コード(import されているモジュール)

しかし、以下のようなものは自動では収集されません

  • 外部ファイル(モデルデータ、設定ファイル、テキストなど)
  • DLL などのネイティブバイナリ
  • 動的に読み込まれるモジュール(例:importlib.import_module() で読み込まれるもの)

このため、ビルドする際に .spec ファイルを編集したり、pyinstaller のコマンドオプションを使って、PyInstaller に明示的に追加情報を与える必要があります。
以降では、実行時エラーの具体例と、それに対応する .spec ファイルの修正方法について、順を追って詳しく解説していきます。

.version ファイルの不足によるエラーの対応

作成した実行ファイル(.exe)を実行すると、次のようなエラーが発生します。

(.venv) PS> ./dist/ocr.exe kintai.png
・・・
FileNotFoundError: [Errno 2] No such file or directory: 'C:\\Users\\[ユーザ名]\\AppData\\Local\\Temp\\_MEI110962\\paddlex\\.version'
[PYI-15608:ERROR] Failed to execute script 'ocr' due to unhandled exception!

エラーの原因

PyInstallerは、実行時に必要なファイルを一時フォルダに展開してからプログラムを実行します。
しかし、paddlex パッケージに含まれている .version ファイルが、ビルド時に実行ファイルに正しく含まれていないため、実行時に見つからずエラーとなります。

対応方法

  • ocr.spec ファイルの Analysis セクションで、paddlex パッケージを明示的に指定して依存ファイルを含める必要があります。
  • これにより .version ファイルも実行ファイルに含まれ、エラーが解消します。

ocr.spec の修正

  • 元の .spec ファイルに追記・修正を行い、paddlex パッケージの依存ファイルを自動収集して含めるようにします。
  • PyInstaller.utils.hooks.collect_all() を使って、データ・バイナリ・隠れたインポートを抽出します。

以下は、修正済みの .spec ファイルです:

# -*- mode: python ; coding: utf-8 -*-

# 指定したパッケージに含まれるファイルを一括収集
from PyInstaller.utils.hooks import collect_all

# 実行ファイルに含めたいパッケージをリストで定義(複数対応可能)
packages = ['paddlex']

# パッケージから収集した各種ファイルを格納するリスト
datas = []         # 設定ファイルやモデルファイルなどのデータファイルを格納
binaries = []      # DLLやSOなどのバイナリファイルを格納
hiddenimports = [] # 動的にインポートされるPythonモジュールの名前を格納

# 各パッケージから必要なファイルを収集
for pkg in packages:
    pkg_datas, pkg_binaries, pkg_hiddenimports = collect_all(pkg)
    datas += pkg_datas
    binaries += pkg_binaries
    hiddenimports += pkg_hiddenimports

# Analysis セクションで収集済みファイルを指定
a = Analysis(
    ...
    # もともと以下のように空リストだった箇所を、
    # collect_all で収集した内容に置き換えています。
    # 変更前:
    # binaries=[],
    # datas=[],
    # hiddenimports=[],
    binaries=binaries,            # 収集したバイナリファイルを渡す
    datas=datas,                  # 収集したデータファイルを渡す
    hiddenimports=hiddenimports,  # 収集した動的インポートモジュールを渡す
    ...
)
...

修正のポイント

packages = ['paddlex']
  • 実行ファイルに含めたい Python パッケージ名をリスト化。
  • .versionpaddlex パッケージの一部として含まれているため、これを指定すれば自動で対象になります。
datas = []
binaries = []
hiddenimports = []

📋 3つのリストの役割

項目 内容例 主な対象
datas モデル・設定ファイル・静的データ .version、HTML、json など
binaries ネイティブバイナリ mklml.dll、iomp5.dll など
hiddenimports 動的インポートされるモジュール ftfy、cv2 など
for pkg in packages:
    pkg_datas, pkg_binaries, pkg_hiddenimports = collect_all(pkg)
    datas += pkg_datas
    binaries += pkg_binaries
    hiddenimports += pkg_hiddenimports
  • 各パッケージに対して collect_all() を使うことで、手動で個別にファイルを指定する手間を省けます。
  • 複数パッケージに対応した、汎用的な実装です。
a = Analysis(
    ...
    binaries=binaries,
    datas=datas,
    hiddenimports=hiddenimports,
    ...
)
  • PyInstaller に収集したファイル情報を渡すことで、.exe に必要なすべてのリソースが含まれるようになります。
  • これにより、FileNotFoundError を防止できます。

paddlex[ocr] の追加依存パッケージ不足によるエラー対応

.spec ファイルを修正後、再ビルドして exe を実行すると、次のようなエラーが発生します。

(.venv) PS> pyinstaller ocr.spec --clean
・・・
(.venv) PS> ./dist/ocr.exe kintai.png
・・・
  File "paddlex\utils\deps.py", line 194, in _wrapper
    require_extra(extra, obj_name=pipeline_name)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "paddlex\utils\deps.py", line 187, in require_extra
    raise RuntimeError(msg)
RuntimeError: `PP-StructureV3` requires additional dependencies. To install them, run `pip install "paddlex[ocr]=="` if you’re installing `paddlex` from an index, or `pip install -e "/path/to/PaddleX[ocr]"` if you’re installing `paddlex` locally.
[PYI-5720:ERROR] Failed to execute script 'ocr' due to unhandled exception!

エラーの原因

このエラーは、PyInstaller で作成した実行ファイルに paddlex[ocr] の追加依存パッケージが含まれていないために発生します。
OCR 関連の機能を実行する際にこれらのパッケージが必要ですが、PyInstaller はこれらを自動検出できません。

対応方法

ocr.spec ファイルに、paddlex[ocr] が依存する Python パッケージを明示的に追加して収集する必要があります。
paddlex[ocr] の依存パッケージは、GitHub の setup.py に以下のように定義されています。

        ...
        "ocr": [
            "einops",
            "ftfy",
            "imagesize",
            "Jinja2",
            "lxml",
            "opencv-contrib-python",
            "openpyxl",
            "premailer",
            "pyclipper",
            "pypdfium2",
            "regex",
            "scikit-learn",
            "shapely",
            "tiktoken",
            "tokenizers",
        ],
        ...

ocr.spec の修正

以下のように、依存する Python パッケージの import 名を collect_all() に渡して収集します。

packages = [
    'paddlex',
    # 以下の依存パッケージも追加してください
    'einops',
    'ftfy',
    'imagesize',
    'jinja2',          # PyPI名 Jinja2 → import名 jinja2
    'lxml',
    'cv2',             # PyPI名 opencv-contrib-python → import名 cv2
    'openpyxl',
    'premailer',
    'pyclipper',
    'pypdfium2',
    'regex',
    'sklearn',         # PyPI名 scikit-learn → import名 sklearn
    'shapely',
    'tiktoken',
    'tokenizers',
]

⚠️ 注意:collect_all() に渡すのは「import 名」

PyPI に登録されているパッケージ名と、Python の import 名は異なることがあります。
collect_all() に渡すのは、Python の import 名(モジュール名)である必要があります。

例(PyPI のパッケージ名と Python の import 名)

  • scikit-learnsklearn
  • Jinja2jinja2
  • opencv-contrib-pythoncv2

import 名の調べ方

  • Google 検索:「scikit-learn import名」などで検索すると、公式ドキュメントや解説が見つかります。
  • AI に聞く:ChatGPT などに「Jinja2のimport名は?」と尋ねればすぐに確認できます。

mklml.dll の不足によるエラーの対応

.specファイル修正後に再ビルドして exe を実行すると、次のようなエラーが発生します。

(.venv) PS> pyinstaller ocr.spec --clean
・・・
(.venv) PS> ./dist/ocr.exe kintai.png
・・・
RuntimeError: (PreconditionNotMet) The third-party dynamic library (mklml.dll) that Paddle depends on is not configured correctly. (error code is 126)
  Suggestions:
  1. Check if the third-party dynamic library (e.g. CUDA, CUDNN) is installed correctly and its version is matched with paddlepaddle you installed.
  2. Configure third-party dynamic library environment variables as follows:
  - Linux: set LD_LIBRARY_PATH by `export LD_LIBRARY_PATH=...`
  - Windows: set PATH by `set PATH=XXX;%PATH%`
  - Mac: set  DYLD_LIBRARY_PATH by `export DYLD_LIBRARY_PATH=...` [Note: After Mac OS 10.11, using the DYLD_LIBRARY_PATH is impossible unless System Integrity Protection (SIP) is disabled.] (at ..\paddle\phi\backends\dynload\dynamic_loader.cc:344)

[PYI-13060:ERROR] Failed to execute script 'ocr' due to unhandled exception!

エラーの原因

  • paddlepaddle が内部で依存している MKL ライブラリ(mklml.dll)が見つからないために発生します。
  • エラーコード 126 は「DLL が見つからない」ことを示しています。

対応方法

  • PyInstaller でビルドする際に、paddlepaddle が依存している mklml.dll を実行ファイルに含める必要があります。
  • これらの DLL は paddle/libs フォルダに格納されています。
  • collect_all() は Python のパッケージやモジュールに関連する依存ファイルを主に検出するため、外部のネイティブ DLL などは自動で検出できない場合があります。
  • そのため、PyInstaller の .spec ファイル内で datas.append() を使って、mklml.dll を明示的に追加するのが確実です。

ocr.spec の修正(一部)

# -*- mode: python ; coding: utf-8 -*-

...

for pkg in packages:
    pkg_datas, pkg_binaries, pkg_hiddenimports = collect_all(pkg)
    datas += pkg_datas
    binaries += pkg_binaries
    hiddenimports += pkg_hiddenimports

# 以下の処理を追加してください。
# paddle/libs フォルダ内の DLL(例: mklml.dll)を含める
# datas.append((コピー元パス, 実行ファイル(.exe)内での配置先パス))
datas.append(('.venv/Lib/site-packages/paddle/libs', 'paddle/libs'))

a = Analysis(
    ...
    datas=datas,
    ...
)

修正のポイント

  • datas(元のファイル・フォルダのパス, exe 内での配置先パス)タプル を要素とするリストです。
  • ここでは、paddle/libs フォルダごと指定しています。これはフォルダ内に複数の DLL ファイルがあり、どれも実行時に必要になる可能性があるためです。
  • collect_all() ではこれらの DLL が自動検出されにくいため、まとめてフォルダ指定して明示的に含めています。
  • これにより、実行時の DLL 不足によるエラーを防止します。

すべての修正を反映した .spec ファイル(完成版)

# -*- mode: python ; coding: utf-8 -*-

from PyInstaller.utils.hooks import collect_all

packages = [
    'paddlex',
    'einops',
    'ftfy',
    'imagesize',
    'jinja2',
    'lxml',
    'cv2',
    'openpyxl',
    'premailer',
    'pyclipper',
    'pypdfium2',
    'regex',
    'sklearn',
    'shapely',
    'tiktoken',
    'tokenizers',
]

datas = []
binaries = []
hiddenimports = []

for pkg in packages:
    pkg_datas, pkg_binaries, pkg_hiddenimports = collect_all(pkg)
    datas += pkg_datas
    binaries += pkg_binaries
    hiddenimports += pkg_hiddenimports

datas.append(('.venv/Lib/site-packages/paddle/libs', 'paddle/libs'))

a = Analysis(
    ['ocr.py'],
    pathex=[],
    binaries=binaries,
    datas=datas,
    hiddenimports=hiddenimports,
    hookspath=[],
    hooksconfig={},
    runtime_hooks=[],
    excludes=[],
    noarchive=False,
    optimize=0,
)
pyz = PYZ(a.pure)

exe = EXE(
    pyz,
    a.scripts,
    a.binaries,
    a.datas,
    [],
    name='ocr',
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    upx_exclude=[],
    runtime_tmpdir=None,
    console=True,
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None,
)

まとめ:PyInstaller で PaddleOCR を扱う際に押さえておきたい2つのポイント

✅ パッケージ全体を確実に組み込むには collect_all() を使うこと

collect_all() を使えば、対象パッケージの構成ファイル・データ・依存モジュールなどを自動で収集できます。
PaddleOCR のように多くの内部依存を持つライブラリでは特に効果的です。


✅ 個別ファイルや追加モジュールが必要な場合は明示的に指定すること

一部のファイルは collect_all() だけでは拾われないことがあるため、必要に応じて Analysis セクションの binariesdatashiddenimports に直接記述します。


💡これら2点を押さえて .spec ファイルを設計すれば、PyInstaller でのビルドは安定しやすくなります。

おわりに

本記事では、PaddleOCR を Windows 環境で PyInstaller を使って exe 化するための手順を、トラブルシューティング込みで徹底解説しました。

PaddleOCR の exe 化は手順自体は単純に見えますが、実際には多くの依存関係や DLL の取り扱いが必要となり、PyInstaller のデフォルト動作だけでは正常に動作しないケースがほとんどです。
今回紹介した .spec ファイルの修正を行うことで、.version ファイルの読み込みエラーや、mklml.dll の不足による実行時エラーなど、代表的な問題を確実に回避できるようになります。

配布や実運用に向けて Python の環境に依存しない実行ファイル(.exe)を生成したい方にとって、本記事が exe 化の成功にお役立ていただければ幸いです。

PaddleOCR を PyInstaller で exe 化する徹底解説ガイド(Windows 対応) 2025-07-18 15:54:49

コメントはありません。

4056

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

お問い合わせ
gomibako@aska-ltd.jp