YOLOとONNX Runtime Webを使ったスマホブラウザでの物体検出 –

blog20250801.md

こんにちは、テクノロジーイノベーションの朝日です。今回はスマホブラウザ上での物体検出がどのくらい使えるか確認したかったので、YOLOONNX Runtime Webを使って実装してみました。

環境

Python 3.12.11
ultralytics 8.3.170
YOLO 12
ONNX Runtime Web 1.22.0

YOLOをONNX形式でエクスポートする

JavaScriptで使う場合TF.js形式にすることも考えられますが、今回はONNX Runtime Webを使うことにしたため、ONNX形式でエクスポートします。

ONNXモデルのエクスポートの手順に則ってエクスポートします。

まず、Python環境でultralyticsパッケージをインストールします。

pip install ultralytics

なお、今回はVisual Studio Code Dev Containers環境で作業したため、追加で以下の作業を行う必要がありました。

sudo apt update sudo apt install libgl1

エクスポートの引数を見るとNMS(Non-Maximum Suppression)を処理してくれるオプションがあるようなので、Trueにしておきます。 NMSについての説明は省略しますが、このオプションなしのモデルの場合は、JavaScript側でこのロジックを実装してあげる必要があります。

yolo export model=yolo12n.pt format=onnx nms=True

正常終了すると、yolo12n.onnxというファイルができているはずです。

実装

静止画版

まずは静止画を渡して物体検出するコードを作成します。 短いのでHTML+JavaScriptで一気に記載します。

"ja"> "UTF-8"> YOLO+ONNX Runtime Demo(picture) "viewport" content="width=device-width, initial-scale=1.0" /> type="file" id="imgInput" disabled>
"viewCanvas" style="border:solid; width:100%; height:auto;"> "dataCanvas" style="display:none;">

今回は、NMS処理ありのモデルを使ったため、簡単なコードで実装ができました。

実際に動かして、下の画像を処理させてみると、

以下のように検出された物体のバウンディングボックスが書き込まれます。

今回のコードでは、表示用とYOLO用で別々のCanvasを用意して、入力画像の長辺が640pxになるように変換してから推論させています。

推論結果は、戻り値のoutput0.data[x1, y1, x2, y2, score, ClassId]*検出個数の配列で格納されているので、元の画像のサイズに変換しなおしてから表示用Canvasに描画しています。

Webカメラ版

静止画版を少し変えるとWebカメラ対応のコードにできます。

ただ、今回のコードではカメラの解像度は手を抜いて手入力で設定するようにしています。 W,Hを指定してSTARTボタンで開始です。

"ja"> "UTF-8"> YOLO+ONNX Runtime Demo(webcam) "viewport" content="width=device-width, initial-scale=1.0" />

Wtype="number" id="inputWidth" value="5000">"fps">

Htype="number" id="inputHeight" value="5000">

"viewCanvas" style="border:solid; width:100%; height:auto;"> "dataCanvas" style="display:none;">

静止画版のコードと比較するとわかりますが、変更点はVideoを入力にするようにしたのと、processメソッドの最後でRequestAnimationFrameを追加しているくらいで推論や結果の描画周りは同じコードになっています。

実際に動作させると以下のような感じになります。

右上にFPSを表示させていますが、もう少し速いと嬉しいなという感じですね…。

今回のコードは、こちらに公開していますので、簡単に試すことができます。

GPU ON/OFFでの比較

今回のコードでは、以下の部分でWebGPUを利用するように指定しています。

session = await ort.InferenceSession.create('yolo12n.onnx', { executionProviders: ['webgpu'] });

Using the WebGPU Execution Providerによると、scriptタグで読み込むのをort.min.jsからort.webgpu.min.jsに変えるように書いてあるのですが、今回動かした感じだとそのままでも大丈夫そうでした。 そして、このオプションを外すとCPUで動作するのですが、当然ですが以下のようにFPSがかなり下がりました。

最後に

今回は、スマホブラウザでYOLOによる物体検出を行ってみました。

なお、エクスポートの引数を見ていると、dynamicというオプションがあったので、これを有効にすれば縦横比とか解像度を意識しなくても良くなるのかと思いましたが、いくつかの画像で試しているとエラーがでてしまったので、今回は640×640に固定する方法を取りました。

今後は他のオプションや他のモデルを使っての比較なども行ってみたいですね。


Source link

関連記事

コメント

この記事へのコメントはありません。