PDF には OCR が必要ですか? PyMuPDF を使用して、完全な再認識の代わりにページごとのプリフライトを実行する
PDF を OCR したい場合、PDF 全体を再認識する必要はありません。 PyMuPDF を使用して、テキスト レイヤーの有無と全ページ画像かどうかをページごとに判断し、認識に本当に必要なページのみを送信します。実行可能なサンプル、回転ページ テスト、および分岐境界命令が添付されています。
この記事のポイント
・PDF全体を一律にスキャンと判定しないでください。 OCR するかどうかを決定する前に、テキスト レイヤーとページ全体の画像をページごとに記録する必要があります。
- 空白以外の文字が 40 文字以上あるページは直接抽出されます。単語が 40 未満で、単一の画像が 70% 以上を占めるページは、OCR 候補に入力されます。
- 残りのページは手動検査に入ります。空白スペース、ベクトルワード、複雑なレイアウトはこのカテゴリに分類される可能性があるため、黙って破棄すべきではありません。
- 40 単語と 0.70 という 2 つのしきい値は、テスト目的でのみ監査可能であり、言語間の標準ではありません。中国語、数式などは別途校正が必要です。
・隠しテキストレイヤーは文字化けする場合があり、標準文字数に達していても信頼できるものではありません。契約番号や金額などの主要なフィールドはランダムにチェックする必要があります。
PDF の翻訳やアーカイブを扱う多くのチームは、入り口で文書全体に「スキャン済み」または「コピー可能」というラベルを付けることに慣れています。 300 ページの PDF では、最初の 280 ページにテキスト レイヤーが含まれ、最後の 20 ページのみがスキャンされた添付ファイルとして含まれる場合があります。全体の部分ごとに分類すると、OCR 全体の待ち時間が長くなり、本来正しい数値を誤認識する可能性もあります。一方で、ホームページのテキストのみをコピーし、すべてのページで OCR をスキップできる場合は、これも危険です。
より信頼性の高いアプローチは、プリフライトの結果を使用して各ページを次のステップに進めることです。この記事では、直接抽出、OCR 候補キューへの送信、および手動検査という保守的な 3 方向の分割を実装します。これは解釈可能なエンジニアリング ヒューリスティックであり、テキストの品質を判断するための普遍的な分類子ではありません。読んだ後は、実行可能なページごとのプリフライト プログラムのほか、迂回境界や一般的な障害処理のアイデアを得ることができます。
一文の結論
PDF に OCR が必要かどうかを判断する必要はありません。 PyMuPDF を使用してページごとに事前チェックし、本当に認識する必要があるページのみを OCR に送信します。
| あなたの状況 | 推奨される実践方法 | 理由 |
|---|---|---|
| 1 ページから少なくとも 40 個の空白以外の文字を抽出する | 直接抽出 (TEXT_CANDIDATE) | すでに十分な文字がありますが、隠れた不良 OCR レイヤーをスポットチェックする必要があります |
| 40 単語未満で、ページの少なくとも 70% を占める 1 つの画像 | OCR候補キューに送信 | フルページのスキャンは識別に適していますが、純粋な写真でも十分です。 |
| 空白のページ、ベクタータイプ、まばらなタイトル、または複雑なパズル | 手動検査(REVIEW) | これらの状況は最初の 2 つのカテゴリに確実に分類できず、自動的にスキップしたり破棄したりすることもできません。 |
| 300 ページのハイブリッド ドキュメント | 完全な処理ではなく、ページごとにプリフライトします | スキャンされた添付ファイルが少ないためすべてのページの OCR を実行したり、ホームページにテキストがあるためすべての OCR をスキップしたりすることは避けてください。 |
注: 画像のコンテンツは、顧客ファイルや OmniDoc インターフェイスではなく、以下のコードによって生成された合成 PDF からのものです。画像ページ上のテキストはラスター ピクセルです。テキスト ページのテキストには実際のテキスト レイヤーがあります。
最初に何を確認するかを決めます
ここでは、空白を削除した後のテキスト文字数と、ページ上の最大の画像が占めるページ領域の割合という 2 つの信号が使用されます。前者は「十分な文字が抽出されましたか?」と答えます。後者は、全ページ スキャンと空白ページを区別するのに役立ちます。ページ上の画像拡大率を超えないように、画像領域は最初にクロップ ボックスと交差します。
| 観察 | この記事の転用 | まだまだ注意が必要です |
|---|---|---|
| 少なくとも 40 個の空白以外の文字 | TEXT_CANDIDATE | 隠れた不良 OCR レイヤーにも多くの単語が含まれる可能性があります |
| 40 語未満で、少なくとも 70% をカバーする 1 つの画像 | OCR_CANDIDATE | 純粋な写真も条件を満たしますが、OCR は意味がない可能性があります |
| 残りのケース | レビュー | 空白スペース、ベクターテキスト、スパースなタイトル、複雑なパズルなど、すべてがここに存在します |
40と0.70の閾値は、このテスト群の監査を容易にするためのものであり、言語間標準ではありません。 中国語、公式、表紙、短縮形は別々にラベル付けしてください。 ここでは、重複する画像の面積を追加するのではなく、面積ごとの最大の画像を取得します。したがって、複数の画像で構成されたスキャンページはレビューに入ることがあります。 これは意図的に保たれた境界線です。
完全実行可能なサンプル
サンプルはPyMuPDF==1.28.0を使用し、テッセラクトには依存せず、オンラインOCRや翻訳サービスも呼び出していません。 example.pyとして保存し、空のディレクトリで実行します。 作成されるファイル名はrouting-fixture.pdfに固定されています。実際のプロジェクトでは、入力ファイルを上書きしないでください。
import json
import pymupdf
def inspect_page(page):
chars = len("".join(page.get_text().split()))
bounds = page.cropbox
# 图片坐标与文本坐标都是未旋转坐标;不要混用旋转后的 page.rect。
bounds = pymupdf.Rect(0, 0, bounds.width, bounds.height)
ratios = []
for image in page.get_image_info():
rect = pymupdf.Rect(image["bbox"]) & bounds
ratios.append(max(0, rect.get_area()) / bounds.get_area())
largest = max(ratios, default=0.0)
route = ("TEXT_CANDIDATE" if chars >= 40 else
"OCR_CANDIDATE" if largest >= 0.70 else "REVIEW")
return {"page": page.number + 1, "chars": chars,
"largest_image_ratio": round(largest, 3), "route": route}
with pymupdf.open() as source:
page = source.new_page(width=360, height=480)
page.insert_text((28, 60), "Sample invoice 2026-09-26", fontsize=16)
page.insert_text((28, 100), "Quantity 12 Unit price USD 15.00", fontsize=12)
page.insert_text((28, 132), "Amount USD 180.00 Checked manually", fontsize=12)
scan = page.get_pixmap(matrix=pymupdf.Matrix(2, 2)).tobytes("png")
page = source.new_page(width=360, height=480)
page.insert_image(page.rect, stream=scan)
source.new_page(width=360, height=480)
source.save("routing-fixture.pdf")
with pymupdf.open("routing-fixture.pdf") as pdf:
result = [inspect_page(page) for page in pdf]
assert [r["route"] for r in result] == [
"TEXT_CANDIDATE", "OCR_CANDIDATE", "REVIEW"]
assert result[1]["chars"] == 0
assert result[1]["largest_image_ratio"] == 1.0
pdf[1].set_rotation(90)
assert inspect_page(pdf[1])["route"] == "OCR_CANDIDATE"
print(json.dumps(result, indent=2))
OCRにアクセスする際は、成功マーカーではなくTextPageをキャッシュしてください
PyMuPDFのOCRインターフェースはpage.get_textpage_ocr(...)です。 テッセラクトおよび対応する言語データは別途準備する必要があります。 TextPageを取得した後、その後の抽出で同じページで重複認識を避けるためにtextpageパラメータとして渡すべきです。 具体的な設置方法やパラメータについては、PyMuPDF OCRドキュメントをご覧ください。
本記事はOCRエンジンを搭載していないため、テスト結果は分布ロジックと座標の使用が正しいことだけを証明しており、中国語の認識率、表の復元率、翻訳品質を表すものではありません。 本番環境では、OCRエンジンのバージョン、言語パック、ページ番号、入力ファイルの要約、手動サンプリング結果を記録する必要があります。 最後の文字列だけを残さないでください。そうしないと、どのページから数字が来ているのか解釈しづらくなります。
最も見落とされがちな三つの断層の種類
隠しテキストレイヤーは文字が乱れている場合があります。 文字数を満たしたということは「抽出を続けられる」という意味です。また、置き換えられた文字、重複行、キーフィールドがレンダリングに対応しているかどうかも確認する必要があります。 契約番号や金額などの重要な項目はランダムに検査しなければなりません。
ベクトルパスで描かれるテキストはテキストでも画像でもありません。 彼らはレビューに入力します。 ページを自動的に空白にマークしたり、ページを静かに落としたりしないでください。
ドキュメントを閉じた後にページを使用すると無効なオブジェクトが生成されます。 with pymupdf.open(...)のスコープを保持し、事前チェック、レンダリング、抽出の後にのみファイルをリリースしてください。 座標、画像情報、ページライフサイクルの詳細については、PyMuPDF Page APIを参照してください。
信頼できないPDFは、ファイルサイズ、ページ数、レンダリングピクセル、時間、メモリ制限を単独プロセスで設定すべきです。 この例は小さなファイルのみをテストしており、悪意のあるファイルのサンドボックスは提供していません。 PyMuPDFを作成・使用する前に、ライセンス条件や配布方法も必ず確認してください。
ストリームから翻訳ワークフローへの移行
限定的な出力とはテキストの列ではなく、ページ番号と決定理由が記載された記録です。 翻訳前に、どのページが確実に抽出可能かを確認してください。 翻訳後、内容、数字、レイアウトが見直されます。OmniDoc製品エントリーで文書処理サービスを確認できます。 この記事のローカルプログラムは独立して動作し、OmniDocアカウントに依存しておらず、内部製品アルゴリズムであるとは限りません。
📊 コア比較
| ルート | トリガー条件 | 適切なページ | 主なリスク |
|---|---|---|---|
| 直接抽出(TEXT_CANDIDATE) | 少なくとも40文字の非スペース文字 | 既存のテキストレイヤーの本文ページ | 隠れた不良OCRレイヤーには乱れたテキストが含まれていることがあります |
| OCR候補者(OCR_CANDIDATE) | 40語未満で、1枚の画像で少なくとも70%をカバーしている | 全ページスキャンコピー | 純粋な写真も要件を満たしていますが、OCRの結果が意味を持たない場合があります |
| 手動検査(レビュー) | 上記の2つのカテゴリーには該当しません | 白紙のページ、ベクターテキスト、まばらなタイトル、複雑なパズル | 手動判断が必要であり、スキップや破棄は自動的にできません |
🎯 どの方法があなたに合いますか?
もし......
- 表紙と裏面で大きな品質差がある混合文書を扱い、ページごとに異なるルートで事前チェックを行います。
- 主に契約書、財務書類、キーナンバーを含むその他の文書を扱います。ページTEXT_CANDIDATEでは、数値とレンダリング間の対応関係をランダムに確認します。
- スキャンのバッチ処理:OCR結果の記録エンジンバージョン、言語パック、ページ番号を活用し、追跡性を軽んじます。
- 未知のソースからPDFを受け取る:スタンドアロンプロセスでリソース制限を設定し、メインプロセスで直接処理しない。
❓ よくある質問(FAQ)
1. ホームページはテキストをコピーできますが、PDF全体のOCRプロセスをスキップしてもいいですか?
いや、できない。 最初のページにテキストレイヤーがあるからといって、次のページにも同じものがあるとは限りません。ページごとに判断すべきです。
2. なぜ画像面積を直接合計しないのですか?
面積ごとに重なる画像を追加すると、カバレッジ率が過大評価されます。 この記事は面積ごとの最大の画像を扱うため、複数の画像をつなぎ合わせたスキャンページは「レビュー」セクションに含まれることがあり、これは意図的な境界線です。
3. 文字数が40文字に達した場合、テキストの品質は問題ないということですか?
そう結論づけることはできません。 隠れた不良OCRレイヤーには多くの文字が含まれていることもあるので、置き換え文字の有無、重複行の有無、キーフィールドの特定などを確認する必要があります。
4. ベクターパスで描かれたテキストはどのように扱うべきでしょうか?
それらはテキストでも画像でもありません。REVIEWと入力し、手動で審査されます。自動的に空白または無音で削除されるべきではありません。
5. 地元のプログラムはOmniDocアカウントに依存していますか?
依存していません。 この記事のローカルプログラムは独立して運営されており、オンラインのOCRや翻訳サービスを呼び出すことはありません。
📝 概要
まず、OCRを行うかどうか決める前に、証拠をページごとに確認してください。 不確実なページをキューに残す方が、不確かな結果を成功として偽装するよりも効果的です。


