2025年10月1日水曜日

ONNX Runtime WebとPaddleOCRを使ってブラウザ上でOCRを実行する

先日、ハルミさんによるZennの記事「GPUなしローカルでも高速・高精度なOCRができるOnnxOCRが凄い」が目に止まりました。この記事で紹介されているOnnxOCRですが、PaddleOCRをONNXモデルに変換したものとのことです。元記事によると、とても性能が良いとのことなので、動かしてみようと思い立ちました。

ONNXモデルなのでONNX Runtime Webを使ってブラウザで実行することで、Oracle APEXのアプリでも利用できそうです。

ChatGPTにONNX Runtime WebとPaddleOCRを組み合わせた実装例を探してもらったところ、GitHub上の xulihang / paddleocr-browser を見つけてくれました。OnnxOCRは使用していませんが、ONNX Runtime Web、e-Search OCRとPaddleOCRを使って、ブラウザ上でOCRを実行しています。

色々見つけた結果を取捨選択して、ONNX Runtime Webとe-Search OCRとOnnxOCRを組み合わせて、ブラウザ上でOCRを実行するAPEXアプリケーションを作成してみました。

作成したAPEXアプリケーションは以下のように動作します。

e-Search OCRによる文字認識では文字を認識した位置も検出しますが、その表示は行なっていません。画像上に矩形を表示する手順については、以前に記事「HTMLの画像に重ねて矩形を描画する手順のまとめ」で紹介しています。


APEXアプリケーションですが、あまりAPEXの機能は使用していません。概ね静的サイトのホスティングに近い実装です。

以下にAPEXアプリケーションの作成手順について紹介します。

空のAPEXアプリケーションを作成します。名前Local OCRとします。作成したアプリケーションのホーム・ページに、すべての機能を実装します。

OCRにかける画像を選択するページ・アイテムと、OCRを実行するボタンを配置するリージョンとして、Controlsを作成します。タイプ静的コンテンツです。

外観テンプレートItem Containerを選択しています。テンプレート・オプションAlighnmentEndを選んでいます。今回はJavaScriptのコードを静的アプリケーション・ファイルにまとめ、APEXアクションとして呼び出します。APEXアクションのコンテキストをこのリージョンに作成するため、静的IDとしてCONTROLSを設定します。


OCRにかける画像を選択するページ・アイテムをP1_IMAGEとして作成します。タイプイメージ・アップロードです。

レイアウトリージョンControlsスロットItemです。

ページを送信してデータベース側で処理を行うことはないので、他の設定は処理に影響しません。


ページ・アイテムP1_IMAGEの値が変更されたときに、以下のJavaScriptコードが実行されるように動的アクションを作成します。

apex.actions.findContextById("CONTROLS").invoke("CHANGE");

ボタンであれば、カスタム属性data-actionで呼び出すAPEXアクションを指定できます。それ以外のコンポーネントでは、同等の属性はありません。そのため、動的アクションからAPEXアクションのCHANGEを呼び出します。APEXアクションCHANGEのコードは静的アプリケーション・ファイルに記述します。


OCRのスキャンを実行するボタンとしてSCANを作成します。

動作アクション動的アクションで定義を選択し、詳細カスタム属性data-action="SCAN"を記述します。ボタンをクリックすると実行されるAPEXアクションSCANは、静的アプリケーション・ファイルに記述します。


選択した画像をプレビューするリージョンを作成します。タイプ静的コンテンツソースHTMLコードとして以下を記述します。

<img id="image" style="width:100%;"></img>

外観テンプレート・オプションで、Body Height480pxに設定しています。


OCRで抽出した文字列を書き込むページ・アイテムとしてP1_TEXTを作成します。タイプテキスト領域です。プレビューの右隣に配置するため、レイアウト新規行の開始オフにします。


以上でページのデザインは完成です。

ページ・プロパティJavaScriptファイルURLに以下を記述します。
https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/ort.min.js
[async]https://cdn.jsdelivr.net/npm/opencv.js/opencv.min.js
-- [module]#APP_FILES#app#MIN#.js
[module]#APP_FILES#ocr_reviewed_improved.js
最初にONNX Runtime Web(ort.min.js)をロードしています。次にOpenCVをロードしています。

続いて、OCRを実行するコードを記述した静的アプリケーション・ファイルをロードしています。私が書いたapp.jsはコメント・アウトしています。ocr_reviewed_improved.jsは、私が書いたapp.jsを、Claude Sonnet 4.5でレビューして書き直したコードです。

ページ・ロード時に実行に以下を記述し、ページ・ロード直後はボタンSCANを無効にします。OCRライブラリの初期化が完了した後に、ボタンSCANを有効にします。

document.getElementById("SCAN").disabled = true;


静的アプリケーション・ファイルとしてocr_reviewed_imporoved.jsを作成します。


ocr_reviewed_improved.jsのコードです。Claudeとのやり取りに興味がある方のために、チャットのリンクも掲載しておきます。

apex.message.showErrorsの使い方は間違っていましたが、そもそもapex.message.showErrorsをコードに追加したこと、使い方を教えるときちんとコードを修正したのには感心しました。


今回作成したAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/local-ocr-with-onnxocr-and-paddleocr.zip

Oracle APEXのアプリケーション作成の参考になれば幸いです。