本文主要應用deepface的正面(frontal)人臉檢測的預設模型,使用analyze
函數,用於分析一張人臉圖像的情感(emotion)。
在Colab上實現,若用其他平台需稍微修改程式碼。
Deepface是一個輕量級的Python人臉辨識和臉部屬性分析(年齡、性別、情緒和種族)框架。它是一個混合人臉辨識框架,包含最先進的模型:VGG-Face、Google FaceNet、OpenFace、Facebook DeepFace、DeepID、ArcFace和DlibSFace。
Deepface是完全開源的程式碼,可以應用於個人及商業的環境並加以修改,且無任何侵權的疑慮。
本文實驗結果圖
NotoSansTC-Bold.ttf
,且路徑正確。haarcascade_frontalface_default.xml
需要在正確的路徑下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'])
先判斷 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
x:
文字的起始橫座標。y:
文字的起始縱座標。text:
要加入的文字內容。size:
文字的大小,預設為 20。color:
文字的顏色,以 RGB 格式表示,預設為白色 (255, 255, 255)。img:
一個全域變數,代表圖像。這裡的函式假設 img 已經被定義並且可被修改。修改後的圖像將被存回這個全域變數。font_path:
字型文件的路徑,這裡使用 "./NotoSansTC-Bold.ttf"
。你可能需要根據你的系統或文件結構調整路徑。font:
使用 ImageFont.truetype
從指定的字型文件中創建字型物件,並指定字型大小。imgPil:
使用 Image.fromarray
將 Numpy 陣列 (這裡是 img) 轉換為 PIL 影像物件。draw:
使用 ImageDraw.Draw
定義一個可以在圖像上繪製的物件。draw.text:
在圖像上的指定位置 ((x, y)) 繪製指定的文字 (text),使用指定的顏色 (fill=color) 和字型 (font=font)。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'])