😁

[streamlit]表情判定アプリを作ろう(クラウドサービス使わない)

2022/08/07に公開

はじめに

これまで機械学習などをテーマにstreamlitを試してきましたが、もう少し肩の力を抜いたギミック的なこともしたいなと思い今回は表情判定WEBアプリを作ります。
streamlitで表情解析となると王道となるのはクラウドサービスのAPIを用いるパターンだと思いますが、ここではpy-featと言うライブラリを用いてローカルだけで完結させますので気軽に試せるのではないかなと思います。

参考)py-feat

顔画像を入力すると、"anger", "disgust", "fear", "happiness", "sadness", "surprise", "neutral"といった表情の予測スコアを返すライブラリです。
https://py-feat.org/pages/intro.html

アプリイメージ


画像のアップロード、PCカメラの撮影どちらでも可能です


カメラを選ぶとPCのカメラが起動します


判定画面(ここ、デザイン全く凝っていません・・・表示するだけ)

実装

Dockerで環境を構築します。おおよその流れは以前の記事の通りです。
https://zenn.dev/littledarwin/articles/8b5372e2f2c249

今回用いるファイル類はこちらに格納しました。
https://github.com/LittleDarwin2021/streamlit_face_emotion

Dockerfile

ここがいきなりのつまずきポイントでした。プログラム中でOpenCVが用いられている関係でlibgl1-mesa-devのインストールが必要とのことです。

Dockerfile
# Dockerfile
FROM python:3

COPY requirements.txt .

RUN pip3 install --upgrade pip && \
    pip3 install --no-cache-dir -r requirements.txt && \
    apt-get update && apt-get upgrade -y && \
    apt-get install -y libgl1-mesa-dev

WORKDIR /src
COPY /src /src

docker-compose.yml

特に工夫はありません

docker-compose.yml
version: '3'
services:

  streamlit:
    restart: always
    build: 
      context: .
      dockerfile: Dockerfile
    container_name: streamlit
    working_dir: '/src'
    tty: true
    volumes: 
      - ./src:/src
    ports: 
      - '8501:8501'
    command: streamlit run app.py

app.py

今回はシンプルに感情予測を返すだけにしていますが、py-featは色んなことができますので途中の記述は用途に応じて書き換えてください。

app.py
#ライブラリのインポート
import streamlit as st
import pandas as pd
import numpy as np
import cv2
import numpy as np
import pandas as pd
import re
import os
import matplotlib.pyplot as plt
from PIL import Image


#py-featでモデルを構築する。色々いじる余地があるので公式ドキュメント参照
from feat import Detector
face_model = "retinaface"
landmark_model = "mobilenet"
au_model = "svm"
emotion_model = "resmasknet"
detector = Detector(
    face_model=face_model,
    landmark_model=landmark_model,
    au_model=au_model,
    emotion_model=emotion_model
)
from feat.utils import get_test_data_path


#本編  
st.title("Face emotion app")

#画像アップロードかカメラを選択するようにする。
img_source = st.radio("画像のソースを選択してください。",
                              ("画像をアップロード", "カメラで撮影"))
if img_source == "カメラで撮影":
  img_file_buffer = st.camera_input("カメラで撮影")
elif img_source == "画像をアップロード":
  img_file_buffer = st.file_uploader("ファイルを選択")
else:
    pass


#どちらを選択しても後続の処理は同じ
if img_file_buffer :
  img_file_buffer_2 = Image.open(img_file_buffer)
  img_file = np.array(img_file_buffer_2)
  cv2.imwrite('temporary.jpg', img_file)
  
  #py-featの表情解析結果をデータフレーム形式でimage_predictionとする
  image_prediction = detector.detect_image("temporary.jpg")
  
  #感情に関するカラムだけを残す
  image_prediction = image_prediction[["anger", "disgust", "fear", "happiness", "sadness", "surprise", "neutral"]]
  
  #感情の最大値を示すデータのカラム名(感情名)をemotionとする
  emotion = image_prediction.idxmax(axis = 1)[0]

  st.markdown("#### あなたの表情は")
  st.markdown("### {}です".format(emotion))
  

Dockerに環境ができたらブラウザでhttp://localhost:8501にアクセスするとAppが起動します。

おわりに

以上、streamlitを用いた簡単な表情分析アプリでした。とりあえずの実装を趣旨としたものであり推定精度については言及しませんでしたが、「neutral」と「happiness」はある程度正確に判別できているように思うので、笑顔判定器くらいであれば使えるかと思います。

Discussion