グリーンバックはもういらない！？Background Mattingでどこでも合成（Windows10、Python 3.6）

# はじめに
Zoomでバーチャル背景が流行っていますね。グリーンバックを必要とせずに一枚の背景画像から人物を切り抜き、ピクセルレベルで違和感なく合成できるBackground Mattingをやってみました。CPUでも動くよ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/dbb05383-0513-192c-17d1-9fb33d52708b.png)

# システム環境
- Windows10（RTX2080 Max-Q、i7-8750H、RAM16GB）
- Anaconda 2020.02
- Python 3.6
- CUDA 10.0
- cuDNN

# 導入
[Background-Matting](https://github.com/senguptaumd/Background-Matting)からクローンします。

back-matting環境を作ります。

~~~
$ cd Background-Matting-master
$ conda create -n back-matting python=3.6
$ conda activate back-matting
~~~

[Pytorch（CUDA 10.0）](https://pytorch.org/get-started/previous-versions/)をインストールします。

~~~
$ pip install torch==1.2.0 torchvision==0.4.0 -f https://download.pytorch.org/whl/torch_stable.html
~~~

必要なライブラリをインストールします。

~~~
$ pip install tensorflow-gpu==1.14.0
$ pip install -r requirements.txt
~~~

[ここ](https://drive.google.com/drive/folders/1WLDBC_Q-cA72QC8bB-Rdj53UB2vSPnXv)からモデルをダウンロードし、Modelsフォルダに置きます。

下記からCUDA 10.0をインストールします。

https://developer.nvidia.com/cuda-10.0-download-archive?target_os=Windows&target_arch=x86_64&target_version=10&target_type=exenetwork

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/26281ce9-443d-de70-bac6-177f14aca983.png)

<!--
システム環境変数に、C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.0\binを追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/a3525187-59cd-3faa-a455-c2a2d6a1fd19.png)

システム環境変数を編集したら、
-->

インストールできたら、Anacondaを再起動します。（システム環境変数にPATHが追加されるため）

cuDNNも必要なので、Download cuDNN v7.6.4 (September 27, 2019), for CUDA 10.0をダウンロードします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/88885d07-6a84-144e-d731-2bc8d8afc449.png)

ダウンロードしたら、***cudnn-10.0-windows10-x64-v7.6.4.38\cuda\bin\cudnn64_7.dll***を***C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.0\bin***に移動

***cudnn-10.0-windows10-x64-v7.6.4.38\cuda\lib\x64\cudnn.lib***を***C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.0\lib\x64***に移動

***cudnn-10.0-windows10-x64-v7.6.4.38\cuda\include\cudnn.h***を***C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.0\include***に移動します。

下記を実行し、画像から人物を切り抜いたマスク画像を生成します。

~~~
$ python test_segmentation_deeplab.py -i sample_data/input
~~~

<!-- 
https://github.com/tensorflow/models.git
をクローンし、PYTHONPATHにmodels-master\research\slimを追加します？？？
--> 


sample_data\inputに_masksDL.pngの画像が生成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/4bd45bfe-ee11-cb73-79e8-bf93c26f6960.png)


下記を実行し、補正します。

~~~
$ python test_pre_process.py -i sample_data/input
~~~

Done: sample_data/input
と出力され、補正されたらしい。

test_background-matting_image.pyの20行目をコメントアウトし、19行目のコメントを外し、os.environ["CUDA_VISIBLE_DEVICES"]を"0"にします。

~~~python
os.environ["CUDA_VISIBLE_DEVICES"]="0" # "4"
# print('CUDA Device: ' + os.environ["CUDA_VISIBLE_DEVICES"])
~~~

下記を実行します。

~~~
$ python test_background-matting_image.py -m real-hand-held -i sample_data/input/ -o sample_data/output/ -tb sample_data/background/0001.png
~~~

sample_data\outputに結果が表示されました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/35a7efbe-e64d-920e-4d34-9b4d34932091.png)

バックグラウンド（背景）の例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/06d2c8f5-a87e-bbcf-e069-3d9da4e9459e.png)

# CPUでやーる
test_background-matting_image.pyの19行目のos.environ["CUDA_VISIBLE_DEVICES"]を"-1"にします。

~~~python
os.environ["CUDA_VISIBLE_DEVICES"]="-1"
~~~

57行目のtorch.load(model_name1)をtorch.load(model_name1,map_location='cpu')にします。
そして、cuda()の部分を取っ払います！

~~~python 
netM.load_state_dict(torch.load(model_name1, map_location='cpu'))
# netM.cuda(); 
netM.eval()
~~~

あとは156行目付近のcuda()を取り除けば、動くはず。

~~~python 
img,bg,rcnn_al,multi_fr=Variable(img),Variable(bg),Variable(rcnn_al),Variable(multi_fr)
input_im=torch.cat([img,bg,rcnn_al,multi_fr],dim=1)

alpha_pred,fg_pred_tmp=netM(img,bg,rcnn_al,multi_fr)

al_mask=(alpha_pred>0.95).type(torch.FloatTensor)
~~~

塩さん、ありがとうございます！
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">そのcuda()とほかcuda関連系のメソッド取っ払ってみてください！</p>&mdash; 塩 (@shiomasa1218) <a href="https://twitter.com/shiomasa1218/status/1254322768608325637?ref_src=twsrc%5Etfw">April 26, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

※test_segmentation_deeplab.py、test_pre_process_video.pyのCPU化が必要？

# 動画もやーる

動画もフレームにして処理した後、動画にするので、一緒ですね。

サンプルの動画を[ここ](https://drive.google.com/drive/folders/1C_fLlL_WUP7A_ZcdKxbYVcF_T1uy1SRK)からダウンロードし、sample_videoとsample_video_fixedをBackground-Mattingの下に置きます。

動画からフレームを抽出します。
sample_videoの下に、inputフォルダとbackgroundフォルダを作成します。

[ffmpeg](https://ffmpeg.org/download.html)をダウンロードします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63863/092bb51a-6972-1655-5017-b14fb4326a5e.png)

システム環境変数のPATHにC:\ffmpeg-20200424-a501947-win64-static\binを追加します。

システム環境変数を編集したらAnacondaを再起動します。

fountain.movをtarget_back.movに名前を変更し、下記コマンドを実行します。

~~~
$ cd sample_video
$ ffmpeg -i teaser.mov input/%04d_img.png -hide_banner
$ ffmpeg -i target_back.mov background/%04d.png -hide_banner
~~~

inputフォルダに対して、セグメンテーション（マスク画像生成）を行います。

~~~
$ cd ../
$ python test_segmentation_deeplab.py -i sample_video/input
~~~

下記を実行し、補正します。

~~~
$ python test_pre_process_video.py -i sample_video/input -v_name sample_video/teaser_back.png
~~~

下記を実行し、結果を見てみましょう。

~~~
$ python test_background-matting_image.py -m real-hand-held -i sample_video/input/ -o sample_video/output/ -tb sample_video/background/
~~~

結果のフレームをffmpegを用いて動画にします。

~~~
$ cd sample_video
$ ffmpeg -r 60 -f image2 -i output/%04d_matte.png -vcodec libx264 -crf 15 -s 1280x720 -pix_fmt yuv420p teaser_matte.mp4
$ ffmpeg -r 60 -f image2 -i output/%04d_compose.png -vcodec libx264 -crf 15 -s 1280x720 -pix_fmt yuv420p teaser_compose.mp4
~~~

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">teaser_matte.mp4 <a href="https://t.co/PQCMWo5K1n">pic.twitter.com/PQCMWo5K1n</a></p>&mdash; 藤本賢志(ガチ本)@pixivFANBOXはじめました (@sotongshi) <a href="https://twitter.com/sotongshi/status/1254431876288143360?ref_src=twsrc%5Etfw">April 26, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

sample_video_fixedについても同様に行います。inputフォルダとbackgroundフォルダを作成、ffmpegでフレームを抽出します。

~~~
$ cd sample_video_fixed
$ ffmpeg -i teaser.mov input/%04d_img.png -hide_banner
$ ffmpeg -i target_back.mov background/%04d.png -hide_banner
~~~

inputフォルダに対して、セグメンテーション（マスク画像生成）を行います。

~~~
$ cd ../
$ python test_segmentation_deeplab.py -i sample_video_fixed/input
~~~

sample_video_fixedについては補正は必要ありません。

下記を実行し、結果を見てみましょう。

~~~
$ python test_background-matting_image.py -m real-fixed-cam -i sample_video_fixed/input/ -o sample_video_fixed/output/ -tb sample_video_fixed/background/ -b sample_video_fixed/teaser_back.png
~~~

結果のフレームをffmpegを用いて動画にします。

~~~
$ cd sample_video_fixed
$ ffmpeg -r 60 -f image2 -i output/%04d_matte.png -vcodec libx264 -crf 15 -s 1280x720 -pix_fmt yuv420p teaser_matte.mp4
$ ffmpeg -r 60 -f image2 -i output/%04d_compose.png -vcodec libx264 -crf 15 -s 1280x720 -pix_fmt yuv420p teaser_compose.mp4
~~~

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">sample_video_fixed teaser_matte.mp4 <a href="https://t.co/HGRoMUhpQA">pic.twitter.com/HGRoMUhpQA</a></p>&mdash; 藤本賢志(ガチ本)@pixivFANBOXはじめました (@sotongshi) <a href="https://twitter.com/sotongshi/status/1254438418559283200?ref_src=twsrc%5Etfw">April 26, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

お疲れ様でした。