【クソアプリ】あなたもDeepMagicでマジシャンに！

[クソアプリ2 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/kuso-app2)の18日目の記事です。

誰でもマジシャンになれるDeepMagicを開発しました。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Qiitaアドベントカレンダー用のクソアプリ「Deep Magic」が完成しました。手で囲った物体を消すことができます。 <a href="https://t.co/mrX2d8Azi6">pic.twitter.com/mrX2d8Azi6</a></p>&mdash; shinmura0 | 2/15発表者募集中 (@shinmura0) <a href="https://twitter.com/shinmura0/status/1203655576359555072?ref_src=twsrc%5Etfw">December 8, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

#概要
上記の動画でも紹介しているように、指で囲った物体を消すことができます。

ただし、モニター越しで物体を消しているため、種も仕掛けも**ありまくる**
しょうもないマジックです。**コンセントとモニターが必要なため**、忘年会にも
持っていけませんし、活躍する場が皆無です。

活躍する場が無い...まさしくクソアプリです。

#構成
本アプリは、異なるディープラーニングモデルを3種類使っています。
以下の3ステップで構成されています。

+ 1ステップ：[handtracking](https://github.com/victordibia/handtracking)で手を検出
+ 2ステップ：MobileNet V2で手の形を分類
+ 3ステップ：[Partial Convolutions](https://qiita.com/shinmura0/items/742adb4faefcfc8dd5cb#patial-convolutions)で物体を消す

##1ステップ目
[handtracking](https://github.com/victordibia/handtracking)は以前にも紹介していますが、普通のPC（GPUなし）でも高速に
手の検出ができる優れものです。Githubからクローンしてくるだけで、簡単に使えます。
![hand3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264781/b36f6133-df44-5eae-2a10-d2f67839bd04.gif)
（動画はGithubより）

jetson Nanoで動かすとマルチスレッドで11FPS、シングルスレッドで8FPSの速度が
出ます。（TensorRTにすると、もっと速くなるはずです。）
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Qiitaのアドベントカレンダーに向け、クソアプリを開発中...。まずは、handtrackingをJetson Nanoで動かしてみました。<br><br>生のTesorFlowでもほぼ10FPSで動くので感動！TensorRTになるともっと速くなるのかな？<a href="https://t.co/SQIQPbBvPL">https://t.co/SQIQPbBvPL</a> <a href="https://t.co/LoGGR9lyD0">pic.twitter.com/LoGGR9lyD0</a></p>&mdash; shinmura0 | 2/15発表者募集中 (@shinmura0) <a href="https://twitter.com/shinmura0/status/1193169016925249536?ref_src=twsrc%5Etfw">November 9, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

ただし、[こちら](https://qiita.com/shinmura0/items/07d976fc13ce774036b8#handtracking%E3%81%AE%E7%BD%A0)でも書いたように色々モデルがあり、精度が劇的に変わるため
注意が必要です。

産業用用途では、[こちら](https://qiita.com/shinmura0/items/09ed686466f3d7141d07)にあるような使い方もできます。

##2ステップ目
MobileNet V2では、handtrackingで検出してきた手の画像を渡し、手の形を
分類しています。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Qiita用 <a href="https://t.co/8bsOO16VJH">pic.twitter.com/8bsOO16VJH</a></p>&mdash; shinmura0 | 2/15発表者募集中 (@shinmura0) <a href="https://twitter.com/shinmura0/status/1204245198705836033?ref_src=twsrc%5Etfw">December 10, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

2ステップ目では、以下のように手の形を3種類に分類するタスクを行っています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264781/c2bdcc65-d39b-375f-b7ce-0d8980bcb74c.png)

「ポインター」を認識すると、赤い枠が出てきて物体を消失させる範囲を決めることができます。
「グー」を認識すると、3ステップ目に移行します。「その他」では、特に何もしません。

（本当は、handtacking内で折角SSDが使われているので、手の形の違いで
データを用意して学習させれば、MobileNet V2は不要になります。
それによって、シンプルかつ高速に処理することができますが、
アノテーションに時間がかかるため、今回は諦めました。）

###学習の条件など
+ 画像のサイズ：96×96
+ 最適化手法：SGD
+ エポック：400
+ 転移学習を使っています。

用意した画像の枚数は以下のとおりです。

||枚数|
|---|---|
|ポインター|112|
|グー|51|
|その他|175|

学習させる際は、[PCACA](https://qiita.com/koshian2/items/78de8ccd09dd2998ddfc)を使って500枚に増幅しています。

ちなみに、精度はvalidation、testのデータで共に70％くらい。
MobileNet V2を使って速度を優先させているため、いくらか精度を犠牲にしています。

ただし、予測確率に閾値を設けることで自信がない予測値は全て「その他」に
分類しました。これにより精度が**80％ほど**になりました。

##3ステップ目
[Partial Convolutions](https://qiita.com/shinmura0/items/742adb4faefcfc8dd5cb#patial-convolutions)(PCs)は、マスクした部分を綺麗に復元することが可能です。

PCsには事前に屋内の画像を与え、ランダムにマスクされた画像を復元させる学習を
しておきます。これにより、PCsではマスクされた部分を自然な画像に復元できる
ようになります。

そして、実行の際には、「ポインター」の範囲（赤い枠）でマスクした画像を
PCsに入力し復元させます。その結果、復元させた画像では、赤い枠内が自然な
感じになり、あたかも、枠内にあった物体が消えたようになる仕組みです。

学習の要件は以下のとおりです。

+ 学習用の画像は[SUNRGB-D](http://rgbd.cs.princeton.edu/challenge.html)（屋内の画像10,000枚以上）を使用。
+ エポックは30（1000イタレーション/1エポック）。Colabの学習で34時間かかった。

ちなみに、PCsを異常検知に使うと[異常部分の可視化](https://qiita.com/shinmura0/items/742adb4faefcfc8dd5cb)ができます。

#実行結果
##レベル1
消す範囲は、小さければ小さいほど自然な画像になって帰ってきます。
まずは、小さいマグネットを消します。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Qiita用 <a href="https://t.co/2hEVut29Vo">pic.twitter.com/2hEVut29Vo</a></p>&mdash; shinmura0 | 2/15発表者募集中 (@shinmura0) <a href="https://twitter.com/shinmura0/status/1204244857633439744?ref_src=twsrc%5Etfw">December 10, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

##レベル2
冒頭にお見せした動画です。レベル1に比べ、消す範囲が大きくなっていますが、
周りの背景が単純なので、割と良い結果が得られます。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Qiitaアドベントカレンダー用のクソアプリ「Deep Magic」が完成しました。手で囲った物体を消すことができます。 <a href="https://t.co/mrX2d8Azi6">pic.twitter.com/mrX2d8Azi6</a></p>&mdash; shinmura0 | 2/15発表者募集中 (@shinmura0) <a href="https://twitter.com/shinmura0/status/1203655576359555072?ref_src=twsrc%5Etfw">December 8, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

##レベル3
最後は将棋の駒を消します。消す範囲は小さいですが、周りの背景が複雑なので
ちょっと自信がありませんでした。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Qiita用 <a href="https://t.co/c0OPVrMOGc">pic.twitter.com/c0OPVrMOGc</a></p>&mdash; shinmura0 | 2/15発表者募集中 (@shinmura0) <a href="https://twitter.com/shinmura0/status/1204245044045070336?ref_src=twsrc%5Etfw">December 10, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

動画をよく見ると、**将棋盤の線も一部再現されています。**
何とか頑張っています。

#使い方
##ハード
+ [Jetson Nano](https://qiita.com/shinmura0/items/08db54d98a7bef93f30d)
+ USBカメラ

##ソフト
+ Keras2.2.5
+ OpenCV
+ TensorFlow

##手順
基本的に[Github](https://github.com/shinmura0/DeepMagic)に上げたもので実行可能なのですが、Partial Convolutionsの
モデルは、容量が40MBもあるためアップすることができませんでした。
そのため、**このモデルだけ欠落しています。**

このモデルはメール（shinmura_0@yahoo.co.jp）をいただければ、送信できます。
（40MBでもアップできる方法があれば教えてください）
また、[こちら](https://github.com/shinmura0/PConv-Keras/blob/master/Ano-Unet_V2.ipynb)を参考に自分で学習することも可能です。

アプリの使い方は以下のとおりです。

+ [こちら](https://github.com/shinmura0/DeepMagic)から実行ファイルをダウンロードしてください。
+ main.pyを実行してください。

カメラ画像が表示されたら、以下のとおりに実行してください。

+ 「S」ボタンを押すと、実行開始です。
+ 右手の人差し指を立てて（爪を上に向けるのがポイントです）、消したい物体を囲ってください。
+ その後、手のひらをカメラ側に見せた状態で「グー」にすると囲った物体を消すことができます。
+ 消す範囲が小さければ小さいほど、精巧な復元画像を得ることができます。
+ 消す範囲をリセットする場合は、「R」ボタンを押してください。その後、「S」ボタンを押し実行開始です。

#実行時間
2ステップ目までだと全体で6FPSくらい出ますが、3ステップ目に移行すると
1FPSくらいになります。各処理単体の実行時間は以下のとおりです。

||内容|実行時間(msec）|
|---|---|---|
|1ステップ目|handtracking|120|
|2ステップ目|MobileNet V2|50|
|3ステップ目|Partial Convolutions|500|

#クソアプリから抜け出すために
このアプリの欠点は、マジックのくせに電源とモニターが必要なことです。
スマートではありません。カッコよくありません。

でも、一番のネックはモニターが固定されていることなのです。
モニターを見ながら遊んでいると首が痛くなります。

これは、周りにあるものを消そうとして、気が付くと**首が120度に曲がっている**
ためです。（↓こんなイメージ。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264781/59deb246-7185-92bb-2a5f-9d78720f3ebb.png)

じゃあ、移動式モニターがあれば良いわけです。
移動式モニター、移動式モニター...
スマホでやれば良いじゃん！と思ったあなた、鋭いです。

スマホでも[手の検出が高速にできます](https://github.com/google/mediapipe/blob/master/mediapipe/docs/hand_tracking_mobile_gpu.md)。
![hand_tracking_android_gpu.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264781/919657cc-44b2-77d6-3d4a-14bcb97631b8.gif)
（動画はGithubより）

指の座標も得られるので、さらに高精度の判別ができると思います。

ただ、この後3ステップ目（Partial Convolutions）を動かすと、激遅になると思われるので
**スマホ計画は頓挫**。。。やっぱり、モニターは固定。クソアプリから抜け出せない。

結論：「クソアプリでもいいじゃない。」