React + Tesseract.js でリアルタイム文字認識してみた
Note
#React
#TypeScript
今回は React と文字認識用(OCR)のライブラリである Tesseract.js
を使ってリアルタイムの文字認識を Web 上でやってみました。
Tesseract.js
公式ページ - https://tesseract.projectnaptha.com/
Tesseract.js
は、有名(らしい)な文字認識のエンジンである Tesseract OCR engine を使っている JavaScript のライブラリです。
JS で使えるため、ブラウザ上でも Node.js(サーバー)上でも動くのが強みです
簡単な使い方
公式ドキュメントにもありますが、使い方を軽く説明します。
まず、ライブラリの createWorker()
を使って worker
を作成、初期化します:
const worker = createWorker();
await worker.load();
await worker.loadLanguage("eng");
await worker.initialize("eng");
今回は英語("eng")でしていますが、日本語("jpn")もあるみたいです
あとは対象の画像ファイルから文字を認識したい場合は、
const data = await worker.recognize("sample.png");
これで認識の結果が返ってきます! 簡単ですね
リアルタイムでの文字認識
画像ファイルからの読み込みを紹介しましたが、リアルタイムでの文字認識を実現するためには、カメラを使い、写った情報を取得する必要があります
今回は、カメラの映像を 2 秒ごとに canvas
に変換してそれを読み込むように作成していきます。
まずは各関数を紹介していきます:
initWorker()
const initWorker = async () => {
const worker = createWorker();
await worker.load();
await worker.loadLanguage("eng");
await worker.initialize("eng");
setWorker(worker);
};
今回は React の useState()
を使用しているため、setWorker()
で作成した worker を保管しています
initStream()
const initStream = async () => {
const stream = await navigator.mediaDevices.getUserMedia({
video: { width: 500, height: 300 },
audio: false,
});
setStream(stream);
};
getUserMedia()
でユーザーにカメラの使用の許可をもらいます。stream は同様に useState()
で保管します。
onRecognizeText()
const onRecognizeText = () => {
const timerId = setInterval(async () => {
if (videoRef.current === null || !worker) return;
const c = document.createElement("canvas");
c.width = 500;
c.height = 300;
c.getContext("2d")?.drawImage(videoRef.current, 0, 0, 500, 300);
// canvasから文字を認識!!
const {
data: { text },
} = await worker.recognize(c);
setText(text);
}, 2000);
return () => clearInterval(timerId);
};
2 秒ごとに <video />
のデータを canvas
に変換して worker.recognize()
で文字認識をします。
コード全体は以下のようになります。上で紹介した関数は省略しています:
import React, { useState, useRef, useEffect } from "react";
import { createWorker } from "tesseract.js";
const App = () => {
const [stream, setStream] = useState<MediaStream | null>(null);
const [worker, setWorker] = useState<Tesseract.Worker | null>(null);
const [text, setText] = useState("");
const videoRef = useRef<HTMLVideoElement>(null);
const initWorker = async () => {
// ...
};
const initStream = async () => {
// ...
};
const onRecognizeText = () => {
// ...
};
useEffect(() => {
if (!worker) initWorker();
if (!stream) initStream();
if (worker && stream && videoRef.current !== null) {
videoRef.current.srcObject = stream;
const clear = onRecognizeText();
return clear;
}
}, [worker, stream]);
return (
<div>
<video ref={videoRef} autoPlay />
<pre>
<h1>{text}</h1>
</pre>
</div>
);
};
export default App;
動作結果
このようになりました。簡単に実装できましたが、精度としては難ありかなと感じます(日本語だとより難しいそうです)
JSでの文字認識をやってみた。精度いいとは言えんなぁ... pic.twitter.com/0FrjQRWsMM
— さっこー (@sako_data)
June 27, 2020
さいごに
React + Tesseract.js でリアルタイム文字認識をしていきました。 実際に使うためには、画像の前処理とかをして精度を上げていく必要がありそうです