2024-01-16|閱讀時間 ‧ 約 33 分鐘

[Python][人臉辨識]應用Deepface辨識臉部情緒

本文主要應用deepface的正面(frontal)人臉檢測的預設模型,使用analyze 函數,用於分析一張人臉圖像的情感(emotion)。

在Colab上實現,若用其他平台需稍微修改程式碼。

Deepface

Deepface是一個輕量級的Python人臉辨識和臉部屬性分析(年齡、性別、情緒和種族)框架。它是一個混合人臉辨識框架,包含最先進的模型:VGG-Face、Google FaceNet、OpenFace、Facebook DeepFace、DeepID、ArcFace和DlibSFace。

Deepface是完全開源的程式碼,可以應用於個人及商業的環境並加以修改,且無任何侵權的疑慮。

github開源碼與其他模型參考網址


本文實驗結果圖

結果圖

程式範例及檔案與模型連結

在colab上,上傳檔案

  • 請確保存在相應的字體文件 NotoSansTC-Bold.ttf,且路徑正確。
  • Haar 級聯分類器 haarcascade_frontalface_default.xml 需要在正確的路徑下

colab上傳檔案

程式碼

import cv2
from deepface import DeepFace
import numpy as np

from google.colab.patches import cv2_imshow # 若是在非colab環境,請註解掉from PIL import Image,ImageFont, ImageDraw
from IPython.display import display
# 定義該情緒的中文字
text_obj={
'angry': '生氣',
'disgust': '噁心',
'fear': '害怕',
'happy': '開心',
'sad': '難過',
'surprise': '驚訝',
'neutral': '正常'
}

# 定義加入文字函式
def putText(x,y,text,size=20,color=(255,255,255)):
global img

font_path = "./NotoSansTC-Bold.ttf" # Adjust the font path if needed
font = ImageFont.truetype(font_path, 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('1234.jpg') # 載入圖片
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 將圖片轉成灰階
face_cascade = cv2.CascadeClassifier("./haarcascade_frontalface_default.xml") # 載入人臉模型
faces = face_cascade.detectMultiScale(gray) # 偵測人臉

for (x, y, w, h) in faces:
# 擴大偵測範圍,避免無法辨識情緒
x1 = x
x2 = x+w
y1 = y
y2 = y+h
face = img[y1:y2, x1:x2] # 取出人臉範圍
try:
emotion_result = DeepFace.analyze(face, actions=['emotion'],enforce_detection=False) # 辨識情緒
dominant_emotion = emotion_result[0]['dominant_emotion'] if emotion_result and 'dominant_emotion' in emotion_result[0] else None #避開錯誤,確保dominant_emotion一定回傳值

if dominant_emotion:
putText(x, y, text_obj[dominant_emotion]) # 放入文字
else:
print('Dominant emotion not found in the result.')

except Exception as e:
print(f'error : {e}')
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2) # 利用 for 迴圈,抓取每個人臉屬性,繪製方框

cv2_imshow(img) #若是在非colab環境 請更改cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

程式碼解析

印出emotion_result來解析

在使用別人訓練好的模型及函式,都會先試著印出來看後續要怎麼處理得到的資料

print的第一行:可以得知是 emotion_result 一個list       

print的第二行:得知是一個list內含有字典       

print的第三行:既然知道是字典就來看所有key有包含哪些       

print的第四行:看起來'dominant_emotion'的值是預估情緒的結果       

將emotion_result[0]['dominant_emotion']印出,看起來得到想要的結果了

emotion_result  = DeepFace.analyze(face, actions=['emotion'],enforce_detection=False)  # 辨識情緒
print('emotion_result: 資料格式為',type(emotion_result))
print('emotion_result: 資料為',emotion_result)
print('emotion_result_dit 所有鍵為' ,emotion_result[0].keys())
print('emotion_result: 資料為: ',emotion_result[0]['dominant_emotion'])

避開錯誤,確保dominant_emotion一定回傳值

先判斷 emotion_result不為空值,在判斷emotion_result[0]是否有'dominant_emotion'這個key,兩個條件都滿足回傳emotion_result[0]['dominant_emotion'],不滿足回傳空值

dominant_emotion = emotion_result[0]['dominant_emotion'] if emotion_result and 'dominant_emotion' in emotion_result[0] else None

這個寫法主要確保emotion_result[0]['dominant_emotion']存在,在去提取,避免引發錯誤,程式就不會往下執行

圖像寫入文字函式

def putText(x,y,text,size=20,color=(255,255,255)):
global img

font_path = "./NotoSansTC-Bold.ttf" # Adjust the font path if needed
font = ImageFont.truetype(font_path, 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
  1. 參數說明:
    • x: 文字的起始橫座標。
    • y: 文字的起始縱座標。
    • text: 要加入的文字內容。
    • size: 文字的大小,預設為 20。
    • color: 文字的顏色,以 RGB 格式表示,預設為白色 (255, 255, 255)。
  2. 全域變數:
    • img: 一個全域變數,代表圖像。這裡的函式假設 img 已經被定義並且可被修改。修改後的圖像將被存回這個全域變數。
  3. 字型設定:
    • font_path: 字型文件的路徑,這裡使用 "./NotoSansTC-Bold.ttf"。你可能需要根據你的系統或文件結構調整路徑。
    • font: 使用 ImageFont.truetype 從指定的字型文件中創建字型物件,並指定字型大小。
  4. 圖像轉換:
    • imgPil: 使用 Image.fromarray 將 Numpy 陣列 (這裡是 img) 轉換為 PIL 影像物件。
    • draw: 使用 ImageDraw.Draw 定義一個可以在圖像上繪製的物件。
  5. 文字繪製:
    • draw.text: 在圖像上的指定位置 ((x, y)) 繪製指定的文字 (text),使用指定的顏色 (fill=color) 和字型 (font=font)。
  6. 圖像轉換回 Numpy 陣列:
    • img = np.array(imgPil): 最後,使用 np.array 將 PIL 影像物件轉換回 Numpy 陣列,這樣修改後的圖像就能夠儲存在 img 這個全域變數中。



其他預估

預估年紀

因預測的人臉有八個所以有八個結果

result = DeepFace.analyze("1234.jpg", actions=["age"])
# print("預估年紀:", result["age"])
for age in result:
print('預估年紀',result[0]['age'])

預估性別

result = DeepFace.analyze("1234.jpg", actions=["gender"])
for sex in result:
print('預估性別',sex['gender'])


喜歡的話,在點愛心,加入會員追蹤作者,會持續更新分享,謝謝大家




分享至
成為作者繼續創作的動力吧!
© 2024 vocus All rights reserved.