目次を表示する

OCR技術の過去・現在・未来

OCRの起源と古典的パイプライン ── 文字を機械に読ませる100年の試み

OCRの起源と古典的パイプライン ── 文字を機械に読ませる100年の試み

この章で何ができるようになるか:OCR の歴史的発展を辿り、古典的 OCR パイプラインの各ステージ(前処理・検出・セグメンテーション・認識・後処理)が何をしているかを理解できるようになる。これにより、現代の深層学習ベース OCR が「何を置き換えたか」がわかるようになる。


黎明期 ── 「機械の目」への挑戦(1920s-1970s)

OCR の歴史は、多くの人が想像するより遥かに古い。コンピュータが存在する前から、「文字を機械に読ませる」試みは始まっていた。

最初期の発明

Emanuel Goldberg は 1920年代〜30年代にかけて、マイクロフィルム上の文字を光電セルで読み取る「Statistical Machine」を開発し、1931年に米国特許(US Patent 1,838,389)を取得した。これは文書検索を自動化するための装置で、OCR の概念的な先駆けと位置づけられる。

ほぼ同時期、オーストリアの発明家 Gustav Tauschek も 1929年に光学式文字読み取り装置の特許を取得している。テンプレートマッチング(Template Matching)の原型とも言える方式で、文字の形状をあらかじめ用意したテンプレートと照合する仕組みだった。

実用化の始まり

本格的な OCR の実用化は 1950年代に始まる。

David H. Shepard は 1950年末に「Gismo」と呼ばれる装置を開発した。当初はタイプライターで打たれた 23 種類の英字を読み取ることができ、1951年の改良版では全 26 種類の英字に対応した最初期の実用的文字読み取り機だ。Shepard はその後 Intelligent Machines Research(IMR)社を設立し、OCR の商用化に乗り出した。

Gismo(1951)の仕組み(概念):
  1. 紙面に光を当てる
  2. 反射光を光電セルで検出
  3. 各文字位置の明暗パターンを取得
  4. あらかじめ登録されたパターンと照合
  5. 最も一致するパターンの文字を出力

制約:
  - 特定のタイプフェイスのみ対応
  - 文字間隔が均一であることが前提
  - 紙面の汚れ・傾きに弱い

産業への導入

1956年、アメリカ銀行協会(ABA) に小切手処理の自動化のための MICR(Magnetic Ink Character Recognition:磁気インク文字認識) 技術が提示され、1958年にE-13B書体が標準規格として正式に採用された。小切手の下部に磁気インクで印刷された特殊フォント(E-13B)を磁気ヘッドで読み取る方式だ。

MICR の特徴:
  ✅ 光学式より信頼性が高い(磁気信号は汚れに強い)
  ✅ 高速処理が可能(毎分数百枚)
  ❌ 専用フォント・専用インクが必要
  ❌ 汎用的な文字認識ではない

MICR は厳密には「OCR」とは異なる(光学式ではなく磁気式)が、「機械による文字自動読み取り」という点で OCR の歴史と深く関わっている。2026年現在でも、世界中の小切手処理で MICR は現役だ。

1965年には米国郵便公社(USPS) が郵便番号の自動読み取りに OCR を導入した。これは OCR の大規模産業利用の先駆けとなった。

黎明期の限界

1970年代以前の OCR の制約:
  1. 対応フォントが限定的(特定のタイプフェイスのみ)
  2. 文字の配置が厳密に規定されている必要がある
  3. 紙面の品質に強く依存(汚れ・傾き・シワに弱い)
  4. ハードウェアに束縛(専用装置が必要で高価)
  5. 手書き文字はほぼ認識不可能

これらの限界を突破するために、次の時代——テンプレートマッチングと特徴抽出の時代が始まる。


テンプレートマッチングと特徴抽出の時代(1970s-1990s)

1970年代以降、コンピュータの性能向上と画像処理技術の発展により、OCR は「専用ハードウェア」から「ソフトウェア」の世界へ移行していった。

テンプレートマッチング(Template Matching)

最もシンプルな文字認識手法。画像中の文字領域を、あらかじめ用意した文字テンプレート(グリフ)とピクセル単位で比較する。

テンプレートマッチングの処理:

1. 入力画像の文字領域を正規化(サイズ・位置を統一)
2. 全てのテンプレート(A, B, C, ... Z, 0, 1, ... 9)と比較
3. 類似度が最も高いテンプレートの文字を出力

類似度の計算(単純な例):
  similarity = 一致するピクセル数 / 全ピクセル数

  入力画像:          テンプレート "A":    テンプレート "B":
    ....##....         ....##....         .#####....
    ...#..#...         ...#..#...         .#...#....
    ..######..         ..######..         .#####....
    .#......#.         .#......#.         .#...#....
    .#......#.         .#......#.         .#####....

  similarity("A") = 0.95   ← 最高一致 → "A" と認識
  similarity("B") = 0.42
❌ テンプレートマッチングの限界:
  - フォントが変わると認識できない(テンプレートと一致しない)
  - 文字サイズ・傾き・太さの変化に弱い
  - テンプレート数 × ピクセル比較のため計算コストが高い
  - 手書き文字は個人差が大きすぎてテンプレート化できない

特徴抽出(Feature Extraction)

テンプレートマッチングの限界を克服するために登場したのが、特徴抽出ベースのアプローチだ。ピクセルを直接比較するのではなく、文字を構造的な特徴に分解して認識する。

特徴抽出の例 ── 文字 "A" の構造的特徴:

  1. 上部に頂点がある(△の頂点)
  2. 左右に下向きの斜めストロークがある
  3. 中央に水平のクロスバーがある
  4. 閉じたループが1つある(△の内側)
  5. 下部は開いている

これらの特徴は、フォントが変わっても "A" に共通する
→ フォント非依存の認識が可能

Kurzweil の全書体 OCR(1974)

Ray Kurzweil は 1974年に、特定のフォントに依存しない全書体対応 OCR(omni-font OCR)を開発した。複数の書体にまたがって約 98% の認識精度を達成し、OCR の実用性を大きく前進させた。

Kurzweil の OCR は当初、視覚障害者向けの読み上げ装置として設計された。印刷物をスキャンし、OCR でテキスト化した後、音声合成(Speech Synthesis)で読み上げる——現在のアクセシビリティ技術の先駆けだ。

商用 OCR の普及(1980s-1990s)

1980年代〜1990年代にかけて、パーソナルコンピュータの普及とともに商用 OCR ソフトウェアが登場した。

主要な商用 OCR:
  - OmniPage(Caere 社、1988年〜): PC 向け OCR の草分け
  - ABBYY FineReader(1993年〜): 高精度 OCR。多言語対応が強み
  - Tesseract(HP Labs、1985年〜1994年開発):
    → HP が社内で開発。当時は非公開
    → 2005年にオープンソース化(Google が支援)
    → 2026年現在も広く使われている OSS OCR エンジン

古典的 OCR パイプライン ── 6つのステージ

1990年代〜2000年代に確立された古典的 OCR パイプラインは、以下の6段階で構成される。

graph LR
    A[入力画像] --> B[前処理<br/>Preprocessing]
    B --> C[テキスト検出<br/>Text Detection]
    C --> D[行セグメンテーション<br/>Line Segmentation]
    D --> E[文字セグメンテーション<br/>Character Segmentation]
    E --> F[文字認識<br/>Recognition]
    F --> G[後処理<br/>Post-processing]
    G --> H[出力テキスト]

    style B fill:#e8f4fd,stroke:#1e88e5
    style C fill:#e8f4fd,stroke:#1e88e5
    style D fill:#e8f4fd,stroke:#1e88e5
    style E fill:#e8f4fd,stroke:#1e88e5
    style F fill:#e8f4fd,stroke:#1e88e5
    style G fill:#e8f4fd,stroke:#1e88e5

各ステージを順に見ていこう。

ステージ1:前処理(Preprocessing)

生の入力画像を文字認識に適した状態に変換する。このステージの品質が最終的な認識精度を大きく左右する。

二値化(Binarization)

カラー/グレースケール画像を白黒2値に変換する。文字(前景)と背景を分離するための最も基本的な処理だ。

import cv2
import numpy as np

# グレースケール変換
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# --- 大津の方法(Otsu's Method)---
# 画像全体のヒストグラムから最適な閾値を自動決定
# 均一な照明条件で有効
threshold, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

# --- 適応的二値化(Adaptive Thresholding)---
# 局所領域ごとに閾値を計算
# 照明ムラがある画像で有効(Sauvola 法の近似)
adaptive_binary = cv2.adaptiveThreshold(
    gray, 255,
    cv2.ADAPTIVE_THRESH_GAUSSIAN_C,  # 近傍ピクセルのガウシアン加重平均
    cv2.THRESH_BINARY,
    blockSize=11,  # 近傍領域のサイズ
    C=2            # 閾値からの定数オフセット
)
二値化手法の使い分け:

✅ 大津の方法(Otsu's Method):
  - 照明が均一なスキャン画像に適する
  - 高速(画像全体で1つの閾値)
  ❌ 影や照明ムラがあると失敗する

✅ 適応的二値化(Niblack / Sauvola):
  - 照明ムラ・影のある画像に強い
  - 局所領域ごとに閾値を計算
  ❌ パラメータ調整が必要(ウィンドウサイズ、定数)

傾き補正(Deskewing)

スキャン時の傾きを検出・補正する。ハフ変換(Hough Transform) でテキスト行の角度を推定し、逆回転させる。

# ハフ変換で直線(テキスト行)を検出
lines = cv2.HoughLinesP(
    binary, 1, np.pi / 180,
    threshold=100,      # 直線として検出する最小投票数
    minLineLength=100,  # 最小の線分長
    maxLineGap=10       # 線分間の最大ギャップ
)

# 検出された直線群の角度の中央値を傾き角度とする
angles = [np.arctan2(y2 - y1, x2 - x1) for x1, y1, x2, y2 in lines[:, 0]]
median_angle = np.median(angles) * 180 / np.pi

# 逆回転で傾きを補正
(h, w) = binary.shape
center = (w // 2, h // 2)
rotation_matrix = cv2.getRotationMatrix2D(center, median_angle, 1.0)
deskewed = cv2.warpAffine(binary, rotation_matrix, (w, h), borderValue=255)

ノイズ除去(Noise Removal)

スキャンのゴミ、紙の質感、圧縮ノイズなどを除去する。メディアンフィルタやモルフォロジー演算が使われる。


ステージ2:テキスト検出(Text Detection)

画像のどこにテキスト領域があるかを特定する。

連結成分分析(Connected Component Analysis) は、二値画像上で連結した黒ピクセルの塊を一つの「成分」として抽出する手法だ。各成分のサイズ・アスペクト比・密度から、テキストかどうかを判定する。

MSER(Maximally Stable Extremal Regions) は、閾値を連続的に変化させたときに面積が安定している領域を抽出する。文字は背景とのコントラストが安定しているため、MSER で検出できる。自然画像中のテキスト検出(シーンテキスト検出)で広く使われた。


ステージ3:行セグメンテーション(Line Segmentation)

テキスト領域を行単位に分割する。水平射影プロファイル(Horizontal Projection Profile) が代表的な手法だ。

水平射影プロファイルの仕組み:

二値画像の各行(水平ライン)の黒ピクセル数を集計する

画像:                           射影プロファイル:
  Hello World                     ████████████  ← テキスト行
  (空白行)                       ─            ← 谷(行間)
  This is OCR                     ██████████    ← テキスト行
  (空白行)                       ─            ← 谷(行間)
  Technology                      ████████      ← テキスト行

→ 射影プロファイルの「谷」(黒ピクセル数が0またはごく少ない行)で行を分割
# 水平射影プロファイル
horizontal_profile = np.sum(binary == 0, axis=1)  # 各行の黒ピクセル数

# 谷(行間)を検出して行を分割
threshold = np.max(horizontal_profile) * 0.1
is_text_row = horizontal_profile > threshold

# 連続するテキスト行をグルーピング → 各グループが1行

ステージ4:文字セグメンテーション(Character Segmentation)

行を個々の文字に分割する。水平射影の垂直版——垂直射影プロファイル(Vertical Projection Profile) を使う。

垂直射影プロファイル:

テキスト行画像:   H e l l o
                  ↕ ↕ ↕ ↕ ↕
垂直射影:        █ █ █ █ █   (各列の黒ピクセル数)
                   ↑ ↑ ↑ ↑
                   谷 谷 谷 谷  (文字間のギャップ)

→ 谷の位置で文字を分割
❌ 文字セグメンテーションが難しいケース:
  - リガチャ(合字): "fi", "fl" が結合している
  - カーニング: 文字間隔が不均一
  - 手書き文字: 文字が繋がっている(筆記体など)
  - 日本語: 漢字の画数が多く、部首単位で分割されてしまう
  - アラビア語: 右から左、かつ文字が連結する

→ 文字セグメンテーションの困難さが、後に「セグメンテーションフリー」な
  深層学習アプローチ(CTC, Attention)を生むことになる

ステージ5:文字認識(Recognition)

セグメンテーションされた個々の文字画像を、文字コードにマッピングする。

認識手法の進化:

1. テンプレートマッチング(1970s〜)
   → ピクセル直接比較。フォント依存。精度に限界

2. 特徴抽出 + ルールベース(1980s〜)
   → ストローク・ループ・交差点などの構造特徴を手動設計
   → ルールベースで分類

3. HOG + SVM(2000s〜)
   → HOG(Histogram of Oriented Gradients)で勾配方向ヒストグラムを特徴量化
   → SVM(Support Vector Machine)で分類
   → 手動特徴設計の最終形態
# HOG 特徴量の計算例(scikit-image)
from skimage.feature import hog
from sklearn.svm import SVC

# 文字画像からHOG特徴量を抽出
# orientations: 勾配方向のビン数
# pixels_per_cell: セルサイズ(特徴量の粒度)
features = hog(
    char_image,
    orientations=9,
    pixels_per_cell=(8, 8),
    cells_per_block=(2, 2),
    visualize=False
)

# SVM で分類
# 学習済みモデルで文字クラスを予測
predicted_char = svm_model.predict([features])[0]

ステージ6:後処理(Post-processing)

認識結果のエラーを修正し、最終的なテキストを出力する。

後処理の手法:

1. 辞書照合(Dictionary Lookup)
   認識結果: "recogmition" → 辞書にない
   候補: "recognition"(編集距離1)→ 修正

2. N-gram 言語モデル
   文字/単語の出現確率を統計的に評価
   P("th") > P("tx") → "tx" は "th" に修正される可能性が高い

3. 正規表現ベースの構造チェック
   日付: "\d{4}-\d{2}-\d{2}" のパターンに合致しなければ修正
   郵便番号: "\d{3}-\d{4}" のパターンチェック

古典的パイプラインの限界 ── 次の時代への橋渡し

古典的 OCR パイプラインは、整った印刷文書に対しては高い精度を達成した。しかし以下の場面では根本的な限界があった。

graph TD
    A[古典的 OCR の限界] --> B[手書き文字]
    A --> C[劣化した文書]
    A --> D[複雑なレイアウト]
    A --> E[非ラテン文字]
    A --> F[手動特徴設計]

    B --> B1[個人差が大きすぎて<br/>テンプレート化できない]
    C --> C1[ノイズ・かすれ・裏写りで<br/>二値化が破綻する]
    D --> D1[表・図・多段組みで<br/>射影プロファイルが機能しない]
    E --> E1[漢字数千字・アラビア語の連結など<br/>ラテン文字前提の設計が通用しない]
    F --> F1[特徴量を人手で設計する必要があり<br/>スケールしない]

    style A fill:#ffebee,stroke:#c62828
    style B1 fill:#fff3e0,stroke:#e65100
    style C1 fill:#fff3e0,stroke:#e65100
    style D1 fill:#fff3e0,stroke:#e65100
    style E1 fill:#fff3e0,stroke:#e65100
    style F1 fill:#fff3e0,stroke:#e65100
具体的な精度の壁(2000年代の目安):

✅ 高精度が出るケース(認識率 95%以上):
  - 高品質スキャンの英語印刷文書
  - 固定フォーマットの帳票
  - MICR のような専用フォント

❌ 精度が大きく落ちるケース(認識率 70%以下も):
  - 手書き文字(特に走り書き)
  - FAX で送られた文書(低解像度 + ノイズ)
  - 自然画像中のテキスト(看板・メニュー等)
  - 複数言語が混在する文書

最も根本的な問題は 「特徴量を人手で設計する」 というアプローチの限界だ。HOG や構造特徴は人間が「文字を識別するために重要だ」と判断した特徴であり、人間が思いつかない特徴は使えない。

2012年、AlexNet が ImageNet コンペティションで圧勝し、「特徴量は学習で獲得する」という深層学習のパラダイムが画像認識を席巻した。OCR もこの波に乗る。次章では、CNN と RNN が OCR にもたらした革命を見ていく。


まとめ

  • OCR の歴史は1920年代に始まる。Goldberg の Statistical Machine、Tauschek の光学読取装置が先駆け
  • 1950年代に実用化が始まり、Shepard の Gismo、銀行の MICR、郵便番号読み取りへと展開した
  • 1974年の Kurzweil の全書体 OCR が、特定フォントに依存しない認識を実現し、商用化への道を開いた
  • 古典的 OCR パイプラインは「前処理 → 検出 → 行セグメンテーション → 文字セグメンテーション → 認識 → 後処理」の6段階で構成される
  • 前処理(二値化・傾き補正・ノイズ除去)の品質が最終精度を大きく左右する
  • テンプレートマッチング → 特徴抽出 → HOG+SVM と認識手法は進化したが、いずれも手動の特徴設計に依存していた
  • 手書き文字、劣化文書、複雑なレイアウト、非ラテン文字への対応が根本的な限界であり、深層学習による特徴の自動学習がこの壁を打ち破ることになる