0Pricing
AI Agents · レッスン

スキャン文書のOCR

pytesseract経由のTesseract、画像の前処理、認識精度の向上を学びます。

「スキャン文書のOCR」はCoddyKit上の無料AI Agentsレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAI Agents学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 AI Agentsコースには全4レッスンが含まれています。

OCRが必要な場合

すべての文書がデジタルネイティブなPDFとは限りません。スキャンした文書、文字を撮影した写真、手書きのメモ、画像ベースのPDFからテキストを抽出するには、光学式文字認識(OCR)が必要です。

OCRは、テキストのピクセル画像を機械で読み取り可能な文字に変換します。主要なPythonライブラリには、pytesseract(Google Tesseract)とEasyOCR(ディープラーニング、多言語対応)があります。

pytesseractの基礎

pytesseractは、GoogleのTesseract OCRエンジンを利用するPythonラッパーです。まずTesseractをOSレベルでインストールし、その後pip install pytesseract Pillowを実行します。

import pytesseract
from PIL import Image

# Simple text extraction
image = Image.open('scanned_document.png')
text = pytesseract.image_to_string(image)
print(text)

# Specify language (default: English)
text_fr = pytesseract.image_to_string(
    Image.open('french_doc.png'),
    lang='fra'
)

# Get detailed output with bounding boxes
data = pytesseract.image_to_data(
    image,
    output_type=pytesseract.Output.DICT
)
for i, word in enumerate(data['text']):
    if word.strip():
        conf = data['conf'][i]
        print(f'Word: {word!r:20} Confidence: {conf}')

画像の前処理:グレースケール化

OCRの精度は画像品質に大きく左右されます。最初の前処理はグレースケール化です。色は文字認識に役立たないノイズを加えるだけです。

前処理にはPillowまたはOpenCVを使用します。グレースケール化によってノイズが減り、Tesseractによる文字境界の検出精度が向上します。

from PIL import Image, ImageOps
import numpy as np

def preprocess_grayscale(image_path):
    img = Image.open(image_path)

    # Convert to grayscale
    img = img.convert('L')  # 'L' = 8-bit grayscale

    # Optionally resize for better OCR (Tesseract works best at ~300 DPI)
    # Scale up small images
    width, height = img.size
    if width < 800:
        scale = 800 / width
        new_size = (int(width * scale), int(height * scale))
        img = img.resize(new_size, Image.LANCZOS)

    return img

img = preprocess_grayscale('scan.jpg')
text = pytesseract.image_to_string(img)
print(text[:300])

画像の前処理:二値化

二値化は、グレースケール画像を純粋な白黒画像に変換します。これにより、灰色の影、照明のむら、背景ノイズが除去され、OCRで文字をはっきり識別できるようになります。

from PIL import Image, ImageFilter
import numpy as np

def apply_threshold(img):
    # Method 1: Simple fixed threshold
    img_array = np.array(img)
    threshold = 128
    binary = np.where(img_array > threshold, 255, 0).astype(np.uint8)
    return Image.fromarray(binary)

def adaptive_threshold(img):
    # Method 2: Otsu's method via OpenCV (better for uneven lighting)
    try:
        import cv2
        img_array = np.array(img)
        _, binary = cv2.threshold(
            img_array, 0, 255,
            cv2.THRESH_BINARY + cv2.THRESH_OTSU
        )
        return Image.fromarray(binary)
    except ImportError:
        return apply_threshold(img)

img = preprocess_grayscale('uneven_scan.png')
img_clean = adaptive_threshold(img)
text = pytesseract.image_to_string(img_clean)
print(text[:300])

画像の前処理:傾き補正

スキャンした文書は、わずかに回転していることがよくあります。2度の傾きでもOCRの精度は大幅に低下します。傾き補正では、画像をOCRエンジンに渡す前に回転角度を検出して修正します。

import numpy as np
from PIL import Image

def deskew(img):
    try:
        import cv2
        img_array = np.array(img)

        # Find rotation angle using Hough line transform
        edges = cv2.Canny(img_array, 50, 150, apertureSize=3)
        lines = cv2.HoughLines(edges, 1, np.pi/180, threshold=100)

        if lines is None:
            return img  # no lines detected, return unchanged

        angles = []
        for line in lines:
            rho, theta = line[0]
            angle = np.degrees(theta) - 90
            if -45 < angle < 45:
                angles.append(angle)

        if not angles:
            return img

        median_angle = np.median(angles)
        if abs(median_angle) > 0.5:  # only deskew if significant tilt
            print(f'Deskewing by {median_angle:.2f} degrees')
            return img.rotate(-median_angle, expand=True, fillcolor=255)
        return img
    except ImportError:
        return img  # OpenCV not available — skip deskew

Tesseractの言語オプション

Tesseractは100以上の言語に対応しています。言語パックはOSのパッケージマネージャーでダウンロードします。多言語の文書では、+区切りで複数の言語を指定します。

import pytesseract
from PIL import Image

# List available languages
import subprocess
result = subprocess.run(['tesseract', '--list-langs'], capture_output=True, text=True)
print('Available languages:')
print(result.stdout)

# Single language
text_en = pytesseract.image_to_string(Image.open('doc.png'), lang='eng')

# Multiple languages (auto-detect best match)
text_multi = pytesseract.image_to_string(
    Image.open('doc.png'),
    lang='eng+fra+deu'  # English + French + German
)

# Tesseract config options for better accuracy
custom_config = r'--oem 3 --psm 6'  # OEM 3=LSTM, PSM 6=assume uniform block of text
text_tuned = pytesseract.image_to_string(
    Image.open('doc.png'),
    config=custom_config
)

ディープラーニングベースのEasyOCR

EasyOCRはディープラーニングモデルを使用し、劣化した画像、曲線状のテキスト、非ラテン文字の文字体系ではTesseractを上回ります。OSレベルのインストールは必要ありません。

pip install easyocrでインストールします。初回の実行時にモデルの重み(約200MB)がダウンロードされます。

import easyocr

# Initialize reader (downloads model on first run)
reader = easyocr.Reader(
    ['en', 'tr'],  # list of languages
    gpu=False       # set True if CUDA available
)

# Read text from image
results = reader.readtext('scanned_page.png')

for (bbox, text, confidence) in results:
    print(f'Text: {text!r:30} Confidence: {confidence:.2f}')
    # bbox = [[x1,y1],[x2,y2],[x3,y3],[x4,y4]] (four corners)

# Get plain text only
text_only = ' '.join(result[1] for result in results)
print('Full text:', text_only[:300])

多言語文書へのEasyOCRの利用

EasyOCRは、複数の言語が混在する文書を適切に処理できます。国際契約書、複数言語のキャプションを含む研究論文、異なる文字体系の専門用語を含む文書などに便利です。

import easyocr

# For Arabic-English mixed document
reader_ar = easyocr.Reader(['ar', 'en'], gpu=False)
results = reader_ar.readtext('arabic_contract.png')

# For CJK languages
reader_cjk = easyocr.Reader(['ch_sim', 'en'], gpu=False)  # Simplified Chinese + English
results_cjk = reader_cjk.readtext('chinese_report.png')

# Filter by confidence threshold
HIGH_CONFIDENCE = 0.7
def filter_confident_results(results, threshold=HIGH_CONFIDENCE):
    return [
        (bbox, text, conf)
        for bbox, text, conf in results
        if conf >= threshold
    ]

完全な前処理パイプライン

グレースケール化、二値化、傾き補正というすべての前処理を、1つのパイプライン関数にまとめます。前処理済みの画像にOCRを実行し、テキストと信頼度の指標の両方を返します。

import pytesseract
from PIL import Image

def ocr_pipeline(image_path, lang='eng', engine='tesseract'):
    print(f'Processing: {image_path}')

    # 1. Load
    img = Image.open(image_path)

    # 2. Preprocess
    img = img.convert('L')         # grayscale
    img = adaptive_threshold(img)  # binarize
    img = deskew(img)              # correct rotation

    # 3. OCR
    if engine == 'easyocr':
        reader = easyocr.Reader([lang], gpu=False)
        results = reader.readtext(image_path)
        text = ' '.join(r[1] for r in results if r[2] > 0.5)
    else:
        config = f'--oem 3 --psm 6 -l {lang}'
        text = pytesseract.image_to_string(img, config=config)

    # 4. Clean
    text = '\n'.join(
        line.strip() for line in text.splitlines()
        if line.strip()
    )
    return text

text = ocr_pipeline('invoice_scan.jpg')
print(text[:500])

画像ベースのPDFの処理

PDFコンテナ内にスキャンしたページを画像として格納しているPDFもあります。このような「画像PDF」を検出し、まずPyMuPDFで画像を抽出してから、ページごとにOCRを適用します。

import fitz
from PIL import Image
import io
import pytesseract

def is_image_pdf(doc):
    # Check if first page has very little extractable text
    text = doc[0].get_text().strip()
    return len(text) < 50

def ocr_pdf(filepath):
    doc = fitz.open(filepath)
    if not is_image_pdf(doc):
        # Native text — no OCR needed
        return '\n'.join(doc[i].get_text() for i in range(len(doc)))

    print('Image PDF detected — running OCR')
    all_text = []

    for page_num in range(len(doc)):
        page = doc[page_num]
        # Render page as image at 300 DPI
        mat = fitz.Matrix(300/72, 300/72)  # scale to 300 DPI
        pix = page.get_pixmap(matrix=mat)
        img = Image.open(io.BytesIO(pix.tobytes('png')))
        text = pytesseract.image_to_string(img)
        all_text.append(f'--- Page {page_num+1} ---\n{text}')

    doc.close()
    return '\n'.join(all_text)

信頼度によるフィルタリングと後処理

OCRの出力には、特に劣化した画像で誤りが含まれます。信頼度の低い単語を除外し、よくあるOCRの誤り(0とO、1とlなど)を修正し、空白を正規化してテキストを後処理します。

import re

COMMON_OCR_ERRORS = {
    r'\b0([a-z])\b': r'O\1',
    r'\bl([0-9])\b': r'1\1',
    r'\|': 'I',
    r'  +': ' ',
}

def post_process_ocr(text):
    for pattern, replacement in COMMON_OCR_ERRORS.items():
        text = re.sub(pattern, replacement, text)
    lines = [line.strip() for line in text.splitlines()]
    return '\n'.join(line for line in lines if line)

def high_confidence_ocr(words_with_conf, min_confidence=60):
    words = [w for w, conf in words_with_conf if w.strip() and conf >= min_confidence]
    return post_process_ocr(' '.join(words))

fake_ocr_output = [('0range', 90), ('|s', 40), ('l5', 85), ('good', 95)]
print(high_confidence_ocr(fake_ocr_output))

理解度チェック

OCRの前に画像に閾値処理(二値化)を適用する目的は何ですか。

復習:スキャン文書のOCR

OCRは、スキャン画像を機械で読み取り可能なテキストに変換します。pytesseractはGoogle Tesseractをラップしたもので、100以上の言語パックに対応し、高速で成熟しています。EasyOCRはディープラーニングを使用し、劣化した画像や多言語テキストをより適切に処理します。

必ず前処理としてグレースケール化を行い、二値化には大津の閾値処理を適用し、傾きを補正します。画像ベースのPDFでは、PyMuPDFでページを高DPIの画像としてレンダリングしてからOCRを実行します。信頼度の閾値で結果をフィルタリングし、ノイズを除外します。

よくある質問

「スキャン文書のOCR」レッスンは無料ですか?

はい。「スキャン文書のOCR」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、AI Agentsコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 AI Agentsコースには全4レッスンが含まれています。

「スキャン文書のOCR」で何を学びますか?

pytesseract経由のTesseract、画像の前処理、認識精度の向上を学びます。 ブラウザで直接実行するハンズオンコードでAI Agentsを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

AI Agentsを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのAI Agentsは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「スキャン文書のOCR」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このAI Agentsレッスンでコードを書いて実行できますか?

はい。すべてのAI Agentsレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. PyMuPDFとpdfplumberによるPDF解析
  2. スキャン文書のOCR
  3. 複数文書Q&Aエージェント
  4. 文書の分類とルーティング
← AI Agentsに戻る