【ブラウザだけ、Zoom/ Teamsほかで動く】「mmhmm」のようなプレゼン+人物動画リアルタイム合成を自作してみる

# TL;DR

- HTML5のプレゼン上に、背景を削除した自身の映像を重ね、オンラインで、一味違ったプレゼンができます
- [デモをこちらで試せます](https://tomo-makes.github.io/video-overlay-test.html)
    - 1. Webカメラが付いたPCで上のページを開く
    - 2. Webカメラを有効化する(ブラウザのセキュリティ設定)
    - 3. プレゼン風のデッキをカーソルキーで行き来しながら、mmhmm気分? が味わえます。


<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">「mmhmm」がまだプレビューだけど使ってみたいので、作ってみたらまあまあいけた。<br>- HTML5のプレゼンを準備<br>- TensorFlow.js + BodyPixで機械学習による背景削除、プレゼン重畳(<a href="https://twitter.com/hashtag/p5js?src=hash&amp;ref_src=twsrc%5Etfw">#p5js</a> <a href="https://twitter.com/hashtag/ml5js?src=hash&amp;ref_src=twsrc%5Etfw">#ml5js</a>)<br><br>全てブラウザ上で動くので、そのままZoomやTeamsの画面共有で使える。やってみよ。<br><br>* 動画は2倍速 <a href="https://t.co/PhRxM98SR7">pic.twitter.com/PhRxM98SR7</a></p>&mdash; tomo-makes@図解速習DEEP LEARNING (@tomo_makes) <a href="https://twitter.com/tomo_makes/status/1282128475646603264?ref_src=twsrc%5Etfw">July 12, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


# 背景
- Evernote創業者であるフィル・リービン氏が2020/7/7に「mmhmm(んーふー)」を発表
  - [ZoomやMeetなどで魅力的なプレゼンができる「mmhmm」 - PC Watch](https://pc.watch.impress.co.jp/docs/news/1264153.html)
- 現状はプライベートベータ(招待制でのプレビュー)
- ローカルにソフトウェアをインストールして、仮想カメラデバイスとして使うと思われる
- より軽量にブラウザだけで動かしたら、どこまでいけるか試してみたいと思った

# 動作確認
  - Chrome
  - Macbook Pro (macOS Catalina 10.15.3)

# やり方
## VSCode + MarpなどでHTML5プレゼンデッキを作成する

- 参考 [【VS Code + Marp】Markdownから爆速・自由自在なデザインで、プレゼンスライドを作る - Qiita](https://qiita.com/tomo_makes/items/aafae4021986553ae1d8)
- VSCode + Marpの場合、エクスポート形式を、 `Command + ,(カンマ)` から `markdown.marp.exportType` で、ファイルタイプを `html` に設定した上で、デッキをエクスポートします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64608/fd1b03dd-4c06-4e2b-5ff1-6aa587af7e9a.png)


## 所定のCSS、JavaScriptをHTML5のプレゼンデッキに追記する

```html
<html>
<head>
<!-- インポートするJavaScriptライブラリの記述 -->
<script>
// カメラキャプチャ、背景削除、重畳ロジックの記述(JavaScript)
</script>
<style>
/* 上のロジックに関連したスタイルの適用 */
</style>
...
</head>
<body>
...
</body>
</html>
```

- JavaScript部分は以下を実行している
    - 簡易に学習済み機械学習モデルとカメラ、表示のためのcanvasを扱うため、ml5js, p5jsを使った
    - 背景削除にBodyPixを使った
    - 処理の流れ
        - Webブラウザ上でローカルマシンのカメラ利用を承諾
        - HTML5プレゼンの前面に、透過度0.4で大きなキャンバスを重畳
        - カメラから得た画像に対して、BodyPixで人以外の部分(背景)を削除
        - 人の部分をマウスカーソル位置に表示



### スクリプト
#### インポート

```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.min.js"></script>
<script　src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/addons/p5.dom.min.js"></script>
<script src="https://unpkg.com/ml5@latest/dist/ml5.min.js" type="text/javascript"></script>
```

#### 本体

```javascript
 let bodypix;
 let video;
 let segmentation;
 let img;
 
 const options = {
   outputStride: 8, // 8, 16, or 32, default is 16
   segmentationThreshold: 0.3 // 0 - 1, defaults to 0.5 
 }
 
 function preload(){
   bodypix = ml5.bodyPix(options);
 }
 
 function setup() {
   createCanvas(1400, 1600);
   video = createCapture(VIDEO);
   video.size(400, 300);
   bodypix.segment(video, gotResults)
 }
 
 function gotResults(err, result) {
   if (err) {
     console.log(err);
     return;
   }
   segmentation = result;
   background(255,255,255);
   image(segmentation.backgroundMask, mouseX, mouseY, 266, 200);
   bodypix.segment(video, gotResults)
 }
```

###  スタイルシート
```css
canvas {
  opacity:0.4;
  z-index:5;
}
```


# できあがり!
- あとでGitHubへリソースU/Lし、追記


# まとめ

- HTML5のプレゼンを準備する(ここではVSCode + Marp)
- ml5jsを使い、TensorFlow.js + BodyPixで機械学習による背景削除、プレゼン重畳してmmhmmもどきが動かせた

# 今後の発展

- CSSで透過度を指定し、プレゼンにオーバーレイしているだけなので、少しデッキの色味が変わっている
    - ちゃんとマスクして、オーバーレイして、とやれるはず
- BodyPixによるTensorFlow.js上での背景削除では、フレームレートに限界がある
- また、合成にあたって、例えばマスクにぼかしをかけるなど、自然に見せるためのロジックを軽く組み込むのは難しい
- Chroma key(クロマキー)合成により、もう少し軽く、綺麗な合成ができるかも

# 参考リソース
- BodyPix https://developers-jp.googleblog.com/2019/04/bodypix-tensorflowjs.html
- BodyPix on ml5js https://ml5js.org/reference/api-bodypix/
- Canvasをhtmlコンテンツ上にoverlayする http://jsfiddle.net/6C55n/
- Draw video on canvas https://editor.p5js.org/monicawen/sketches/S1jQHsQn7