LoginSignup
2
2
記事投稿キャンペーン 「2024年!初アウトプットをしよう」

OpenCV.jsをChrome拡張で動かすためにはDYNAMIC_EXECUTION=0でビルドする

Posted at

まとめ

OpenCV.jsを「DYNAMIC_EXECUTION=0」を指定してビルドすることで、Manifest V3でも利用できるOpenCV.jsを手に入れることができる。

解説

OpenCV.jsを手っ取り早く利用する方法

公式サイトによるとOpenCV.jsを利用する方法として公式サイトに用意されているファイルをダウンロードして利用するというのが案内されている。

Chrome拡張(Manifest V3)ではevalやnew Functionが禁止されている

しかしダウンロードしたファイルをChrome拡張で利用しようとするとエラーとなる。これはManifest V3でevalやnew Functionが禁止されているために発生する。

対応方法としてサンドボックス化されたiframeを用意するというのが案内されている。その中であればeval等も禁止されていない。
この方法で利用する方法はすでに記事になっている。

Emscriptenのオプションでevalとnew Functionを避けられる

Emscriptenのオプションを調べていくと「DYNAMIC_EXECUTION=0 」evalとnew Functionを利用しないようにするというそのものズバリなものが存在する。

一部の連携向けの機能やオプションが利用できなくなるというのもあるが、OpenCV.jsをちょこっと使う程度のことであれば恐らく問題ない。

OpenCV.jsのビルド環境を整える

OpenCV.jsのビルドはdockerでも提供されておりかなりお手軽に実行することができる。

おまけとして platforms/js/opencv_js.config.py を編集して必要なモジュールだけをビルドするようにすることができるので色々と削るとファイルサイズの削減につながる。

opencv_js.config.py の編集を済ませたらあとはコマンド一発でビルドできる。以下は私がビルドした際のコマンドなので参考までに。

Power Shell
docker run --rm --workdir /src -v "$(get-location):/src" "emscripten/emsdk:2.0.10" emcmake python3 ./platforms/js/build_js.py build_js --disable_single_file --build_flags="-s DYNAMIC_EXECUTION=0 -s ENVIRONMENT=web -s EXPORT_ES6=1 -s MODULARIZE=1 -s FILESYSTEM=0 -s INCOMING_MODULE_JS_API=[] -s INVOKE_RUN=0"

OpenCV.jsを利用する

私の場合はChrome拡張をTypeScriptで実装しており、また動作オプションによってはOpenCV.jsを利用しない場合もあったので動的に読み込む必要があった。以下に参考となるコードを書いておく。

OpenCV.ts
let cv: any;

export const initOpenCV = async (): Promise<void> => {
    if (cv) return Promise.resolve();

    const url = chrome.runtime.getURL("opencv_js.min.js");
    const module = await import(/* @vite-ignore */ url);
    cv = await module.default();
    return Promise.resolve();
};
背景差分で物体抽出を行うコード断片
    // 初期化
    frame = new cv.Mat(canvas.height, canvas.width, cv.CV_8UC4);
    fgmask = new cv.Mat(canvas.height, canvas.width, cv.CV_8UC1);
    fgbg = new cv.BackgroundSubtractorMOG2(500, 16, true);

    ...

    // 検出処理
    const ctx = canvas.getContext("2d", { alpha: false, willReadFrequently: true })!;
    const uint8ClampedArray = ctx.getImageData(0, 0, canvas.width, canvas.height).data;
    frame.data.set(uint8ClampedArray);
    fgbg.apply(frame, fgmask);
    cv.imshow(output, fgmask);

TypeScriptでの型情報をOpenCV.js関係のパッケージから拝借してくる手もあるがそこまで大規模な処理にならないなら割り切ってしまってもイイと個人的には思う。

2
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2