おはようございます。先週なんとなく、熱っぽいことがあった次男ですが、 諸事情により、実家に来てから、症状が悪化して、39度を超える発熱、想定外の事態です。 幸い、高熱が続くことは無く、翌朝は平熱に戻ったので、インフルエンザではなさそう@kjunichiです。
背景
CycleGANで息子たちの顔を入れ替えるやつを学習させようと、まずは子供たちの顔を切出そうと
を読み直して、切り取ったものの、ずいぶん精度が悪かったし、おそかった。。
ここで利用している顔検出処理の実装はPureJSで、かつ、だいぶ今となっては古いので、 OpenCV3.0以降はEmscriptenでビルド出来るようになるというかすかな記憶があり、 ちょっと前はEmscripteのIncomming版でないとWASMできなかったのだが、 最近はlatestで対応されていることを知った。
そんな訳で、顔検出をWASM化したOpenCV.jsでやったら、精度や速度が改善されるのでは?と思い 始めたが、そもそも、OpenCV.jsをNode.jsから動かすのに躓いた。
OpenCVの公式にWASMでビルドする方法があった
ということで、git cloenしてEmscriptenで簡単にWASMでOpenCVがビルドできた
で、どうやってつかうの?
公式には、nodeコマンドでテストもできるよ!って書いてあり、 パッと見、
cv = require('./opencv.js');
とtest_mat.jsなどに記述があり、 楽勝!
と思いきや、テストはパスするも
cv = require('./opencv.js'); let mat = new cv.Mat();
なんて書いても、cv.Matにコンストラクターは未定義だ!のエラー しか出てこない。。
/Volumes/EXTHDD3/local/opencv/build_wasm/bin/opencv.js:21 var Module;if(!Module)Module=(typeof cv!=="undefined"?cv:null)||{};var moduleOverrides={};for(var key in Module){if(Module.hasOwnProperty(key)){moduleOverrides[key]=Module[key]}}var ENVIRONMENT_IS_WEB=false;var ENVIRONMENT_IS_WORKER=false;var ENVIRONMENT_IS_NODE=false;var ENVIRONMENT_IS_SHELL=false;if(Module["ENVIRONMENT"]){if(Module["ENVIRONMENT"]==="WEB"){ENVIRONMENT_IS_WEB=true}else if(Module["ENVIRONMENT"]==="WORKER"){ENVIRONMENT_IS_WORKER=true}else if(Module["ENVIRONMENT"]==="NODE"){ENVIRONMENT_IS_NODE=true}else if(Module["ENVIRONMENT"]==="SHELL"){ENVIRONMENT_IS_SHELL=true}else{throw new Error("The provided Module['ENVIRONMENT'] value is not valid. It must be one of: WEB|WORKER|NODE|SHELL.")}}else{ENVIRONMENT_IS_WEB=typeof window==="object";ENVIRONMENT_IS_WORKER=typeof importScripts==="function";ENVIRONMENT_IS_NODE=typeof process==="object"&&typeof require==="function"&&!ENVIRONMENT_IS_WEB&&!ENVIRONMENT_IS_WORKER;ENVIRONMENT_IS_SHELL=!ENVIRONMEN TypeError: cv.Mat is not a constructor at Object.<anonymous> (/Volumes/EXTHDD3/local/opencv/build_wasm/bin/dame.js:3:11) at Module._compile (module.js:641:30) at Object.Module._extensions..js (module.js:652:10) at Module.load (module.js:560:32) at tryModuleLoad (module.js:503:12) at Function.Module._load (module.js:495:3) at Function.Module.runMain (module.js:682:10) at startup (bootstrap_node.js:191:16) at bootstrap_node.js:613:3
ひょっとして非同期なのでは?
slコマンドをEmscripteで動かした経験もあるので、Emscriptenは コードの読み込みは非同期だったことを思い出す。
cv = require('./opencv.js'); setTimeout(()=>{ (()=>{ let mat = new cv.Mat(); })() },8000);
やった!
今度は動いた。
しかし、全然スマートじゃない!
改善版
var cv = require("./opencv.js"); cv['onRuntimeInitialized']=()=>{ console.log(`cv.CV_8UC3 = ${cv.CV_8UC3}`); let mat = new cv.Mat(10, 20, cv.CV_8UC3); console.log(mat); };
まとめ
Emscriptenではmain関数が呼ばれる準備が完了したら、 ModuleのonRuntimeInitializedに登録したコールバックを読んでくれる
cause opencv_js.js need time to load
なんで、opencvのテストは成功したんだろと軽く再度テストコードのtests.jsを眺めたら、
let testrunner = require('node-qunit'); testrunner.options.maxBlockDuration = 20000; // cause opencv_js.js need time to load
と、なんらかのウェイトを入れてテストを実行している模様。