iT邦幫忙

2022 iThome 鐵人賽

DAY 12
2

這篇教學會介紹使用 OpenCV,搭配 Deepface 第三方函式庫,實作偵測人臉後,即時辨識出該人臉的情緒反應 ( 喜怒哀樂...等 ),以及即推估這個人臉的年齡 ( 甚至可以偵測該人臉的性別和人種 )。

原文參考:情緒辨識與年齡偵測

因為程式中的 OpenCV 會需要使用鏡頭或 GPU,所以請使用本機環境 ( 參考:使用 Python 虛擬環境 ) 或使用 Anaconda Jupyter 進行實作 ( 參考:使用 Anaconda ) ,並安裝 OpenCV 函式庫 ( 參考:OpenCV 函式庫 )。

https://ithelp.ithome.com.tw/upload/images/20220923/20091306eH7WMF5Opj.jpg

安裝 Deepface 函式庫

Deepface 函式庫是由 Facebook AI research group 所研發,並於 2015 年開源,是一套非常完整且容易使用的臉部識別與特徵分析函式庫,Deepface 是使用 Tensorflow 和 Keras 搭配 Python 所開發,只需要輸入指令就能安裝:

pip install deepface

使用 Deepface 函式庫

如果是第一次使用 Deepface 函式庫,可先執行下方的程式碼 ( 圖片請搜尋一張人臉的圖片 ),執行後會額外下載一些人臉訓練的模型 ( 檔案大小總共可能快 2G ),下載後應該就能看到出現分析的參數,Deepface 分析的參數包含了情緒 ( emotion )、年齡 ( age )、性別 ( gender ) 和人種 ( race )

使用時記得加上 try 和 except,避免偵測不到產生的錯誤導致程式中止。

import cv2
from deepface import DeepFace
import numpy as np

img = cv2.imread('test.jpg')     # 讀取圖片
try:
    analyze = DeepFace.analyze(img)  # 辨識圖片人臉資訊
    print(analyze)
except:
    pass

cv2.imshow('oxxostudio', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Python 教學 - 情緒辨識與年齡偵測

情緒辨識

完成後,修改程式碼,在 DeepFace.analyze 方法中添加 actions=['emotion'] 參數,再次執行程式,就會看見分析圖片中人臉情緒的結果,以蒙娜麗莎像為例,所偵測到的情緒百分之 93 是「中性 neutral」。

import cv2
from deepface import DeepFace
import numpy as np

img = cv2.imread('test.jpg')     # 讀取圖片
try:
    analyze = DeepFace.analyze(img, actions=['emotion'] )  # 辨識圖片人臉資訊,取出情緒資訊
    print(analyze)
except:
    pass

cv2.imshow('oxxostudio', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Python 教學 - 情緒辨識與年齡偵測

年齡、性別、人種偵測

修改 actions 參數,就能讀取年齡、人種與性別,下方的程式碼執行後,會印出蒙娜麗莎的相關分析資訊 ( 滿有趣的是分析出來蒙娜麗莎的性別是男性,好像符合「蒙娜麗莎是達文西自畫像」的傳說 )。

import cv2
from deepface import DeepFace
import numpy as np

img = cv2.imread('mona.jpg')
try:
    emotion = DeepFace.analyze(img, actions=['emotion'])  # 情緒
    age = DeepFace.analyze(img, actions=['age'])          # 年齡
    race = DeepFace.analyze(img, actions=['race'])        # 人種
    gender = DeepFace.analyze(img, actions=['gender'])    # 性別

    print(emotion['dominant_emotion'])
    print(age['age'])
    print(race['dominant_race'])
    print(gender['gender'])
except:
    pass

cv2.imshow('oxxostudio', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Python 教學 - 情緒辨識與年齡偵測

辨識多張臉的情緒

如果影像中有「多張臉」,可以先透過「人臉偵測」的方式節取出有人臉的範圍,再將該範圍的影像進行情緒辨識 ( 參考「OpenCV 人臉偵測」 ),詳細說明寫在下方程式碼中:

import cv2
from deepface import DeepFace
import numpy as np
from PIL import ImageFont, ImageDraw, Image

# 定義該情緒的中文字
text_obj={
    'angry': '生氣',
    'disgust': '噁心',
    'fear': '害怕',
    'happy': '開心',
    'sad': '難過',
    'surprise': '驚訝',
    'neutral': '正常'
}

# 定義加入文字函式
def putText(x,y,text,size=70,color=(255,255,255)):
    global img
    fontpath = 'NotoSansTC-Regular.otf'            # 字型
    font = ImageFont.truetype(fontpath, size)      # 定義字型與文字大小
    imgPil = Image.fromarray(img)                  # 轉換成 PIL 影像物件
    draw = ImageDraw.Draw(imgPil)                  # 定義繪圖物件
    draw.text((x, y), text, fill=color, font=font) # 加入文字
    img = np.array(imgPil)                         # 轉換成 np.array

img = cv2.imread('emotion.jpg')                    # 載入圖片
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)       # 將圖片轉成灰階

face_cascade = cv2.CascadeClassifier("xml/haarcascade_frontalface_default.xml")   # 載入人臉模型
faces = face_cascade.detectMultiScale(gray)        # 偵測人臉

for (x, y, w, h) in faces:
    # 擴大偵測範圍,避免無法辨識情緒
    x1 = x-60
    x2 = x+w+60
    y1 = y-20
    y2 = y+h+60
    face = img[x1:x2, y1:y2]  # 取出人臉範圍
    try:
        emotion = DeepFace.analyze(face, actions=['emotion'])  # 辨識情緒
        putText(x,y,text_obj[emotion['dominant_emotion']])     # 放入文字
    except:
        pass
    cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 5)    # 利用 for 迴圈,抓取每個人臉屬性,繪製方框

cv2.imshow('oxxostudio', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

Python 教學 - 情緒辨識與年齡偵測

即時辨識,在畫面中顯示情緒

參考「讀取並播放影片」文章,搭配「使用中文字型」的方法,就能透過攝影鏡頭即時偵測情緒反應,並將偵測到的情緒顯示在畫面中。

import cv2
from deepface import DeepFace
import numpy as np
from PIL import ImageFont, ImageDraw, Image

# 定義該情緒的中文字
text_obj={
    'angry': '生氣',
    'disgust': '噁心',
    'fear': '害怕',
    'happy': '開心',
    'sad': '難過',
    'surprise': '驚訝',
    'neutral': '正常'
}

# 定義加入文字函式
def putText(x,y,text,size=50,color=(255,255,255)):
    global img
    fontpath = 'NotoSansTC-Regular.otf'            # 字型
    font = ImageFont.truetype(fontpath, size)      # 定義字型與文字大小
    imgPil = Image.fromarray(img)                  # 轉換成 PIL 影像物件
    draw = ImageDraw.Draw(imgPil)                  # 定義繪圖物件
    draw.text((x, y), text_obj[text], fill=color, font=font) # 加入文字
    img = np.array(imgPil)                         # 轉換成 np.array

cap = cv2.VideoCapture(0)

if not cap.isOpened():
    print("Cannot open camera")
    exit()
while True:
    ret, frame = cap.read()
    if not ret:
        print("Cannot receive frame")
        break
    img = cv2.resize(frame,(384,240))
    try:
        analyze = DeepFace.analyze(img, actions=['emotion'])
        emotion = analyze['dominant_emotion']  # 取得情緒文字
        putText(0,40,emotion)                  # 放入文字
    except:
        pass
    cv2.imshow('oxxostudio', img)
    if cv2.waitKey(5) == ord('q'):
        break
cap.release()
cv2.destroyAllWindows()

Python 教學 - 情緒辨識與年齡偵測

更多 Python 教學

大家好,我是 OXXO,是個即將邁入中年的斜槓青年,我已經寫了超過 400 篇 Python 的教學,有興趣可以參考下方連結呦~ ^_^


上一篇
( Day 11 ) OpenCV 追蹤並標記特定顏色
下一篇
( Day 13 ) 辨識微笑,拍照儲存
系列文
Python x AI 影像辨識好好玩32
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
SK.
iT邦新手 5 級 ‧ 2024-05-31 17:14:32

提醒!在分辨年齡、性別、人種偵測的程式無法print出來
要寫成以下這樣才能使用(目前還不知道為什麼)
使用:jupyter notebook

import cv2
from deepface import DeepFace
import numpy as np

img = cv2.imread('bomb.jpg')
try:
    emotion = DeepFace.analyze(img, actions=['emotion'])  # 情緒
    age = DeepFace.analyze(img, actions=['age'])          # 年齡
    race = DeepFace.analyze(img, actions=['race'])        # 人種
    gender = DeepFace.analyze(img, actions=['gender'])    # 性別

    print(emotion[0]['dominant_emotion']) #修改
    print(age[0]['age'])                  #修改
    print(race[0]['dominant_race'])       #修改
    print(gender[0]['dominant_gender'])   #修改
except:
    print("print failed.")
    pass

cv2.imshow('bomb', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

我要留言

立即登入留言