2024/12/31

【Python】tesseract.js+Flask+PywebviewでOCRを実装する

はじめに

画像から文字を抽出するOCR(Optical Character Recognition)は、紙の書類を電子化したり、スクリーンショットに写った文字を読み込んで活用したりと、さまざまなシーンで重宝される技術です。

PythonでOCRを実装する際、「Tesseract」というオープンソースのOCRエンジンの名前を耳にした方も多いのではないでしょうか。しかしながら、TesseractのインストールやOSごとの依存関係を調整する必要があるなど、環境構築で課題が生じる可能性があります。

本記事では、そうした問題を回避するため、tesseract.jsFlaskPywebviewを組み合わせて、Python環境で比較的容易にOCR機能を実装する方法をご紹介します。


1. Tesseractとは

Tesseractは、Googleが管理する高機能なオープンソースのOCRエンジンです。C++実装であり、多言語の文字認識に対応しています。Pythonから利用する場合、Tesseract本体をOSごとにインストールしたうえで、学習データ(.traineddata)の配置して、「pytesseract」や「pyocr」といったラッパーライブラリを通して画像解析を行うのが一般的です。

2. tesseract.jsとは

こうした導入や運用での煩雑さを軽減する一つの方法として、JavaScript版のtesseract.jsが挙げられます。tesseract.jsはWebAssembly技術を用いており、Webブラウザやブラウザ互換の環境であれば、Tesseract本体をインストールせずともOCRが実行できます。Python環境でも、後述のFlask+Pywebview構成などを使うことでGUIアプリケーションとして利用できます。

3. tesseract.js+Flask+Pywebviewで実装するOCR

3-1. 全体構成の概要

本記事で紹介する方法では、以下の三つの要素を組み合わせてOCRを実行します。

  1. Flask

    • Python製の軽量Webフレームワーク。
    • 今回の例ではファイルアップロードや簡易APIの実装などを行い、ブラウザ(Pywebview)に対する表示や処理の受け渡しを担います。
  2. Pywebview

    • Pythonコードから「ブラウザ相当のUIウィンドウ」を生成するライブラリ
    • Flaskで立ち上げたWebアプリにローカルでアクセスし、GUIアプリケーションのような操作感を提供します。
  3. tesseract.js

    • WebAssembly版Tesseract。
    • Pywebview上でレンダリングされるHTML環境に読み込み、画像中のテキストを認識します。

3-2. ディレクトリ構成例


project/
├── app.py
└── templates/ 
    └── index.html

3-3. 実装サンプルのコード紹介

以下に、主要ファイルのサンプルコードを示します。

app.py
from flask import Flask, render_template, request, jsonify
import webview
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
@app.route('/process-ocr', methods=['POST'])
def process_ocr():
data = request.get_json()
ocr_text = data.get('text', '')
print('OCR結果:\n', ocr_text) # OCR結果をコンソールに出力
return jsonify({'status': 'success'})
if __name__ == '__main__':
window = webview.create_window('OCR アプリケーション', app)
webview.start()
view raw app.py hosted with ❤ by GitHub
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>OCR アプリケーション</title>
<script src='https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js'></script>
<style>
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
#imagePreview {
max-width: 100%;
margin: 20px 0;
display: none;
}
#result {
margin-top: 20px;
padding: 10px;
border: 1px solid #ccc;
min-height: 100px;
}
#status {
color: #666;
margin: 10px 0;
}
.button-group {
margin: 20px 0;
}
button {
padding: 8px 16px;
margin-right: 10px;
}
.preview-container {
margin: 20px 0;
text-align: center;
}
</style>
</head>
<body>
<div class="container">
<h1>OCR処理</h1>
<input type="file" id="imageInput" accept="image/*" onchange="previewImage(event)">
<div class="preview-container">
<img id="imagePreview" alt="プレビュー">
</div>
<div class="button-group">
<button onclick="processImage()">OCR実行</button>
<button onclick="clearAll()">クリア</button>
</div>
<div id="status"></div>
<div id="result"></div>
</div>
<script>
function previewImage(event) {
const file = event.target.files[0];
if (file) {
const preview = document.getElementById('imagePreview');
preview.style.display = 'block';
preview.src = URL.createObjectURL(file);
}
}
async function processImage() {
const file = document.getElementById('imageInput').files[0];
const statusDiv = document.getElementById('status');
const resultDiv = document.getElementById('result');
if (!file) {
alert('画像を選択してください');
return;
}
statusDiv.textContent = 'OCR処理中...';
try {
const worker = await Tesseract.createWorker();
const { data: { text } } = await worker.recognize(file);
await worker.terminate();
resultDiv.textContent = text;
statusDiv.textContent = 'OCR処理完了';
// OCR結果をPythonに送信
fetch('/process-ocr', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({text: text})
});
} catch (error) {
console.error('Error:', error);
statusDiv.textContent = 'エラーが発生しました';
}
}
function clearAll() {
document.getElementById('imageInput').value = '';
document.getElementById('imagePreview').style.display = 'none';
document.getElementById('result').textContent = '';
document.getElementById('status').textContent = '';
}
</script>
</body>
</html>
view raw index.html hosted with ❤ by GitHub

3-4. 動作画面

テストファイル:eng_bw.png

今後の課題・改良点

複数画像の取り込み

  • 現状のサンプルでは単一のファイル入力を想定しています。

並列処理(パフォーマンスの向上)

  • tesseract.jsはWebAssemblyで動作するため比較的高速ではあるものの、大量の画像を同時に処理したい場合や高速化が求められる場面では、並列処理などを検討して下さい。

まとめ

以上のように、tesseract.jsとFlask、およびPywebviewを組み合わせることで、Python環境でOCR機能を簡易的に実装できる方法をご紹介しました。
本記事のアプローチがPythonでOCR機能を開発する際の一助になれば幸いです。