(この記事は p5.js の Advent Calendar 2025 の記事にする予定です)
はじめに
この記事は、3年前くらい書いた以下の記事のアップデート版のようなものです。
●p5.js Web Editor で opencv.js を動的にロードして利用する - Qiita
https://qiita.com/youtoy/items/3d423c6d0787ef045904
今回、上記の記事内のコードを少し見直してみました。
コードの内容など
今回、書き直したコードは以下のとおりです。以前の記事と同様、p5.js Web Editor上で利用する前提で、以下は sketch.js に書く処理になります。
let canvas, pg, capture;
let cvReady = false; // OpenCV の読み込み完了フラグ
function setup() {
canvas = createCanvas(640, 480);
pg = createGraphics(width, height);
capture = createCapture(VIDEO);
capture.size(640, 480);
capture.hide();
loadOpenCv();
}
function draw() {
background(120);
pg.image(capture, 0, 0, width, height);
// OpenCV の準備ができるまでは、元の映像を表示
if (!cvReady) {
image(pg, 0, 0, width, height);
return;
}
const src = cv.imread(pg.elt);
const dst = new cv.Mat();
cv.cvtColor(src, dst, cv.COLOR_RGBA2GRAY, 0);
cv.imshow(canvas.elt, dst);
src.delete();
dst.delete();
}
function loadOpenCv() {
if (window.cv) {
waitForCvReady(window.cv);
return;
}
const script = document.createElement("script");
// 4.x にしておくと、常に最新の 4 系のビルドが取得可能
script.src = "https://docs.opencv.org/4.x/opencv.js";
script.async = true;
script.onload = () => {
waitForCvReady(window.cv);
};
script.onerror = (e) => {
console.error("failed to load opencv.js", e);
};
document.body.appendChild(script);
}
async function waitForCvReady(cvModule) {
let cvInstance = cvModule;
if (cvInstance instanceof Promise) {
cvInstance = await cvInstance;
window.cv = cvInstance;
} else if (!cvInstance.Mat) {
// onRuntimeInitialized を使う以前からのパターン
await new Promise((resolve) => {
cvInstance.onRuntimeInitialized = () => resolve();
});
}
cvReady = true;
console.log("OpenCV.js is ready");
}
コードに関する補足
上記のコードについて、見直した主な箇所を以下で補足します。
常に最新バージョンを読み込む
●OpenCV: Using OpenCV.js
https://docs.opencv.org/4.x/d0/d84/tutorial_js_usage.html
cv が Promise になりうる場合の対応
OpenCV.js のドキュメントで、cv オブジェクトが Promise 型になる場合について書かれており、その場合は await を使うという話が書かれていました。
それについて念のため、以下のように、以前のやり方と上記に対応したやり方をまぜた書き方にしています。
async function waitForCvReady(cvModule) {
let cvInstance = cvModule;
if (cvInstance instanceof Promise) {
cvInstance = await cvInstance;
window.cv = cvInstance;
} else if (!cvInstance.Mat) {
// onRuntimeInitialized を使う以前からのパターン
await new Promise((resolve) => {
cvInstance.onRuntimeInitialized = () => resolve();
});
}
cvReady = true;
console.log("OpenCV.js is ready");
}
読み込み開始を window.load を使ったやり方から setup() 内での処理に変更
以前の処理では、読み込み開始を window.load を使って行っていましたが、setup() 内での処理でも問題なさそうなので、setup() 内の最後のところで処理を開始する形にしました。
動作確認
上記の処理を試した結果は、以下の通りです。
カメラからの入力に対し、色をグレースケールにするシンプルな処理を適用できました。

