顔認識でマスクを付けてくれるWebアプリを作成しStreamlit Sharingで公開する


# 作ったもの
![happy-people.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320225/a53bf95d-b7cd-95de-e8f9-8ae0793b073d.jpeg)
みんな笑顔でとても楽しそうな良い写真ですね．
しかしこういう時期なのでマスクを付けてほしいところです．

そこで顔認識でマスクを付けてくれるWebアプリを作成しました．
https://share.streamlit.io/be4rr/put_mask/put_mask_streamlit.py

このリンクを開いて，この画像をアップロードすると...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320225/6efb3f9c-be80-6af7-0107-3bd9204ae91a.png)
みんなにマスクを付けてあげることができました🎉
これで安心ですね．

Webアプリ全体のプログラムをGitHubに上げています．
https://github.com/Be4rR/put_mask

# 使ったもの
主に次のようなPythonライブラリやサービスを利用しました．
- [Streamlit](https://www.streamlit.io/) 
- [Streamlit Sharing](https://www.streamlit.io/sharing)
- [MTCNN](https://github.com/ipazc/mtcnn)

StreamlitはPythonを使って素早く簡単にWebアプリを作成できるライブラリです．特にデータ分析や機械学習のWebアプリを作るのに向いています．

Streamlit SharingはStreamlitを使って作成したWebアプリを簡単にデプロイできるサービスです．現状では誰でもすぐに使い始められるわけではないようですが，すごく便利です．

MTCNNはDeep Learningを使った顔認識がお手軽にできるPythonライブラリです．

# プログラム

https://github.com/Be4rR/put_mask/blob/master/put_mask_streamlit.py

```put_mask_streamlit.py 
import numpy as np
import streamlit as st
from mtcnn import MTCNN
from PIL import Image, ImageDraw

st.title("Pythonで顔認識してマスクを付けさせる")

# 画像ファイルをアップロードするためのウィジェット
imgfile = st.file_uploader("Upload Image", type=["png", "jpg"], accept_multiple_files=False)

# 画像ファイルがアップロードされていなければ何もしない
if imgfile is not None:    
    img = Image.open(imgfile)
    
    # マスクのイラストの画像
    mask = Image.open("mask.png")
    
    # 元の画像を表示
    st.write("元の画像")
    st.image(img, use_column_width=True)

    # 画像に写っている顔を検出する
    detector = MTCNN()  
    # 検出された顔ごとに，顔のBounding Box，顔である確率，目や鼻などのKeypointsが得られる． 
    results = detector.detect_faces(np.asarray(img))

    for result in results:
        # 顔である確率
        confidence = result["confidence"]
        
        # 顔である確率が90%以下ならスルー
        if confidence < 0.9:
            continue
        
        # 顔のBounding Box
        x, y, w, h = result["box"]
        
        # マスクの画像を顔のサイズに合わせる．
        mask_resized = mask.resize((w, h//2)) 
        
        # マスクの画像を，検出された顔に貼り付ける．       
        img.paste(mask_resized, (x, y+h//2), mask_resized.convert("RGBA"))
        
    pil_img = Image.fromarray(np.uint8(img))
    
    st.write("マスクを付けた画像")
    st.image(pil_img, use_column_width=True)
```

MTCNNの使い方についてはGitHubに書かれています．
https://github.com/ipazc/mtcnn

# Streamlit Sharingでデプロイするときのメモ
どちらかというとこっちが本題です．これはあくまでもメモ程度なので，実際に行う場合は公式の説明を見てください．
https://docs.streamlit.io/en/stable/deploy_streamlit_app.html

最初に述べたように[Streamlit Sharing](https://www.streamlit.io/sharing)は誰でもすぐに使えるというわけではないようです．Streamlit Sharingのページに書いてあるように，リクエストを送って招待を待つ必要があります．自分の場合はリクエストを送ってから３日後くらいに使えるようになりました．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320225/b4f61ed1-8945-8fd1-4f35-28b6a25fae6b.png)

次に必要なファイルについてです．実際のファイルはGitHubにあるので参考にしてください．
https://github.com/Be4rR/put_mask/

まず当然ですがStreamlitのプログラムが必要です．
https://github.com/Be4rR/put_mask/blob/master/put_mask_streamlit.py

２つ目にpipでインストールするライブラリが書かれている`requirements.txt`です．公式の説明では`pipreqs`というツールを使っていますが，日本語の処理でエラーが出たので今回は使っていません．通常通り`pip freeze`で作成しました．

```sh
pip freeze > requirements.txt
```
また，自分のPC環境はWindowsなのでデプロイした際に`pywin32`に関するエラーが出ましたが，`pywin32`をコメントアウトして回避しました．
https://discuss.streamlit.io/t/problem-with-heroku-on-windows-requirement-pywin32-227/2722

最後に`apt-get`でインストールするものを書いた`packages.txt`です．
https://github.com/Be4rR/put_mask/blob/master/packages.txt

今回利用したMTCNNでは内部でOpenCVを使っています．そのため次のパッケージが必要になります．

```packages.txt
freeglut3-dev
libgtk2.0-dev
```
https://discuss.streamlit.io/t/importerror-libgl-so-1-cannot-open-shared-object-file-no-such-file-or-directory-opencv-error/7031

# おわりに
デプロイで少し試行錯誤しましたが，それでも簡単にWebアプリを作って簡単に公開できました．Streamlit Sharingには「１アカウントにつきアプリ３つまで公開できる」などの制限はあるようですが，それでも面白いものがたくさん作れそうです．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320225/4befb86e-c8e5-2c06-90c3-41c063664a0c.png)