はじめに
「画像から文字を抽出したい」という要件、意外とよくありませんか。
個人的には、領収書のスキャンデータを整理したいとか、スクリーンショットからテキストをコピーしたいとか、ちょっとした場面で「OCRがあれば...」と思うことが何度もあったんですよね。
で、調べてみたらTesseract.jsというライブラリがかなり良さそうだったので、今回はこれを紹介します。GitHubスター数は37,700以上、11年以上メンテナンスが続いている安定したプロジェクトです。
とはいえ、説明を読むより実際に動かした方が早いと思います。ブラウザ上でCanvasに描いた文字を、その場でTesseract.jsに読み取らせるサンプルを用意したので、先に挙動を見たい方はこちらからどうぞ。
Tesseract.jsとは
Tesseract.jsは、ブラウザとNode.jsの両方で動作するJavaScript製のOCR(光学文字認識)ライブラリです。
もともとGoogleが開発していたTesseract OCRエンジンをWebAssemblyでラップしたもので、サーバーサイドに依存せずにブラウザ内だけで文字認識ができるという、なかなか画期的なやつです。
特徴・メリット
100言語以上に対応
日本語はもちろん、英語、中国語、韓国語など主要な言語は一通りカバーしています。多言語サイトを運営していたり、海外の資料を扱う機会がある人には嬉しいポイントですね。
ブラウザだけで完結する
これ、意外とすごいことで。従来のOCRって、サーバー側で処理するか、デスクトップアプリを使うかの二択だったんですよ。Tesseract.jsならWebアプリとして提供できるので、ユーザーにインストールを求める必要がない。
軽量化が進んでいる
バージョン5以降で大幅にファイルサイズが削減されました。英語で54%、中国語に至っては73%も軽くなっているとのこと。モバイル環境でも実用的なレベルになってきています。
Apache License 2.0
商用利用も問題なし。業務システムに組み込むハードルが低いのは助かります。
インストール方法
npm/yarn の場合
npm install tesseract.js
# または
yarn add tesseract.js
CDNで使う場合
手軽に試したいなら、CDNから読み込むのが一番早いです。
<script src='https://cdn.jsdelivr.net/npm/tesseract.js@5/dist/tesseract.min.js'></script>
Tesseract.jsのサンプルを動かす
下のサンプルは、テキストボックスに入力した文字をCanvasに描画し、その画像をcreateWorker()で作ったworkerのrecognize()に渡してOCRを実行します。ボタンを押すと、Canvas描画から認識完了までがその場で確認できます。
まずは要点だけを抜き出すと、Tesseract.jsの基本の流れはこれだけです。
import { createWorker } from 'tesseract.js'
// 文字を描いたCanvas(Image・Blob・URLも可)を渡すだけでOCRできる
const worker = await createWorker('eng')
const { data: { text } } = await worker.recognize(canvas)
console.log(text.trim())
// 使い終わったら必ず解放する
await worker.terminate()
実際に動かせるものが下です。初期値のHELLO WORLDのままボタンを押すとほぼ確実に認識できますが、テキストをhello worldのように小文字へ変えても問題なく読み取れます。逆に文字を極端に短くしたり記号だらけにすると、worker.recognize()の結果が空文字やノイズ混じりになりやすいので、その違いも試してみてください。
createWorker('eng')で英語用のワーカーを1つ作り、worker.recognize(canvas)にCanvas要素をそのまま渡しているのがポイントです。画像ファイルのアップロードがなくても、Canvasに描いた文字列だけでTesseract.jsの認識精度を手軽に確認できます。
基本的な使い方
シンプルな例
まずは最もシンプルな使い方から。
import { createWorker } from 'tesseract.js';
(async () => {
// 英語用のワーカーを作成
const worker = await createWorker('eng');
// 画像からテキストを認識
const result = await worker.recognize('image.png');
console.log(result.data.text);
// 後片付け
await worker.terminate();
})();
正直なところ、こんなに簡単でいいのかと思うレベルです。
日本語を認識する場合
日本語の場合は、言語コードをjpnに変更するだけ。
import { createWorker } from 'tesseract.js';
(async () => {
// 日本語用のワーカーを作成
const worker = await createWorker('jpn');
const result = await worker.recognize('japanese_text.png');
console.log(result.data.text);
await worker.terminate();
})();
複数画像を処理する場合
ここ、ちょっとしたポイントがあります。複数の画像を処理するときは、ワーカーを使い回すのが効率的です。
import { createWorker } from 'tesseract.js';
(async () => {
const worker = await createWorker('jpn');
const images = ['image1.png', 'image2.png', 'image3.png'];
for (const image of images) {
const result = await worker.recognize(image);
console.log(`${image}: ${result.data.text}`);
}
// 全部終わってからterminate
await worker.terminate();
})();
画像ごとにワーカーを作り直すと、その都度言語データのロードが走って遅くなるんですよね。
並列処理でさらに高速化
大量の画像を処理するなら、スケジューラーを使った並列処理が便利です。
import { createScheduler, createWorker } from 'tesseract.js';
(async () => {
const scheduler = createScheduler();
// 4つのワーカーを並列で動かす
for (let i = 0; i < 4; i++) {
const worker = await createWorker('jpn');
scheduler.addWorker(worker);
}
const images = ['img1.png', 'img2.png', 'img3.png', 'img4.png'];
const results = await Promise.all(
images.map(img => scheduler.addJob('recognize', img))
);
results.forEach((result, i) => {
console.log(`${images[i]}: ${result.data.text}`);
});
await scheduler.terminate();
})();
実践的なユースケース
領収書・請求書の自動読み取り
経費精算システムとか、会計ソフトとの連携で使えそうですね。撮影した領収書から金額や日付を抽出して、自動入力するイメージ。
名刺管理アプリ
スマホで名刺を撮影して、連絡先情報を自動抽出。既存の名刺管理サービスと同じようなことが、自前で実装できます。
スクリーンショットからのテキスト抽出
画像化されたテキスト(PDFのスキャン画像とか)からテキストを抜き出すツール。社内システムで「この画像からテキストをコピーしたい」という要望、結構あるんですよね。
多言語ドキュメントの翻訳前処理
海外の資料をOCRで読み取って、翻訳APIに投げる。手作業で打ち直す時代は終わりました。
複数言語をまとめて認識する(英語+日本語)
名刺や領収書のように、英語と日本語が1枚の中に混在するドキュメントも珍しくありません。Tesseract.jsのcreateWorker()は言語コードを配列で渡せるので、createWorker(['eng', 'jpn'])とすれば1つのワーカーで両方のtraineddataを読み込み、混在テキストを一度に認識できます。
import { createWorker } from 'tesseract.js'
// 配列で複数の言語コードを渡すと、1つのワーカーで両方の言語を認識できる
const worker = await createWorker(['eng', 'jpn'])
const { data: { text } } = await worker.recognize(image)
console.log(text)
await worker.terminate()
下のサンプルは、入力した文字列をCanvasに描画してからcreateWorker(['eng', 'jpn'])で作ったワーカーに認識させます。初期値のTokyo 東京駅 2026はアルファベット・漢字・数字が混ざった状態ですが、そのまま認識できるはずです。日本語部分だけを別の単語に差し替えたり、逆に英語部分を消してみたりして、recognize()の結果がどう変わるか確認してみてください。
ワーカーをlet workerで使い回しているのもポイントです。言語データのロードは初回だけで済むので、2回目以降のボタン操作は認識処理だけが走り、体感速度が上がります。
進捗表示付きでOCRを実行する
Tesseract.jsは初回に言語データやコアのWebAssemblyをダウンロードするため、数秒〜数十秒の待ち時間が発生します。createWorker()の第3引数に渡すオプションのloggerコールバックを使うと、status(読み込み中の処理名)とprogress(0〜1の進捗率)を受け取れるので、ローディングUIに反映できます。
import { createWorker } from 'tesseract.js'
// logger に渡した関数が status / progress (0〜1) を都度通知してくれる
const worker = await createWorker('eng', 1, {
logger: (m) => {
console.log(m.status, m.progress)
},
})
await worker.recognize(image)
await worker.terminate()
下のサンプルでは、loggerから届いたm.statusとm.progressをそのまま進捗バーに反映しています。ボタンを押すとワーカーの初期化から認識完了までの各フェーズがリアルタイムに表示されるので、実際のアプリでローディング表示を作るときの参考にしてください。
m.statusにはloading tesseract coreやrecognizing textといったフェーズ名が入ってくるので、そのまま画面に出すだけでも「今何をしているか」が伝わるUIになります。バーが途中で止まって見える場合は、ネットワークが遅くて言語データのダウンロードに時間がかかっている状態です。
注意点
認識精度は画像品質に依存する
当たり前といえば当たり前ですが、ぼやけた画像や手書き文字の認識精度はそこまで高くないです。きれいに印刷された文字なら問題ないですが、癖のある手書きは厳しい。
初回ロードに時間がかかる
言語データをダウンロードするため、初回の実行には数秒かかります。UXを考えるなら、ローディング表示は必須ですね。
日本語は英語より精度が落ちる
これはTesseract全般の話ですが、ラテン文字に比べると日本語の認識精度は若干落ちます。とはいえ、実用レベルではあります。
まとめ
Tesseract.jsは、ブラウザ内で完結するOCR処理を実現できる貴重なライブラリです。
- 100言語以上対応
- ブラウザ・Node.js両対応
- インストールが簡単
- Apache License 2.0で商用利用OK
個人的には、ちょっとした社内ツールを作るときに重宝しそうだなと思っています。サーバーサイドを用意しなくていいのが、地味に嬉しいポイントですね。
興味があれば、まずはCDNから読み込んで試してみてください。思った以上に簡単に動きますよ。