導入
輪郭が取れたら、それを囲む長方形(バウンディングボックス)を求め、その部分だけを切り出せます。「文字が写っている場所だけを OCR に渡す」ための、実務でよく使う操作です。
説明
import numpy as np
import cv2
import matplotlib.pyplot as plt
base = np.full((120, 320), 255, dtype=np.uint8)
cv2.putText(base, "CROP", (30, 85), cv2.FONT_HERSHEY_SIMPLEX, 2.5, 0, 5)
_, binary = cv2.threshold(base, 128, 255, cv2.THRESH_BINARY_INV)
contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# すべての輪郭を囲む1つの長方形を求める
xs, ys, ws, hs = [], [], [], []
for c in contours:
x, y, w, h = cv2.boundingRect(c) # 輪郭を囲む長方形 (左上x, 左上y, 幅, 高さ)
xs.append(x); ys.append(y); ws.append(x + w); hs.append(y + h)
x0, y0, x1, y1 = min(xs), min(ys), max(ws), max(hs)
print("文字全体の範囲:", (x0, y0, x1, y1))
# その範囲を切り出す(NumPy のスライス)
cropped = base[y0:y1, x0:x1]
fig, ax = plt.subplots(1, 2, figsize=(8, 3))
ax[0].imshow(base, cmap="gray"); ax[0].set_title("original"); ax[0].axis("off")
ax[1].imshow(cropped, cmap="gray"); ax[1].set_title("cropped"); ax[1].axis("off")
cv2.boundingRect(輪郭)… その輪郭を囲む最小の長方形(x, y, 幅, 高さ)を返します。- 複数文字をまとめて囲むため、全輪郭の左上・右下をかき集めて全体の範囲を計算しています。
base[y0:y1, x0:x1]… NumPy のスライスで画像の一部を切り出します(縦, 横 の順)。この「余白を落とした画像」を OCR に渡すと、精度が上がります。
やってみよう
cv2.putText の文字や位置を変えると、切り出される範囲も追随します。余白だらけの画像でも、必要な部分だけがきれいに取り出せることを確かめましょう。
演習
切り出した cropped 画像の サイズ(形) を print してください。
ヒント1を見る
print("切り出しサイズ:", cropped.shape)。(高さ, 幅) が返ります。
ヒント2を見る
元の (120, 320) より小さくなっていれば、余白がうまく落ちています。