本のスキャンとファイル#02
購入した本をファイルにスキャンする方法はいくつかある。
オーディオ書籍にする本の頻度や総数、裁断機の購入費用やメンテナンスの有無、スキャンして納品されるまでの日数などを考慮してから選択することが望ましい。著者は月に2/3冊の本(総数1000P以内)を試聴で満足しているため、裁断機を購入して自前でスキャンしている。
どちらを選択しても、スキャンされた本の成果物は1つのファイルで出力されている。(例: XXX.pdf)
そのため、オーディオ書籍の作成過程では、OCRにファイルを1ページごとに読み込ませるために個別ファイルに分割する必要がある。PythonライブラリPyPDF2
を利用した分割用の関数を作成してみた。関数の実行環境は何でもよいが、Pythonスクリプトであるため、仮想環境内で実行することを推奨する。※今回スキャンしたファイルとして、青空文庫から「フランケンシュタイン」を拝借している。
# 1ページごとに個別ファイルに分割する
!pip install PyPDF2==2.0.0
## ライブラリ
import os
from PyPDF2 import PdfReader, PdfWriter
def split_pdf_pages(book_path,
save_dir_path,
save_file_name):
'''
<実装>
電子音声書籍の作成のため、1ページごとに個別ファイルに分割する関数
<引数>
book_path : 書籍(PDF)のパス
save_dir_path : 保存ディレクトリ
save_file_name : 保存ファイル名
<コード例>
split_pdf_pages(book_path='book_origin/フランケンシュタイン.pdf',
save_dir_path="book_output_pdf",
save_file_name='フランケンシュタイン')
'''
os.makedirs(save_dir_path, exist_ok=True)
reader = PdfReader(book_path)
for i in range(len(reader.pages)):
writer = PdfWriter()
writer.add_page(reader.pages[i])
output_filename = os.path.join(
save_dir_path, f"{save_file_name}_page_{i+1}.pdf"
)
with open(output_filename, "wb") as output_file:
writer.write(output_file)
print("//1ページ毎の PDF ファイルに分割しました//")
関数を実行すると、1ページごとに分割されたファイルが指定したディレクトリに出力される。
次の作業として、文字をOCRで読み取るために、「PDF」ではなく「JPG」などの拡張子に変換する。Pythonライブラリ#pdf2image
を利用して拡張子を変換する関数を作成した。
#pdf2image を利用するためには{poppler-utils}をインストールすること(Linux)
#apt-get install poppler-utils
!pip install pdf2imag==1.17.0
## ライブラリ
import os
from glob import glob
from pdf2image import convert_from_path
def convert_pdf_to_jpg(book_pdf,
output_dir,
save_file_name):
'''
<実装>
OCR読み取りのために拡張子を変換する(PDF→JPG)
<引数>
book_pdf : 書籍(PDF)のパス
output_dir : 保存ディレクトリ
save_file_name : 保存ファイル名
<コード例>
convert_pdf_to_jpg(book_pdf="book_output_pdf",
output_dir="book_output_jpg",
save_file_name="フランケンシュタイン")
'''
# 保存ディレクトリ
os.makedirs(output_dir, exist_ok=True)
# PDF to JPG
Item = sorted(glob(f"{book_pdf}/*.pdf"))
for i_Page in Item:
Item_Name = i_Page.split("/")[-1].split(".")[0]
Image = convert_from_path(i_Page)
for i in range(len(Image)):
Image[i].save(f'{output_dir}/{Item_Name}.jpg')
print("//ファイルの拡張子を変換しました//(PDF→JPG)//")
関数を実行すると、各ファイルが拡張子「JPG」に変換される。
次の作業として、各ページの不要な部分をトリミングする。
(トリミング例) 文字の読み取りに不要な箇所をトリミングする。(黄色いマーカーの部分)

これをPythonライブラリPillow
を利用してトリミングする。(黄色いマーカーの部分を切り取る)

#トリミング範囲を把握するための関数#
from PIL import Image
import matplotlib.pyplot as plt
# トリミング範囲を検証するため、1枚の画像を選択する
test_image_path = "XXXX.jpg"
# 任意のトリミング幅(この値を調整すること)
top = 0
bottom = 5
left = 0
right = 0
# 画像を開いてサイズ取得
with Image.open(test_image_path) as img:
width, height = img.size
print(f"元画像サイズ: 幅={width}, 高さ={height}")
# トリミング範囲を計算
crop_left = left
crop_upper = top
crop_right = width - right
crop_lower = height - bottom
# トリミング処理
cropped_img = img.crop((crop_left,
crop_upper,
crop_right,
crop_lower))
# トリミング結果を表示
plt.imshow(cropped_img)
plt.axis('off')
plt.title("トリミング結果")
plt.show()
# トリミング後のサイズを表示
print(f"トリミング後サイズ: 幅={cropped_img.width}, 高さ={cropped_img.height}")
#指定したディレクトリ内の全てのファイルを一括でトリミングする関数#
import os
from PIL import Image
from glob import glob
def trimming_page(source_folder,
output_folder,
top=0, bottom=0, left=0, right=0):
"""
指定フォルダ内の全JPG画像を一括でトリミング処理します。
Parameters:
source_folder (str): 元画像のあるフォルダパス
output_folder (str): トリミング後の画像を保存するフォルダパス
top (int): 上端からのトリミングピクセル数
bottom (int): 下端からのトリミングピクセル数
left (int): 左端からのトリミングピクセル数
right (int): 右端からのトリミングピクセル数
<使用例>
trimming_page(
source_folder="test",
output_folder="book_trimmed",
top=40, bottom=5, left=0, right=0)
"""
os.makedirs(output_folder, exist_ok=True)
# .jpg, .jpeg, .JPG すべて対象に
image_paths = []
for ext in ['*.jpg', '*.jpeg', '*.JPG']:
image_paths.extend(glob(os.path.join(source_folder, ext)))
for img_path in sorted(image_paths):
with Image.open(img_path) as img:
width, height = img.size
# トリミング範囲計算
crop_left = left
crop_upper = top
crop_right = width - right
crop_lower = height - bottom
cropped_img = img.crop((crop_left,
crop_upper,
crop_right,
crop_lower))
# 保存処理
filename = os.path.basename(img_path)
save_path = os.path.join(output_folder, filename)
cropped_img.save(save_path)
print(f"//{source_folder} 内の画像を一括トリミングし、{output_folder} に保存しました//")
ここまで関数を実行すると、OCRを利用して文字をテキストファイルで取得する。(#3に続く)
コメント(一覧)