この記事はOpenCV Advent Calendar 2025の1日目の記事です。
他の記事は目次にまとめられています。
■ はじめに
OpenCV Advent Calendar 2025に興味を持って頂き、ありがとうございます!今年はカテゴリーが「ライブラリ・フレームワーク」から「AI・機械学習・データサイエンス」に移動となりました!(ただ、そんなことを気にせずに投稿しております!)
今回のアドカレでの内容を何か1つでも持ちかえっていただければ、あるいは、来年以降何かのタイミングで検索などでこの情報が参考になりましたら、幸甚に存じます。よろしくお願いいたします!
また、OpenCV Advent Calendar寄稿者の方も、お忙しい中、ご参加いただき誠にありがとうございます!何卒よろしくお願いいたします。
それでは、OpenCV Advent Calendar 2025開始となります!!25日間、最後までお楽しみくださいませ!
■ TL;DR:OpenCV.jsで関数を有効化したい時はここを見てほしい!
- 対象モジュールは、build対象に入っているか?
- 対象モジュールは、js wrapperに認識されているか?
- 対象関数は、gen_dict.jsに登録されているか?
■ はじめに
OpenCV.jsは、OpenCVが提供している機能をEmscriptenを使ってJavaScriptから使えるようにしたライブラリです。もう8年目になりますね。
ただし、外部ライブラリが必要などの理由でOpenCVが提供している機能のフルセットではなくサブセットになっております。そのため、本当はこの機能欲しいんだけど使えない、という悲しい場合も少なくないです。
或いは、元々のOpenCV.jsだとサイズが大きすぎるから、もうちょっと小さいサイズにシュリンクしたかったりもします。
こういう時は、自分でビルドしてあげると、欲しい機能だけ取り出せたりします!
そこで、OpenCV.jsで関数を有効化するときに確認するべき3つのポイントを紹介したい!!
■ OpenCV.jsをデフォルトでbuildしたい!
まずは、OpenCV.jsをbuildする準備をしましょう。以下は、ubuntu 24.04環境です。
〇 emscriptenの準備
まず、build環境の構築になります。このあたりはサクサクやりましょう
11/30現在、emsdk側に修正が入った影響で、最新版の組み合わせだとC++11では動かないかも!?下記2つの修正が別途必要です(両方やったら、最新のOpenCVとlatestのemsdkの組み合わせでもbuildできました)。
(1) emcmake する時に、 -DCMAKE_CXX_STANDARD=17 を指定する
(2) modules/js/CMakeLists.txt 内の-std=c++11を-std=c++17に書き換える
See https://emscripten.org/docs/getting_started/downloads.html
See https://docs.opencv.org/4.x/d4/da1/tutorial_js_setup.html
cd && mkdir work && cd work
apt update -y
sudo apt install -y python3 git cmake
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install latest
./emsdk activate latest
source ./emsdk_env.sh
/home/kmtr/work
├ emsdk
〇OpenCVとOpenCV contribのダウンロード
次に、OpenCVとContribをcloneしましょう。
cd && cd work
git clone https://github.com/opencv/opencv.git
git clone https://github.com/opencv/opencv_contrib.git
/home/kmtr/work
├ emsdk
├ opencv
├ opencv_contrib
〇OpenCV.jsをbuildしてみる
それではさっそく、OpenCV.jsをbuildしてみましょう。
この時contribのコードを取り込みたい場合は、OPENCV_EXTRA_PATH_MODULESにフルパスで指定すると間違いないですね!(多分問題ないはずですが)。
cd && cd work
emcmake python ./opencv/platforms/js/build_js.py -DOPENCV_EXTRA_MODULES_PATH=/home/kmtr/work/opencv_contrib/modules build_js
/home/kmtr/work
├ emsdk
├ opencv
├ opencv_contrib
├ build_js
■ 実際に関数を追加してみる
それでは、実際に関数を追加してみましょう!
〇【確認ポイント1】対象モジュールは、build対象に入っているか?
emcmakeを実行したときに、各モジュールのbuild statusが表示される。ここを確認しましょう!
-- OpenCV modules:
-- To be built: aruco bgsegm bioinspired calib3d core dnn dnn_objdetect dnn_superres dpm face features2d flann fuzzy hfs img_hash imgproc intensity_transform js line_descriptor mcc objdetect phase_unwrapping photo plot rapid reg rgbd saliency signal stereo structured_light surface_matching tracking video wechat_qrcode xfeatures2d xphoto
-- Disabled: highgui imgcodecs ml shape stitching superres videoio videostab world
-- Disabled by dependency: ccalib datasets optflow quality text ts ximgproc xobjdetect
-- Unavailable: alphamat cannops cudaarithm cudabgsegm cudacodec cudafeatures2d cudafilters cudaimgproc cudalegacy cudaobjdetect cudaoptflow cudastereo cudawarping cudev cvv fastcv freetype gapi hdf java julia matlab ovis python2 python3 sfm viz
-- Applications: examples
-- Documentation: js
-- Non-free algorithms: NO
-
To be builtに含まれるモジュールは、OpenCV.jsに含められるモジュール -
DisabledはOpenCV.jsをbuildするときに明示的に無効化されたモジュール -
Disabled by dependencyはDisabledなどの依存関係で無効化されたモジュール
例えば、img_hashやxphotoモジュール内の関数はOpenCV.jsに組み込めます。しかし、freetypeやsfmは組み込めない、という事になります。自分が使いたい関数のモジュールが有効化されているのかを確認しましょう!
〇【確認ポイント2】対象モジュールは、js wrapperに認識されているか?
自分が使いたい関数を含むモジュールが有効化されていても、まだ油断はなりません!
次は、js wrapperがその対象モジュールを認識しているかを確認しなければなりません。これは各モジュールのCMakeLists.txtを確認してください
ocv_define_module行のWRAP jsが重要です。これが書いてあるモジュールだけが、js wrapperはOpenCV.js対象モジュールとして認識されます。
OpenCV.js対象モジュールとして認識されたかどうかは、emcmake実行時のログにも出力されます!
-- Wrapped in JavaScript(js):
-- opencv_core
-- opencv_imgproc
-- opencv_photo
-- opencv_dnn
-- opencv_features2d
-- opencv_calib3d
-- opencv_objdetect
-- opencv_video
-- opencv_wechat_qrcode
-- opencv_aruco
-- Use autogenerated whitelist /home/kmtr/work/build_js/modules/js_bindings_generator/whitelist.json
上記の例だと、core imgproc photoなんかはOpenCV.jsに含まれますが、ximgprocやxphotoなんかは含まれない、ということになりますね。
例えば、img_hashを対象に入れたいならば、WRAP jsを追加してあげる必要があります。
kmtr@kmtr-VMware-Virtual-Platform:~/work/opencv_contrib4$ git diff
diff --git a/modules/img_hash/CMakeLists.txt b/modules/img_hash/CMakeLists.txt
index fe75c22c..e78887ac 100644
--- a/modules/img_hash/CMakeLists.txt
+++ b/modules/img_hash/CMakeLists.txt
@@ -1,3 +1,3 @@
set(the_description "Image hash algorithms")
set(OPENCV_MODULE_IS_PART_OF_WORLD OFF)
-ocv_define_module(img_hash opencv_imgproc opencv_core WRAP python java objc)
+ocv_define_module(img_hash opencv_imgproc opencv_core WRAP python java objc js)
〇【確認ポイント3】対象関数は、gen_dict.jsに登録されているか?
次に、js wrapperがexportするために、misc/js/gen_dict.jsに対象関数を記述して下さい!
例えば、img_hashに含まれる関数だったら、こんな感じになります。
{
"whitelist":
{
"": [ "averageHash", "blockMeanHash", "colorMomentHash", "marrHildrethHash", "radialVarianceHash", "pHash" ]
},
"namespace_prefix_override":
{
"img_hash": ""
}
}
下にある、namespace_prefix_overrideを書かないと、exportしたはずの関数が見つからない、なんてことがありますので、ご注意ください!。
〇 さあ、自分だけのOpenCV.jsをbuildしよう!
それでは、もう一度buildしてみましょう! これで自分だけの特別なOpenCV.jsの完成になります!!
cd && cd work
emcmake python ./opencv/platforms/js/build_js.py -DOPENCV_EXTRA_MODULES_PATH=/home/kmtr/work/opencv_contrib/modules build_js
■ きちんとできていることを確認する
例えばサンプルコードはこんな感じになります。
このindex.htmlを同じフォルダに作成したopencv.jsを置いてください。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello OpenCV.js</title>
</head>
<body>
<h2>Hello OpenCV.js</h2>
<p id="status">OpenCV.js is loading...</p>
<div>
<div class="inputoutput">
<img id="imageSrc" alt="No Image" />
<div class="caption">imageSrc <input type="file" id="fileInput" name="file" /></div>
</div>
<div class="inputoutput">
<canvas id="canvasOutput" ></canvas>
<div class="caption">canvasOutput</div>
</div>
</div>
<script type="text/javascript">
let imgElement = document.getElementById('imageSrc');
let inputElement = document.getElementById('fileInput');
inputElement.addEventListener('change', (e) => {
imgElement.src = URL.createObjectURL(e.target.files[0]);
}, false);
imgElement.onload = async function() {
cv = (cv instanceof Promise) ? await cv : cv;
let src = cv.imread(imgElement);
let dst = new cv.Mat();
cv.averageHash(src,dst);
cv.resize(dst, dst, src.size(), 0, 0, cv.INTER_NEAREST );
cv.imshow('canvasOutput', dst);
dst.delete();
src.delete();
};
var Module = {
// https://emscripten.org/docs/api_reference/module.html#Module.onRuntimeInitialized
onRuntimeInitialized() {
document.getElementById('status').innerHTML = 'OpenCV.js is ready.';
}
};
</script>
<script async src="opencv.js" type="text/javascript"></script>
</body>
</html>
なお、 cv = (cv instanceof Promise) ? await cv : cv; とある通り、cvは実際に関数を呼ばれるまでは読み込みません。つまり、いきなりこのHTMLファイルを読み込んだ時点で、Webブラウザのコンソール上でcv.averageHashと叩いてもundefinedとエラーになります。
なので、一度cvを実体化してから、確かめましょう!
cv = (cv instanceof Promise) ? await cv : cv;`
cv.averageHash
■ まとめ(再掲)
- 対象モジュールは、build対象に入っているか?
- 対象モジュールは、js wrapperに認識されているか?
- 対象関数は、gen_dict.jsに登録されているか?
以上となります。お忙しい中、お読みいただき、ありがとうございました!!
明日12/2は「Zintなら、OpenCVでもMicro QR CodeもrMQRを簡単にサポートできますよ!」になります。OpenCVだけでは対応できなかった、rMQRも実は簡単に作れますよ!!お楽しみに!