YomiTokuによる印刷・手書き文字認識

目次
概要
主要技術: YomiToku文書画像解析
出典: Kinoshita, K. (2024). YomiToku: AI-powered document image analysis package for Japanese language [Computer software]. GitHub. https://github.com/kotaro-kinoshita/yomitoku
技術特徴: 4つのAIモデル(文字位置検知、文字列認識、レイアウト解析、表構造認識)を備えた日本語文書解析システムである。7000文字超の日本語文字対応、縦書き・横書き混在文書、複雑な表構造(rowspan×colspan:表のセル結合機能)の解析が可能である。リアルタイム処理により、Webカメラで撮影した文書を構造化データとして抽出できる。
応用例: 文書デジタル化、会議議事録自動作成、帳票データ入力自動化、手書き記入読み取り
学習目標: 従来型のOCR(光学文字認識)では困難な複雑な日本語文書の構造理解を体験.AI解析技術の性能特性を理解する。
Python開発環境,ライブラリ類
ここでは、最低限の事前準備について説明する。機械学習や深層学習を行う場合は、NVIDIA CUDA、Visual Studio、Cursorなどを追加でインストールすると便利である。これらについては別ページ https://www.kkaneko.jp/cc/dev/aiassist.htmlで詳しく解説しているので、必要に応じて参照してください。
Python 3.12 のインストール
インストール済みの場合は実行不要。
管理者権限でコマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行する。管理者権限は、wingetの--scope machineオプションでシステム全体にソフトウェアをインストールするために必要である。
REM Python をシステム領域にインストール
winget install --scope machine --id Python.Python.3.12 -e --silent
REM Python のパス設定
set "PYTHON_PATH=C:\Program Files\Python312"
set "PYTHON_SCRIPTS_PATH=C:\Program Files\Python312\Scripts"
echo "%PATH%" | find /i "%PYTHON_PATH%" >nul
if errorlevel 1 setx PATH "%PATH%;%PYTHON_PATH%" /M >nul
echo "%PATH%" | find /i "%PYTHON_SCRIPTS_PATH%" >nul
if errorlevel 1 setx PATH "%PATH%;%PYTHON_SCRIPTS_PATH%" /M >nul
【関連する外部ページ】
Python の公式ページ: https://www.python.org/
AI エディタ Windsurf のインストール
Pythonプログラムの編集・実行には、AI エディタの利用を推奨する。ここでは,Windsurfのインストールを説明する。
管理者権限でコマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行して、Windsurfをシステム全体にインストールする。管理者権限は、wingetの--scope machineオプションでシステム全体にソフトウェアをインストールするために必要となる。
winget install --scope machine Codeium.Windsurf -e --silent
【関連する外部ページ】
Windsurf の公式ページ: https://windsurf.com/
必要なライブラリのインストール
コマンドプロンプトを管理者として実行(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行する。
pip install -U torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126
pip install yomitoku opencv-python pillow numpy
YomiTokuによる文字認識プログラム
概要
このプログラムは、カメラやビデオから取得した画像内の日本語テキストを認識する。YomiTokuライブラリを使用して、画像内の文字位置を検出し、検出された領域から文字を認識する処理を行う。
主要技術
- 文字検出(Text Detection)
画像内のテキストが存在する領域を特定する技術である。YomiTokuではディープラーニングベースの物体検出手法を応用し、文字領域を矩形で囲む処理を行う[1]。
- 文字認識(Text Recognition/OCR)
検出された文字領域から実際の文字内容を認識する技術である。YomiTokuは7000文字を超える日本語文字(ひらがな、カタカナ、漢字)の認識に対応しており、手書き文字と活字の両方を単一モデルで処理できる[2]。
プログラムは、DocumentAnalyzerクラスを通じてこれらの技術を統合的に実行し、結果をDocumentAnalyzerSchemaオブジェクトとして返す。このオブジェクトにはparagraphs(段落)やwords(単語)といった階層的な構造でテキスト情報が格納される。
参考文献
[1] Kinoshita, K. (2024). YomiToku: Japanese Document Intelligence. GitHub repository. https://github.com/kotaro-kinoshita/yomitoku
[2] Kinoshita, K. (2024). YomiToku v0.8.0 Model Card. Hugging Face. https://huggingface.co/yomitoku/yomitoku-v0.8.0
# YomiTokuによる文字認識プログラム
# 特徴技術名: 文字認識(Text Recognition)
# 出典: GitHub: https://github.com/kotaro-kinoshita/yomitoku
# 特徴機能: 7000文字超の日本語文字認識(ひらがな、カタカナ、漢字)による高精度な文字認識
# 学習済みモデル: YomiToku v0.8.0 - 手書き文字認識対応の統合モデル。活字・手書き文字の両方を単一モデルで認識可能。Hugging Face Hubから自動ダウンロード
# 方式設計:
# 関連利用技術: 文字位置検知(Text Detection)、レイアウト解析(Layout Analysis)、表構造認識(Table Structure Recognition)、OpenCV(カメラ入力)、PIL(日本語テキスト描画)
# 入力と出力: 入力: 動画(ユーザは「0:動画ファイル,1:カメラ,2:サンプル動画」のメニューで選択.0:動画ファイルの場合はtkinterでファイル選択.1の場合はOpenCVでカメラが開く.2の場合はhttps://github.com/opencv/opencv/blob/master/samples/data/vtest.aviを使用)、出力: OpenCV画面でリアルタイムに認識結果を表示.1秒間隔でprint()で処理結果を表示.プログラム終了時にprint()で表示した処理結果をresult.txtファイルに保存
# 処理手順: 1.カメラ/動画フレーム取得、2.DocumentAnalyzerによる統合解析、3.文字認識結果の抽出、4.レイアウト解析結果の取得、5.表構造の認識、6.結果の画面表示とコンソール出力
# 前処理、後処理: 前処理: BGR→RGB変換(YomiTokuはRGB形式を期待)、後処理: 日本語フォントによる認識結果の画面描画
# 追加処理: バッファサイズを1に設定してリアルタイム性を確保、認識結果を最大10ブロックに制限して画面の視認性を維持
# 調整を必要とする設定値: FONT_PATH(日本語フォントのパス、環境により要調整)、FONT_SIZE(文字サイズ、画面解像度により調整が必要)
# 将来方策: FONT_SIZE(文字サイズ)の自動調整機能。画面解像度とフレームサイズから最適な文字サイズを自動計算し、視認性を最適化する機能をプログラム内で実装可能
# その他の重要事項: VRAM 8GB以上推奨、CUDA 11.8以上必要、低解像度画像では精度低下(短辺720px以上推奨)
# 前準備:
# pip install -U torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126
# pip install yomitoku opencv-python pillow numpy
import cv2
import tkinter as tk
from tkinter import filedialog
import os
import numpy as np
from PIL import Image, ImageDraw, ImageFont
from yomitoku import DocumentAnalyzer
import sys
import io
import torch
import logging
import time
import urllib.request
# ログレベル設定(YomiTokuのログを抑制)
logging.getLogger('yomitoku').setLevel(logging.WARNING)
logging.getLogger('yomitoku.base').setLevel(logging.WARNING)
# フォント設定
FONT_PATH = 'C:/Windows/Fonts/msgothic.ttc' # 日本語フォントパス(環境により要調整)
FONT_SIZE = 30 # 表示文字サイズ(画面解像度により要調整)
TEXT_COLOR_RGB = (0, 255, 0) # RGB形式での緑色
# 表示設定
WINDOW_NAME = 'Video' # OpenCVウィンドウ名
TEXT_START_Y = 30 # テキスト表示開始Y座標
TEXT_LINE_HEIGHT = 40 # テキスト行間隔
OUTPUT_INTERVAL = 1.0 # コンソール出力間隔(秒)
MAX_DISPLAY_TEXTS = 10 # 最大表示テキスト数
# ファイル設定
RESULT_FILE = 'result.txt' # 結果保存ファイル名
SAMPLE_VIDEO_URL = 'https://github.com/opencv/opencv/raw/master/samples/data/vtest.avi'
SAMPLE_VIDEO_FILE = 'vtest.avi'
# カメラ設定
CAMERA_INDEX = 0 # カメラデバイス番号
BUFFER_SIZE = 1 # カメラバッファサイズ
# Windows文字エンコーディング設定
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', line_buffering=True)
# グローバル変数
device = 'cuda' if torch.cuda.is_available() else 'cpu'
analyzer = DocumentAnalyzer(device=device)
font = ImageFont.truetype(FONT_PATH, FONT_SIZE)
all_results = []
last_print_time = time.time()
first_run = True
def video_processing(frame):
global analyzer, font, all_results, last_print_time, first_run
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# YomiTokuによる解析
try:
result = analyzer(rgb_frame)
except Exception as e:
print(f'解析エラー: {e}')
return frame
# 検出されたテキストを収集
detected_texts = []
if len(result) > 0 and result[0] is not None:
doc_schema = result[0]
# 初回実行時のみデバッグ情報
if first_run:
print('\n=== DocumentAnalyzerSchemaの詳細構造 ===')
if hasattr(doc_schema, 'paragraphs') and doc_schema.paragraphs:
print(f'paragraphs length: {len(doc_schema.paragraphs)}')
if hasattr(doc_schema, 'words') and doc_schema.words:
print(f'words length: {len(doc_schema.words)}')
first_run = False
# テキスト抽出
if hasattr(doc_schema, 'paragraphs') and doc_schema.paragraphs:
for paragraph in doc_schema.paragraphs[:MAX_DISPLAY_TEXTS]:
if hasattr(paragraph, 'text'):
detected_texts.append(paragraph.text)
elif hasattr(paragraph, 'content'):
detected_texts.append(paragraph.content)
if not detected_texts and hasattr(doc_schema, 'words') and doc_schema.words:
for word in doc_schema.words[:MAX_DISPLAY_TEXTS]:
if hasattr(word, 'text'):
detected_texts.append(word.text)
elif hasattr(word, 'content'):
detected_texts.append(word.content)
# 画面表示処理
display_frame = frame.copy()
if detected_texts:
img_pil = Image.fromarray(cv2.cvtColor(display_frame, cv2.COLOR_BGR2RGB))
draw = ImageDraw.Draw(img_pil)
for i, text in enumerate(detected_texts):
y_position = TEXT_START_Y + i * TEXT_LINE_HEIGHT
draw.text((10, y_position), text, font=font, fill=TEXT_COLOR_RGB)
display_frame = cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)
# 1秒間隔でコンソール出力
current_time = time.time()
if current_time - last_print_time >= OUTPUT_INTERVAL:
if detected_texts:
timestamp = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
print(f'\n[{timestamp}] 検出されたテキスト:')
for i, text in enumerate(detected_texts):
print(f' {i+1}: {text}')
all_results.append(f'[{timestamp}] {i+1}: {text}')
last_print_time = current_time
return display_frame
# プログラム開始
print('=== YomiToku文字認識プログラム ===')
print('概要: 動画や画像から日本語文字(ひらがな・カタカナ・漢字)を認識します')
print('操作方法:')
print(' - \'q\'キー: プログラム終了')
print(' - 認識結果は画面上に緑色で表示されます')
print(' - 1秒ごとに認識結果をコンソールに出力します')
print(' - 終了時にresult.txtに全結果を保存します\n')
print(f'使用デバイス: {device.upper()}')
print('YomiToku DocumentAnalyzerが正常に初期化されました\n')
print('0: 動画ファイル')
print('1: カメラ')
print('2: サンプル動画')
choice = input('選択: ')
temp_file = None
if choice == '0':
root = tk.Tk()
root.withdraw()
path = filedialog.askopenfilename()
if not path:
exit()
cap = cv2.VideoCapture(path)
elif choice == '1':
cap = cv2.VideoCapture(CAMERA_INDEX, cv2.CAP_DSHOW)
cap.set(cv2.CAP_PROP_BUFFERSIZE, BUFFER_SIZE)
elif choice == '2':
# サンプル動画ダウンロード・処理
try:
urllib.request.urlretrieve(SAMPLE_VIDEO_URL, SAMPLE_VIDEO_FILE)
temp_file = SAMPLE_VIDEO_FILE
cap = cv2.VideoCapture(SAMPLE_VIDEO_FILE)
except Exception as e:
print(f'動画のダウンロードに失敗しました: {SAMPLE_VIDEO_URL}')
print(f'エラー: {e}')
exit()
else:
print('無効な選択です')
exit()
# メイン処理
try:
while True:
cap.grab()
ret, frame = cap.retrieve()
if not ret:
break
processed_frame = video_processing(frame)
cv2.imshow(WINDOW_NAME, processed_frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
finally:
cap.release()
cv2.destroyAllWindows()
if temp_file:
os.remove(temp_file)
# 結果をファイルに保存
if all_results:
with open(RESULT_FILE, 'w', encoding='utf-8') as f:
f.write('=== YomiToku文字認識結果 ===\n')
f.write(f"処理日時: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())}\n\n")
for result in all_results:
f.write(result + '\n')
print(f'\n結果を{RESULT_FILE}に保存しました')
print('\nプログラムを終了しました')
使用方法
- 上記のプログラムを実行する
- パソコンカメラが起動し、リアルタイム文書解析画面が表示される
- 解析したい文書(印刷物、手書き文書、表、レイアウト複雑な文書等)をカメラに映す
- 画面に文字認識結果が表示される
- コンソールにも文字認識結果が出力される
- 'q'キーを押すとプログラムが終了する
実験・探求のアイデア
基礎レベル実験
文書種別による精度比較実験
- 印刷物と手書き文書の認識精度
- 縦書きと横書きと混在文書の認識精度
応用レベル実験
複雑レイアウト解析実験
- 新聞、雑誌、論文、パンフレット等の多段組レイアウト解析比較
- 図表混在文書でのテキスト領域と図表領域の分離精度測定
表構造認識の限界探求
- 罫線ありと罫線なし表の認識精度比較
- セル結合(rowspan×colspan)の複雑さと認識精度の関係確認
発展レベル実験
詳細パラメータ分析
- フォントサイズ(8pt〜72pt)による認識率変化測定
- 傾斜角度(0°〜45°)による認識精度影響調査
- ヘッダー、フッター、キャプション等の要素分類精度評価
応用可能性の検証
- 様々な手書き文字(ノート,ホワイトボード,黒板,アンケート用紙)と個人差の確認
- ノイズ画像での認識限界調査
- 照明条件(明るさ、影、反射)が与える影響度測定