画像・テキストキャプチャの OCR: ゆがんだキャプチャの読み取り方
画像キャプチャは、文字や数字の短い文字列を画像として表示します。ノイズ、回転、波状の線が加えられることもあります。光学文字認識(OCR)を使えば、Tesseract のようなオープンソースのエンジンで、単純なものは読み取れます。精度は画像の鮮明さに左右されるため、作業の大半は前処理です。このガイドでは、動作する Python の構成を示し、どこで失敗するかを説明します。また、Scarnox のライブ API が解くのは PopularCaptcha のウィジェットトークンであり、画像から文字を読み取るキャプチャではないという点をはっきりさせます。OCR は API 呼び出しではなく、自分で作るコードとして計画してください。
OCR がうまくいく場合とそうでない場合
OCR は、テキストが次の条件を満たす場合の妥当な最初の試みです。
- 1行で、文字の間隔が均一である。
- コントラストが高く、明るい背景に暗い文字である。
- 強い歪み、文字の重なり、交差する線がない。
回転した文字、接触した文字、背景のテクスチャ、文字を横切る線には苦労します。それぞれに特定の前処理が必要で、中にはまったく別のモデルが必要なものもあります。精度は想定するのではなく、測定する準備をしておいてください。
ツールのインストール
Python、Tesseract のバイナリ、そして2つの Python パッケージが必要です。
pip install pillow pytesseract
Tesseract 本体は別途インストールが必要です。Windows では Tesseract プロジェクトのインストーラーを使い、実行ファイルを PATH に通すか、pytesseract.pytesseract.tesseract_cmd でそのパスを指定してください。
前処理をしてから読み取る
精度の大部分は、入力の質から生まれます。以下の手順では、グレースケールに変換し、コントラストを上げ、二値化の閾値を適用し、画像を拡大して、キャプチャが使う文字だけに出力を絞ります。
from PIL import Image, ImageOps
import pytesseract
# キャプチャが使う文字。キャプチャが使わない場合は、0/O や 1/I のような見間違えやすい文字を除外してください。
ALLOWED = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"
def read_text(path: str) -> str:
img = Image.open(path)
gray = ImageOps.grayscale(img)
gray = ImageOps.autocontrast(gray)
# ハード閾値: 140 より明るい画素は白、それ以外は黒にする。
bw = gray.point(lambda p: 255 if p > 140 else 0)
# Tesseract は大きな字形の方がうまく読めます。
bw = bw.resize((bw.width * 3, bw.height * 3))
config = f"--psm 7 -c tessedit_char_whitelist={ALLOWED}" # psm 7: 1行のテキスト
return pytesseract.image_to_string(bw, config=config).strip()
if __name__ == "__main__":
print(read_text("sample_captcha.png"))
閾値の 140 は出発点です。処理後の画像を表示して元の画像と比べ、文字がくっきりし、背景がきれいになるまで調整してください。
頼る前に精度を測定する
ある画像を1回正しく読めたとしても、何も証明されません。正解が分かっているキャプチャのセットを保存し、すべてに関数を実行して一致数を数えてください。
def accuracy(samples: dict[str, str]) -> float:
# samples はファイルパスから正解のテキストへの対応
hits = sum(read_text(path) == truth for path, truth in samples.items())
return hits / len(samples)
labelled = {
"samples/0001.png": "K7PQ2",
"samples/0002.png": "M3XN9",
}
print(f"accuracy: {accuracy(labelled):.0%}")
前処理を変えるたびに、この数値を追跡してください。何度か変更しても数値が低いままなら、そのキャプチャの種類には OCR は適していない可能性が高く、別のアプローチを検討すべきです。
失敗する場面
- ノイズと線。 形態学的処理で線を取り除くか、低い成功率を受け入れてください。
- 回転。 角度を推定し、読み取る前に画像を回転させてください。
- 接触した文字。 列ごとに文字を分割して、それぞれ個別に読むと、行全体を読むより上手くいくことが多いです。
- 時間による変化。 サイトは予告なくデザインを変えることがあり、それだけで一晩で精度が下がることがあります。ラベル付きのセットを保管し、定期的に再実行してください。
前処理のチェックリスト
読み取りに失敗したら、次の項目を順番に確認してください。どの手順が効いたかが分かるように、一度に一つだけ変更します。
- 入力のサイズを確認する。非常に小さいキャプチャは、3倍に拡大すると読みやすくなることが多いです。
- グレースケールに変換し、文字が際立つようにコントラストを伸ばす。
- 閾値を適用する。値を決める前にいくつか試す。
- メディアンフィルターでごま塩ノイズを取り除き、必要ならもう一度二値化する。
- テキスト領域に画像を切り抜き、背景がエンジンを惑わせないようにする。
- 文字の集合を、キャプチャが使う文字に限定する。
- テキストが散らばっている、または積み重なっている場合は、別のページ分割モードを試す。
手順と設定は、ラベル付きサンプルと一緒にバージョン管理してください。前処理のパイプラインもコードであり、コードと同じようにレビューすべきものです。
OCR か、自分で動かすモデルか
古典的な OCR は高速でノートパソコンでも動きますが、キャプチャのスタイルが変わると脆くなります。自分でラベル付けしたセットで学習させた画像モデルは、より多くのばらつきに対応できますが、データの収集と推論の実行が必要です。どちらも構築と保守はあなたの責任です。現時点でどちらも Scarnox がホストするエンドポイントではないため、どちらかに決める前にインフラを計画してください。
Scarnox がここで行うことと行わないこと
Scarnox のライブ API が解くのは PopularCaptcha のウィジェットトークンです。リクエストは POST https://api.scarnox.com/api/tasks/create で、PopularCaptcha のタスク種別、sitekey、ページの URL を送り、レスポンスとしてフォームフィールド用のトークンを受け取ります。これは画像内のテキストを読むこととは別の仕事で、Scarnox は現時点で画像からテキストへのエンドポイントを提供していません。画像キャプチャが問題であれば、OCR か自分で動かすモデルを使ってください。Scarnox がカバーする範囲は他のガイドをご覧ください。サポートされている PopularCaptcha のフローは、アカウントを作成して、クレジットカード不要の無料トライアルクレジットから始められます。現在の料金は料金ページにあります。
正当な用途
- スキャンした文書、スクリーンショット、自分のテスト画像からテキストを読み取る。
- 視覚に障害のあるユーザーが、サイトが提供する代替の手段を使えるように、キャプチャを説明または読み上げるアクセシビリティ支援ツール。
- 自分のキャプチャデザインを、自動化ツールがどれほど簡単に読めるかを確認し、より強固にするためにテストする。
自動アクセスを許可していないサイトのキャプチャを、OCR で突破しないでください。画像キャプチャは、まさにそうした行為を遅らせるために存在しています。