気付かないうちに、怖い顔になっていませんか。それとも、ニヤニヤしすぎていませんか。AIに客観的に評価してもらいましょう!

原理

パソコンに内蔵カメラもしくはUSBでつないだwebカメラを使って顔を撮影し、分析して怒り、むかつき、恐怖、幸せ、悲しい、驚き、中性で評価します。
ドキュメントが多いので人をやりましたが、次は犬の表情をやりたいです!pythonを使っていますが、pythonを使うまでのパソコンの環境設定がめんどくさいです。動かないパソコンもたぶんあると思います。どうしても1クリック化(exe化)できませんでした。できる人教えてください。
中身は、tensorflowと表情学習済みモデルを使用しています。
https://arxiv.org/abs/1710.07557

使い方

1. 後述の方法で起動する。
2. 写真・結果の保存先を選択。必要に応じて撮影間隔・撮影時間・獣医師名・患者名を修正。
3.解析開始を押す。撮影時間が経過後も解析が行われているのでそのまましばらく待つ。
4.解析結果の画面が出てきます。
5.さきほど選択した保存フォルダに、写真と結果がエクセル形式で保存されています。

初回の起動方法

1.以下のファイルをコピペして作って下さい。

from tkinter import *
from tkinter import ttk
import tkinter
import cv2
import os
import time
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import numpy as np
from keras.models import load_model
from keras.preprocessing.image import ImageDataGenerator
from keras.preprocessing import image
import glob
import openpyxl
import datetime
from tkinter import filedialog

# not to show an error message related to CPU
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

# close the tinker window
def _destroyWindow():
    root.quit()
    root.destroy()
    
def askfileplace():
    cd =  filedialog.askdirectory() # ask which directly to use for saving image and excel    
    path.set(cd)

def resource_path(relative_path):
    try:
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.dirname(__file__)
    return os.path.join(base_path, relative_path)
    
# create the function which will be used for pressing botten
def save_frame_camera_key(device_num,interval1,duration1,vetname1,name1,path1):

    os.makedirs("{}//{}_{}".format(path1,vetname1,name1)) # create a folder to save above
    cap = cv2.VideoCapture(device_num) #create a videocapture object    

    if not cap.isOpened():  # check if it has been opened
        return

    n = 0 # increment initiated with 1
    while n <= int(duration1)/int(interval1) :  # calculation of the terminating point of the increment 

        ret, frame = cap.read() # read the object which returens two variables
        # cv2.imshow("Analyzing emotion", frame) # show the window
        cv2.imwrite("{}//{}_{}//{}.jpg".format(path1,vetname1,name1,n), frame) # save the pictures
        time.sleep(int(interval1)) # wait for interval
        n += 1 # increment
        
    # cv2.destroyWindow("Analyzing emotion") # after the while snipet, close the window

    image_paths = glob.glob("{}//{}_{}//*.jpg".format(path1,vetname1,name1)) # get the jpg files in the folder
    
    result=[] # create a list for stucking the results

    for image_path in image_paths: # process each file in the jpg files
        img = image.load_img(image_path, color_mode="grayscale" , target_size=(64, 64)) # convert it to grayscale
        img_array = image.img_to_array(img) # convert it to array
        pImg = np.expand_dims(img_array, axis=0) / 255 # make it between 0 ~ 1
        
        # read the face recognision trained model hdf5
        model_path = resource_path(".//fer2013_mini_XCEPTION.110-0.65.hdf5")
        emotions_XCEPTION = load_model(model_path, compile=False)
        
        prediction = emotions_XCEPTION.predict(pImg)[0] # predict a image using the model
        result.append(prediction) # append the result to the list named result
    
    df = pd.DataFrame(result) # convert it to DataFrame
    df.columns=['angry','disgust','fear','happy','sad','surprise','neutral'] # name the columns
    df = pd.concat([df,pd.DataFrame(df.mean(axis=0),columns=['Mean']).T]) # create a mean row on the bottom
    df.to_excel("{}//{}_{}//result.xlsx".format(path1,vetname1,name1), sheet_name='result') # save a excel file
    
    # create a graph using mtplotlib
    fig = plt.figure() # create object
    ax=fig.add_subplot(1,1,1) # create subplot indicating the place of the subplot
    mycolor = ["#ff0033", "#cc99ff", "#ffff66", "#ff9999", "#6699ff", "#ff9966", "#99ffcc"] # create a list for color
    ax.pie(df.tail(1).values[0],labels=df.columns,counterclock=True, startangle=90, autopct="%1.1f%%",colors=mycolor) # create piechart
    centre_circle = plt.Circle((0,0),0.7,color='white', fc='white',linewidth=1.25) # make it donuts shape
    fig = plt.gcf() #get current figure
    fig.gca().add_artist(centre_circle) # get the current axes and cover the white donuts on the pie chart

    # Create new window by Tkinter Class
    root = tkinter.Tk()
    root.title("表情分析結果")
    root.withdraw()
    root.protocol('WM_DELETE_WINDOW', _destroyWindow)  # When you close the tkinter window.

    # Canvas and put the figure to the canvas
    canvas = FigureCanvasTkAgg(fig, master=root)  # Generate canvas instance, Embedding fig in root
    canvas.draw()
    canvas.get_tk_widget().pack() #canvas._tkcanvas.pack()
    root.update()
    root.deiconify()  

# create interface
root = Tk()
root.title('表情評価ツール')
root.resizable(True, True)

#create text
frame1 = ttk.Frame(root, padding=(32))
frame1.grid()

label1 = ttk.Label(frame1, text='撮影間隔(秒)', padding=(5, 2))
label1.grid(row=0, column=0, sticky=E)

label2 = ttk.Label(frame1, text='撮影時間(秒)', padding=(5, 2))
label2.grid(row=1, column=0, sticky=E)

label3 = ttk.Label(frame1, text='獣医師名(英数字のみ)', padding=(5, 2))
label3.grid(row=2, column=0, sticky=E)

label4 = ttk.Label(frame1, text='患者名(英数字のみ)', padding=(5, 2))
label4.grid(row=3, column=0, sticky=E)

label5 = ttk.Label(frame1, text='写真・結果の保存先', padding=(5, 2))
label5.grid(row=4, column=0, sticky=E)

# create textboxes
interval = StringVar()
interval_entry = ttk.Entry(
    frame1,
    textvariable=interval,
    width=20)
interval_entry.insert(0,"2")
interval_entry.grid(row=0, column=1)

duration = StringVar()
duration_entry = ttk.Entry(
    frame1,
    textvariable=duration,
    width=20)
duration_entry.insert(0,"10")
duration_entry.grid(row=1, column=1)

vetname = StringVar()
vetname_entry = ttk.Entry(
    frame1,
    textvariable=vetname,
    width=20)
vetname_entry.insert(0,"vet")
vetname_entry.grid(row=2, column=1)

name = StringVar()
name_entry = ttk.Entry(
    frame1,
    textvariable=name,
    width=20)
name_entry.insert(0,datetime.datetime.now().strftime("%Y%m%d_%H%M")) # time
name_entry.grid(row=3, column=1)

path =StringVar()
path_entry = ttk.Entry(
    frame1,
    textvariable=path,
    width=20)
path_entry.grid(row=4, column=1)

path_button = ttk.Button(frame1,text="フォルダ選択",command= lambda : [askfileplace()] )
path_button.grid(row=4, column=2)

# create bottens
frame2 = ttk.Frame(frame1, padding=(0, 5))
frame2.grid(row=5, column=1, sticky=W)

button1 = ttk.Button(
    frame2, text='解析開始',
    command= lambda : [save_frame_camera_key(0,interval.get(),duration.get(),vetname.get(),name.get(),path.get())]) # read the function I made
button1.pack(side=LEFT)

button2 = ttk.Button(frame2, text='終了', command=quit)
button2.pack(side=LEFT)


root.mainloop()

2.githubにアクセスして、fer2013_mini_XCEPTION.110-0.65.hdf5というファイルを、さきほどのpythonファイルと同じ場所に保存してください。
https://github.com/oarriaga/face_classification/tree/master/trained_models/emotion_models
Author: Octavio Arriaga. Thank you very much for your splendid work!

3.Anacondaのコマンドプロンプトを起動します。Macはターミナル。

4.必要なパッケージをダウンロードします。tensorflow使うためには、pythonのバージョンを落とさなければなりません。3.8ではtensorflowを使えません。3.6にしましょう!!

conda create -n face python=3.6.10
proceed ([y]/n)? → y
activate face
pip install opencv-python
pip install pandas
pip install matplotlib
pip install openpyxl
pip install tensorflow
pip install keras

Mac: Terminalで以下を順番にコピペし、1つづつEnterを押していく。
conda create -n face python=3.6.10 anaconda
proceed ([y]/n)? → y
conda activate face
pip install opencv-python
pip install pandas
pip install matplotlib
pip install openpyxl
pip install tensorflow
pip install keras

5.python face.py で実行してください。

Categories:

category