導入
ここまでの前処理を1本のパイプラインにつなげてみましょう。「グレースケール → ノイズ除去 → 二値化」の流れは、実務でそのまま OCR の前段に置く定番の並びです。
説明
from PIL import Image, ImageDraw, ImageFont
import numpy as np
import cv2
import matplotlib.pyplot as plt
# 1) 汚れた入力を作る(傾き+ノイズ)
img = Image.new("RGB", (320, 120), "white")
draw = ImageDraw.Draw(img)
draw.text((20, 35), "Receipt", fill=(40, 40, 40), font=ImageFont.load_default(size=44))
img = img.rotate(-5, expand=True, fillcolor=(255, 255, 255))
arr = np.array(img)
noise = np.random.default_rng(1).integers(-40, 40, arr.shape[:2])
arr = np.clip(arr.astype(int) + noise[..., None], 0, 255).astype(np.uint8)
# 2) パイプライン: グレー → ぼかし → Otsu二値化
gray = cv2.cvtColor(arr, cv2.COLOR_RGB2GRAY)
blur = cv2.GaussianBlur(gray, (3, 3), 0)
_, binary = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# 3) 各段階を並べて確認
fig, ax = plt.subplots(1, 4, figsize=(13, 3))
for a, im, t in zip(ax, [arr, gray, blur, binary],
["1.input", "2.gray", "3.blur", "4.binary"]):
a.imshow(im, cmap=None if im.ndim == 3 else "gray")
a.set_title(t); a.axis("off")
- 入力をわざと傾け・ノイズを載せた「現実に近い画像」から始めています。
- グレー → ぼかし → Otsu 二値化 と順に処理し、最後は文字がくっきりした白黒画像になります。この
binaryを Tesseract に渡すのが、第5章のコードにつながる形です。 - 各段階を並べて表示すると、どの処理で何が良くなったかが一目で分かります。デバッグの基本テクニックです。
やってみよう
cv2.GaussianBlur(gray, (3, 3), 0) を外して(blur = gray にして)二値化すると、ノイズが黒い粒として残るのが分かります。ぼかしの効果を体感しましょう。パイプラインの順番や強さを変えて、最終画像がどう変わるか試してください。
演習
パイプラインの最後に、二値化画像 binary へ モルフォロジーのクロージング(cv2.morphologyEx(..., cv2.MORPH_CLOSE, ...))を足して、文字の途切れを埋めた結果を表示してください。
ヒント1を見る
kernel = np.ones((2, 2), np.uint8) を用意し、closed = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)。
ヒント2を見る
plt.imshow(closed, cmap="gray") で表示。クロージングは「膨張→収縮」で、形を保ったまま隙間を埋めます。