Upgrade to Pro — share decks privately, control downloads, hide ads and more …

やっぱりWasm は C++!!!~巨人の肩に乗ろう~

やっぱりWasm は C++!!!~巨人の肩に乗ろう~

この資料はWebAssembly Night #10の資料であり、同時にOpenCV Advent Calendar 2020の9日目の記事の素材でもあります。

リンクをクリックできる、PDF版はこちらのGoogle Driveからどうぞ。

Yuusuke KOUNOIKE

December 09, 2020
Tweet

More Decks by Yuusuke KOUNOIKE

Other Decks in Technology

Transcript

  1. やっぱりWasm は C++!!! 〜巨⼈の肩に乗ろう〜 WebAssembly Night #10 kounoike (@ko_noike) &

    OpenCV Advent Calendar 2020 9⽇⽬ ※現状での個⼈の⾒解です 2
  2. 5

  3. 6

  4. 画像処理 on your Browserの時代 WebRTCインフラの充実 時⾬堂 WebRTC SFU Sora/NTT Com.

    SkyWay/Amazon Chime SDK/ Azure Communication Services/Zoom Customizable SDK... Web会議の実装がより簡単に →差別化要素は︖︓その⼀つとしてのブラウザ側での画像処理 Google Meet 背景ぼかし Meet 最強 記事に書いたように、Googleの技術を結集した成果 7
  5. 典型的ブラウザ画像処理 背景ぼかし TypeScript/tensorflow.jsで作られたBodyPixがよく使われる Webカメラ => getUserMedia() => videoタグ => BodyPix

    => canvasタグ => captureStream() => WebRTC 推論︓tensorflow.js(WebGLバックエンド/Wasmバックエンド) 後処理(ぼかし)︓BrowserJS/CSSでcanvasお絵描き頑張る WebRTCへの送信︓canvasの captureStream() バーチャル背景(背景差し替え)は︖ JSで頑張る︖ OpenCV使って楽をする︖ ⽬標処理時間(理想)︓30fps=33.3333ms 10
  6. 合成処理(単純版) JSだと for(row=0; row<h; row++) for(col=0; col<w; col++) composed[(row*w+col)*4+3] =

    mask[row*w+col]; ctx.drawImage(bg); // 背景を先に描く ctx.putImageData(...); // アルファチャンネル使って合成 OpenCV.jsだと cv.split(original, imageRGBA); // RGBAチャンネルの分離 imageRGBA.set(3, mask); // 3:Alphaをmaskに差し替え cv.merge(imageRGBA, composed); // 結合して戻す ctx.drawImage(bg); // 背景を先に描く ctx.putImageData(...); // アルファチャンネル使って合成 ループはネイティブ側で処理できる 単純な合成でなく他の様々な画像処理もやりやすい 12
  7. opencv.js版(配布/⾃分でビルドともにソースは同じ) let cnt = 0; const updateCanvas = () =>

    { const srcMat = new cv.Mat(video.height, video.width, cv.CV_8UC4); const rgbMat = new cv.Mat(); const rgbOutMat = new cv.Mat(); const outMat = new cv.Mat(); cap.read(srcMat); // videoタグから画像読み込み cv.cvtColor(srcMat, rgbMat, cv.COLOR_RGBA2RGB); // RGBA->RGB rgbMat.convertTo(rgbOutMat, -1, 1, cnt++ % 200 - 100); // -100〜+100 cv.cvtColor(rgbOutMat, outMat, cv.COLOR_RGB2RGBA); // RGBAに戻す cv.imshow("canvas", outMat); // canvasに描画 srcMat.delete(); // メモリ解放処理 rgbMat.delete(); rgbOutMat.delete(); outMat.delete(); requestAnimationFrame(updateCanvas); // rAFでループ }; updateCanvas(); ※実際は変数のスコープを持ち上げたりして解放処理サボったりする 15
  8. C++版(C++処理関数) void doOpenCvTask(size_t addr, int width, int height, int cnt)

    { auto data = reinterpret_cast<void *>(addr); cv::Mat rgbaMat(height, width, CV_8UC4, data); cv::Mat rgbMat; cv::Mat rgbOutMat; cv::Mat outMat; cv::cvtColor(rgbaMat, rgbMat, cv::COLOR_RGBA2RGB); // RGBA->RGB rgbMat.convertTo(rgbOutMat, -1, 1.0, cnt % 200 - 100.0); // -100〜+100 cv::cvtColor(rgbOutMat, outMat, cv::COLOR_RGB2RGBA); // RGBAに戻す // メモリ解放処理いらない if (SDL_MUSTLOCK(screen)) // 描画処理はちょっと⾯倒 SDL_LockSurface(screen); cv::Mat dstRGBAImage(height, width, CV_8UC4, screen->pixels); outMat.copyTo(dstRGBAImage); if (SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen); SDL_Flip(screen); } 16
  9. C++版呼び出しJS const updateCanvas = () => { context.drawImage(video, 0, 0);

    const data = context.getImageData(0, 0, width, height); const buffer = Module._malloc(data.data.length); Module.HEAPU8.set(data.data, buffer); Module.doOpenCvTask(buffer, width, height, cnt++); Module._free(buffer); requestAnimationFrame(updateCanvas); }; updateCanvas(); ※JS側でヒープメモリを管理している (確保・解放をループの外側にしてもいいけど) 17
  10. まとめ&補⾜ C++でWasm書くのは便利 各種マルチメディア・⾃然⾔語処理などのライブラリ活⽤ 「C++はJavaScriptと違ってメモリ管理がいらなくて簡単」 やりたいことと各⾔語の現状次第 単機能Wasmを組み合わせて使えばそれぞれで⾔語選択が可能 なぜ WebAssembly ⽣成を Go

    にしたのか(WebRTC E2EEの話) 「Pure Goで信頼できる暗号化ライブラリがある」など Apache TVM(Rust:推論ランタイム on Wasm)とかも頑張ってる Wasmそのものはまだまだ遅いのでSIMD/Thread/WebGPUなどの発展に期待 21