Tesseract と Pytesseract による日本語 PDF の OCR 処理

Tesseract と Pytesseract による日本語 PDF の OCR 処理

Tesseract OCR v4 と pytesseract を使って PDF から日本語テキストを抽出し、出力を整えるための正規化処理も行います。

Takahiro Iwasa
5 min read

Tesseract OCR v4 と、その Python ラッパーである pytesseract を使って PDF から日本語テキストを抽出します。

題材とするのは、太宰治による、現在パブリックドメインとなっている作品「走れメロス」です。

必要なもの

始める前に、以下のライブラリがインストールされていることを確認してください。

Tesseract OCR 本体も必要です。この記事では Docker イメージにインストールします。ほかのインストール方法は、公式リポジトリを参照してください。

構築

Python スクリプトの作成

app.py
import re
from datetime import datetime
import pdf2image
import 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こちらからダウンロードできます。

Dockerfile
FROM python:3.10
WORKDIR /usr/src/app
COPY 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 で文字を抽出して、結果をテキストファイルに保存します。

Terminal window
NAME=pytesseract-sample
docker 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 up
docker container rm $NAME
docker image rm $NAME

結果

結果は以下からダウンロードできます。

まとめ

パブリックドメインの日本語 PDF を Docker コンテナ内で pdf2image と Tesseract を使って処理し、元の文章とほぼ一致する読みやすいテキストを抽出できました。

pytesseract.image_to_string に渡す lang='jpn' 引数で、Tesseract の日本語用学習データを有効にします。読みやすい出力を得るには、normalize の正規表現も重要です。Tesseract が日本語の文字間に挿入しやすい空白を取り除き、認識結果が断片的に見えるのを防ぎます。

「走れメロス」の元テキストとの比較は、ざっと目を通すだけでなく実際に突き合わせて行う価値があります。見た目の似た漢字同士の誤読は、軽く確認しただけでは見逃しやすいためです。

今回の PDF はスキャンではなく、デジタルで生成された鮮明なテキストであるため、この精度はほぼ最良のケースです。低解像度の資料やスキャン画像で同程度の結果を得るには、OCR の前に画像処理が必要になるでしょう。

About the author

Takahiro Iwasa

Takahiro Iwasa

Software Developer

This blog shares technical notes from hands-on projects—architecture, implementation, and AWS service integrations.