本文へスキップ
BecomeCoder

Python画像認識コース · 第4章 特徴と領域の検出 · レッスン16

文字領域を切り出す ― バウンディングボックス

ブラウザで完結

導入

輪郭が取れたら、それを囲む長方形(バウンディングボックス)を求め、その部分だけを切り出せます。「文字が写っている場所だけを 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) より小さくなっていれば、余白がうまく落ちています。

実際に動かしてみよう

下のエディタにPythonを書いて「実行」を押すと、本物の Pillow・OpenCV(Pyodide)で画像処理をその場で試せます。処理した画像は図として下に表示されます。初回や OpenCV を使う回は読み込みに時間がかかります(数十秒かかることがあります)。しきい値やフィルタの数値を書き換えて、画像の変化を確かめましょう(画像に描く文字は表示が崩れるため英字で書きます。Tesseract などOCRエンジン本体は第5章の読み物で解説します)。

Python — ライブラリ付きで実行(Pyodide)

numpy / pandas / matplotlib が使える本物のPython(Pyodide)を読み込みます。初回のみ読み込みに少し時間がかかります(以降はブラウザにキャッシュされます)。
スクロールして表示された時点でも自動で読み込まれます。