Tesseract と Pytesseract による日本語 PDF の OCR 処理
Tesseract OCR v4 と pytesseract を使って PDF から日本語テキストを抽出し、出力を整えるための正規化処理も行います。
Tesseract OCR v4 と、その Python ラッパーである pytesseract を使って PDF から日本語テキストを抽出します。
題材とするのは、太宰治による、現在パブリックドメインとなっている作品「走れメロス」です。
必要なもの
始める前に、以下のライブラリがインストールされていることを確認してください。
Tesseract OCR 本体も必要です。この記事では Docker イメージにインストールします。ほかのインストール方法は、公式リポジトリを参照してください。
構築
Python スクリプトの作成
import refrom datetime import datetime
import pdf2imageimport pytesseract
def to_images(pdf_path: str, first_page: int = None, last_page: int = None) -> list: """ Convert a PDF to a PNG image.
Args: pdf_path (str): PDF path first_page (int): First page starting 1 to be converted last_page (int): Last page to be converted
Returns: list: List of image data """
print(f'Convert a PDF ({pdf_path}) to a png...') images = pdf2image.convert_from_path( pdf_path=pdf_path, fmt='png', first_page=first_page, last_page=last_page, ) print(f'A total of converted png images is {len(images)}.') return images
def to_string(image) -> str: """ OCR an image data.
Args: image: Image data
Returns: str: OCR processed characters """
print(f'Extract characters from an image...') return pytesseract.image_to_string(image, lang='jpn')
def normalize(target: str) -> str: """ Normalize result text.
Applying the following: - Remove new line. - Remove spaces between Japanese characters.
Args: target (str): Target text to be normalized
Returns: str: Normalized text """
result = re.sub('\n', '', target) result = re.sub('([あ-んア-ン一-鿐])\s+((?=[あ-んア-ン一-鿐]))', r'\1\2', result) return result
def save(result: str) -> str: """ Save the result text in a text file.
Args: result (str): Result text
Returns: str: Text file path """
path = 'result.txt' with open(path, 'w') as f: f.write(result) return path
def main() -> None: start = datetime.now() result = ''
images = to_images('run-melos.pdf', 1, 2) for image in images: result += to_string(image) result = normalize(result) path = save(result)
end = datetime.now() duration = end.timestamp() - start.timestamp()
print('----------------------------------------') print(f'Start: {start}') print(f'End: {end}') print(f'Duration: {int(duration)} seconds') print(f'Result file path: {path}') print('----------------------------------------')
if __name__ == '__main__': main()Dockerfile の作成
6 行目の run-melos.pdf はこちらからダウンロードできます。
FROM python:3.10
WORKDIR /usr/src/appCOPY app.py ./COPY requirements.txt ./COPY run-melos.pdf ./RUN apt update && apt install -y poppler-utils tesseract-ocr tesseract-ocr-jpn \ && pip install -r requirements.txt
CMD ["python", "app.py"]# CMD ["/bin/sh", "-c", "while :; do sleep 10; done"]テスト
このスクリプトは、pdf2image で PDF の各ページを PNG 画像データに変換し、pytesseract を介して Tesseract OCR で文字を抽出して、結果をテキストファイルに保存します。
NAME=pytesseract-sampledocker build -t $NAME .docker run --name $NAME $NAME
# You can see OCR processing result in `result.txt`.docker cp $NAME:/usr/src/app/result.txt ./less result.txt
# Clean updocker container rm $NAMEdocker image rm $NAME結果
結果は以下からダウンロードできます。
まとめ
パブリックドメインの日本語 PDF を Docker コンテナ内で pdf2image と Tesseract を使って処理し、元の文章とほぼ一致する読みやすいテキストを抽出できました。
pytesseract.image_to_string に渡す lang='jpn' 引数で、Tesseract の日本語用学習データを有効にします。読みやすい出力を得るには、normalize の正規表現も重要です。Tesseract が日本語の文字間に挿入しやすい空白を取り除き、認識結果が断片的に見えるのを防ぎます。
「走れメロス」の元テキストとの比較は、ざっと目を通すだけでなく実際に突き合わせて行う価値があります。見た目の似た漢字同士の誤読は、軽く確認しただけでは見逃しやすいためです。
今回の PDF はスキャンではなく、デジタルで生成された鮮明なテキストであるため、この精度はほぼ最良のケースです。低解像度の資料やスキャン画像で同程度の結果を得るには、OCR の前に画像処理が必要になるでしょう。
Related posts
Python で OPC UA の変数ノードを監視する
opcua-asyncio を使って OPC UA の変数ノードを購読し、ポーリングではなくサーバーからの通知で変更を処理します。
インターネット接続なしで Python パッケージをインストールする
接続可能なマシンで Python パッケージをダウンロードして転送し、インターネットに接続できない環境へインストールする方法を解説します。
EC2 上で Proxy.py を軽量 HTTP プロキシとして動かす
認証機構を持たない Proxy.py を EC2 インスタンス上で動かし、SSH トンネル経由で安全にアクセスします。
保守性とテストしやすさのための依存性注入
密結合な TypeScript クラスを、給与計算、システムクロック、Amazon SES のメーラーを注入する構成へリファクタリングします。
Jasmine でモックオブジェクトのプロパティをスパイする
モックオブジェクトのプロパティをスパイする際に発生する Jasmine の "already been spied upon" エラーを、Object.getOwnPropertyDescriptor で回避する方法を解説します。
