プログラミング / 言語 / Python

画像から文字列を抽出する
— OCR 入門(Tesseract + pytesseract)

1. OCR の仕組みとツールの全体像

OCR(Optical Character Recognition)とは、画像に含まれるテキストをコンピュータが読み取れる文字列に変換する技術です。Python では Tesseract OCR(Google 開発のオープンソースエンジン)と、それを Python から呼び出すラッパーライブラリ pytesseract の組み合わせが最もポピュラーです。

📷 画像ファイル
Pillow で読み込み
pytesseract
Tesseract OCR エンジン
📄 テキスト
ライブラリ役割備考
TesseractOCR エンジン本体(外部バイナリ)OS にインストールが必要
pytesseractPython → Tesseract のブリッジpip でインストール
Pillow (PIL)画像の読み込み・前処理pip でインストール
OpenCV高度な前処理(PART 05 で解説)pip でインストール
このパートのゴール: Tesseract と pytesseract をインストールし、画像から英語・日本語テキストを抽出できるようにする。さらに文字の位置情報(bounding box)も取得する。

2. Tesseract のインストール

pytesseract は Tesseract バイナリを外部コマンドとして呼び出します。そのため、まず OS に Tesseract 本体をインストールする必要があります。

Windows — インストーラー方式

UB Mannheim が配布している公式インストーラーを使います。

  1. UB-Mannheim の GitHub Wiki からインストーラーをダウンロード(tesseract-ocr-w64-setup-*.exe
  2. インストール時に「Additional language data」→「Japanese」にチェックを入れる(日本語を使う場合)
  3. デフォルトインストール先:C:\Program Files\Tesseract-OCR\

インストール後、環境変数 PATH に追加するか、Python コード内でパスを直接指定します:

Python
import pytesseract

# Windows の場合は tesseract.exe のパスを明示的に指定
pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'

動作確認(コマンドプロンプト):

cmd
tesseract --version
出力例
tesseract 5.3.x libgif 5.2.1 : libjpeg 9e : libpng 1.6.39 : libtiff 4.5.0 ...

macOS — Homebrew 方式

bash
# Tesseract 本体をインストール
brew install tesseract

# 日本語言語データを追加でインストール
brew install tesseract-lang

動作確認:

bash
tesseract --version
# インストール済み言語の確認
tesseract --list-langs
出力例
tesseract 5.3.x ... List of available languages (3): eng jpn osd
macOS では PATH は自動で設定されるため、Python コード内でのパス指定は通常不要です。

Linux (Ubuntu/Debian)

bash
# Tesseract 本体をインストール
sudo apt-get update
sudo apt-get install -y tesseract-ocr

# 日本語言語データをインストール
sudo apt-get install -y tesseract-ocr-jpn

# インストール済み言語の確認
tesseract --list-langs
CentOS / RHEL 系:sudo yum install tesseract、日本語データは tesseract-langpack-jpn パッケージです。

3. pytesseract / Pillow のインストール

Tesseract のインストールが済んだら、Python ライブラリをインストールします。

bash
# pytesseract:Tesseract の Python ラッパー
pip install pytesseract

# Pillow:画像の読み込み・操作ライブラリ
pip install Pillow

インストール確認:

Python
import pytesseract
from PIL import Image

print(pytesseract.get_tesseract_version())  # Tesseract のバージョン確認
注意: Tesseract 本体のインストールを忘れると TesseractNotFoundError が発生します。pytesseract は Python ライブラリ、Tesseract は OS レベルのバイナリの2つがセットで必要です。

4. 基本的な文字列抽出

Pillow で画像を読み込み、pytesseract.image_to_string() を呼ぶだけで文字列を取得できます。

Python
import pytesseract
from PIL import Image

# Windows の場合はパスを指定(不要なら削除)
# pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'

# 画像を開く
img = Image.open("sample.png")

# OCR でテキストを抽出(デフォルトは英語)
text = pytesseract.image_to_string(img)

print(text)
print("---")
print(f"文字数: {len(text)}")
出力例(英語画像の場合)
Hello, World! This is a sample image for OCR. --- 文字数: 43

ファイルパスを直接渡す方法

Pillow を経由せず、ファイルパスを文字列で渡すこともできます。

Python
import pytesseract

# ファイルパスを直接渡す
text = pytesseract.image_to_string("sample.png")
print(text)

対応している画像形式

PNG・JPEG・TIFF・BMP・GIF などの一般的な形式に対応しています。OCR の精度面では PNG(可逆圧縮) が最も安定しています。JPEG は圧縮ノイズが認識精度を落とすことがあるため、可能であれば PNG に変換してから OCR にかけることをお勧めします。

5. 日本語テキストの認識

デフォルトの認識言語は英語(eng)です。日本語を認識するには lang パラメータを指定します。

Python
import pytesseract
from PIL import Image

img = Image.open("japanese_sample.png")

# lang='jpn' で日本語モデルを使用
text = pytesseract.image_to_string(img, lang='jpn')
print(text)

# 英語と日本語を混在させる場合(+ で区切る)
text_mixed = pytesseract.image_to_string(img, lang='jpn+eng')
print(text_mixed)
日本語認識の注意点:
日本語の精度は英語に比べて低い傾向があります。特にフォントサイズが小さい・手書き・低解像度の画像では誤認識が増えます。PART 05 では画像の前処理(二値化・拡大・ノイズ除去)で精度を向上させる手法を解説します。

利用可能な言語を確認する

Python
import pytesseract

# インストール済み言語データの一覧を取得
langs = pytesseract.get_languages()
print(langs)
# 例: ['eng', 'jpn', 'osd']

jpn が含まれていない場合は、OS に日本語言語データが入っていません。セクション 2 の手順でインストールしてください。

6. 出力フォーマットと詳細データ

pytesseract は文字列以外にも、信頼度スコアや座標を含む詳細なデータを取得できます。

メソッド戻り値の型用途
image_to_string()strシンプルにテキストだけ欲しい場合
image_to_data()str(TSV)/ DataFrame信頼度・座標も含むフル情報
image_to_boxes()str文字ごとの bounding box(旧形式)
image_to_osd()str画像の向き・スクリプト検出
image_to_pdf_or_hocr()bytesPDF / hOCR 形式で出力

image_to_data() — 詳細データの取得

Python
import pytesseract
from PIL import Image
import pandas as pd

img = Image.open("sample.png")

# TSV 形式で取得
tsv_text = pytesseract.image_to_data(img)
print(tsv_text)

# pandas DataFrame として取得
df = pytesseract.image_to_data(img, output_type=pytesseract.Output.DATAFRAME)
print(df.columns.tolist())
# ['level', 'page_num', 'block_num', 'par_num', 'line_num', 'word_num',
#  'left', 'top', 'width', 'height', 'conf', 'text']

# 信頼度が 60 以上の単語だけ抽出
reliable = df[df['conf'] > 60][['text', 'conf', 'left', 'top', 'width', 'height']]
print(reliable.to_string())
DataFrame の主要カラム
level : 認識レベル(1=page 2=block 3=paragraph 4=line 5=word) page_num : ページ番号 left, top : 左上座標(px) width, height : サイズ(px) conf : 信頼度スコア(0〜100、-1 は非テキスト) text : 認識テキスト
Tip: conf(信頼度スコア)が低い単語は誤認識の可能性が高いです。閾値を設けてフィルタリングするだけで、出力品質が大幅に向上します。

7. Bounding Box — 文字位置の取得

認識されたテキストが画像のどの位置にあるかを取得し、矩形を描画する方法を紹介します。

Python
import pytesseract
from PIL import Image, ImageDraw
import pandas as pd

img = Image.open("sample.png")
draw = ImageDraw.Draw(img)

# image_to_data で単語ごとの座標を取得
df = pytesseract.image_to_data(
    img,
    output_type=pytesseract.Output.DATAFRAME,
    lang='eng'
)

# 信頼度が 60 以上の単語に矩形を描画
for _, row in df.iterrows():
    if row['conf'] > 60 and isinstance(row['text'], str) and row['text'].strip():
        x, y, w, h = int(row['left']), int(row['top']), int(row['width']), int(row['height'])
        draw.rectangle([x, y, x + w, y + h], outline='red', width=2)
        # テキストラベルを描画(任意)
        draw.text((x, y - 12), row['text'], fill='red')

# 結果を保存
img.save("output_bbox.png")
print("output_bbox.png に保存しました")

単語レベルの bounding box — image_to_boxes()

image_to_boxes() は文字(1文字)単位で bounding box を返す旧来のメソッドです。座標系は 左下原点 であることに注意してください。

Python
import pytesseract
from PIL import Image, ImageDraw

img = Image.open("sample.png")
h_img = img.height  # 座標変換用に高さを保持

# 文字単位の bounding box を取得
boxes_str = pytesseract.image_to_boxes(img, lang='eng')

draw = ImageDraw.Draw(img)
for line in boxes_str.splitlines():
    parts = line.split()
    if len(parts) < 6:
        continue
    char = parts[0]
    x1, y1, x2, y2 = int(parts[1]), int(parts[2]), int(parts[3]), int(parts[4])
    # image_to_boxes は左下原点 → Pillow (左上原点) に変換
    y1_pil = h_img - y2
    y2_pil = h_img - y1
    draw.rectangle([x1, y1_pil, x2, y2_pil], outline='blue', width=1)

img.save("output_char_bbox.png")
print("output_char_bbox.png に保存しました")
使い分けのポイント:
単語・行レベルで処理したい場合は image_to_data()、1 文字単位で詳細に処理したい場合は image_to_boxes() を使います。通常は image_to_data() のほうが扱いやすいです。

8. 主要な設定オプション

config パラメータに Tesseract のコマンドラインオプションを文字列で渡すことで、認識モードを細かく制御できます。

Python
import pytesseract
from PIL import Image

img = Image.open("sample.png")

# PSM (Page Segmentation Mode) の指定例
# --psm 6 : 単一ブロックのテキストとして処理(デフォルトは 3)
text = pytesseract.image_to_string(img, config='--psm 6')
print(text)

# OEM (OCR Engine Mode) の指定
# --oem 3 : デフォルト(LSTM + Legacy の両方を使用)
# --oem 1 : LSTM のみ使用(Tesseract 4 以降で推奨)
text2 = pytesseract.image_to_string(img, config='--oem 1 --psm 6')
print(text2)

# 数字だけを認識させる
text_num = pytesseract.image_to_string(img, config='--psm 6 -c tessedit_char_whitelist=0123456789')
print(text_num)
PSM 値説明適した画像
--psm 3自動でページ分割(デフォルト)通常の文書画像
--psm 6単一の均一なテキストブロック段落・ブロック単位の画像
--psm 71行のテキストラベル・バナー
--psm 81単語ボタン・タグ
--psm 101文字1文字の認識
--psm 11テキストとして扱える箇所をすべて散在したテキスト
--psm 131行(OSD なし)シンプルな1行テキスト
Tip: 認識対象の画像に合った --psm を選ぶことが精度向上の第一歩です。迷ったらまず --psm 6 を試してみてください。

9. まとめ

Python — 基本パターンのまとめ
import pytesseract
from PIL import Image
import pandas as pd

# Windows の場合
# pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'

def ocr_image(image_path: str, lang: str = 'eng', psm: int = 3) -> str:
    """画像からテキストを抽出する基本関数"""
    img = Image.open(image_path)
    config = f'--psm {psm}'
    return pytesseract.image_to_string(img, lang=lang, config=config).strip()


def ocr_image_with_confidence(image_path: str, lang: str = 'eng',
                               min_conf: int = 60) -> list[dict]:
    """信頼度付きで単語リストを返す"""
    img = Image.open(image_path)
    df = pytesseract.image_to_data(img, lang=lang,
                                   output_type=pytesseract.Output.DATAFRAME)
    results = []
    for _, row in df.iterrows():
        if row['conf'] >= min_conf and isinstance(row['text'], str) and row['text'].strip():
            results.append({
                'text': row['text'],
                'conf': row['conf'],
                'box': (int(row['left']), int(row['top']),
                        int(row['width']), int(row['height']))
            })
    return results


# 使用例
if __name__ == '__main__':
    # 英語テキストの抽出
    text = ocr_image('sample.png', lang='eng', psm=6)
    print("=== 抽出テキスト ===")
    print(text)

    # 日本語テキストの抽出
    text_ja = ocr_image('japanese_sample.png', lang='jpn', psm=6)
    print("\n=== 日本語テキスト ===")
    print(text_ja)

    # 信頼度付き単語リスト
    words = ocr_image_with_confidence('sample.png', min_conf=70)
    print(f"\n=== 信頼度 70 以上の単語: {len(words)} 個 ===")
    for w in words:
        print(f"  '{w['text']}' (conf={w['conf']}, box={w['box']})")
やりたいことメソッドlang 指定
テキストだけ取り出すimage_to_string()lang='eng' or 'jpn'
信頼度・座標も取得image_to_data()同上
文字単位の座標image_to_boxes()同上
認識モードを変えるconfig='--psm N'組み合わせて使用

次のパートでは、認識精度をさらに高めるための 画像前処理(グレースケール・二値化・ノイズ除去・解像度調整)と、Tesseract の代替として注目されている EasyOCR を紹介します。