本文へスキップ
BecomeCoder

Python画像認識コース · 第3章 OCRのための前処理 · レッスン9

二値化としきい値 ― 白か黒かに分ける

ブラウザで完結

導入

OCR が最も読みやすいのは「文字=黒、背景=白」のくっきりした白黒画像です。中間の灰色を無くし、ある明るさ(しきい値)を境に白か黒へ振り分ける処理を 二値化(binarization) と呼びます。前処理の心臓部です。

説明

from PIL import Image, ImageDraw, ImageFont
import numpy as np
import cv2
import matplotlib.pyplot as plt

img = Image.new("RGB", (300, 100), "white")
draw = ImageDraw.Draw(img)
draw.text((15, 25), "Binary", fill=(60, 60, 60), font=ImageFont.load_default(size=48))
gray = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2GRAY)

# 方法1: 固定しきい値(128より明るい→白, 暗い→黒)
_, fixed = cv2.threshold(gray, 128, 255, cv2.THRESH_BINARY)

# 方法2: 大津(Otsu)の方法(しきい値を自動で決める)
t, otsu = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
print("Otsuが選んだしきい値:", t)

fig, ax = plt.subplots(1, 3, figsize=(10, 3))
ax[0].imshow(gray, cmap="gray"); ax[0].set_title("gray");         ax[0].axis("off")
ax[1].imshow(fixed, cmap="gray"); ax[1].set_title("fixed 128");   ax[1].axis("off")
ax[2].imshow(otsu, cmap="gray");  ax[2].set_title("otsu auto");   ax[2].axis("off")
  • cv2.threshold(画像, しきい値, 最大値, 種類) … 二値化します。戻り値は (使ったしきい値, 二値化画像) の2つ。
  • cv2.THRESH_BINARY … しきい値より明るいピクセルを最大値(255)に、暗いを 0 にします。
  • cv2.THRESH_OTSU を足すと、画像の明るさの分布から最適なしきい値を自動計算してくれます(照明のムラに強い)。このとき最初のしきい値引数(0)は無視されます。

固定しきい値は手軽ですが、写真ごとの明るさの違いに弱いです。まず Otsu を試すのが定石です。

やってみよう

方法1の固定しきい値 12820060 に変えて、白黒の分かれ方がどう変わるか観察しましょう。しきい値が高すぎると文字がかすれ、低すぎると背景が黒くつぶれます。

演習

cv2.THRESH_BINARYcv2.THRESH_BINARY_INV に変えて、白黒を反転した二値化(文字が白・背景が黒)を作って表示してください。

ヒント1を見る

方法1の行を _, fixed = cv2.threshold(gray, 128, 255, cv2.THRESH_BINARY_INV) に変えます。

ヒント2を見る

_INV(inverse=逆)を付けると、白と黒が入れ替わります。輪郭検出では文字を白にすると扱いやすくなります。

実際に動かしてみよう

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

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

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