情绪辨识与年龄侦测
这篇教学会介绍使用 OpenCV,搭配 Deepface 第三方函数库,实作侦测人脸后,即时辨识出该人脸的情绪反应 ( 喜怒哀乐...等 ),以及即推估这个人脸的年龄 ( 甚至可以侦测该人脸的性别和人种 )。
快速导览:
因为程序中的 OpenCV 会需要使用镜头或 GPU,所以请使用本机环境 ( 参考:使用 Python 虚拟环境 ) 或使用 Anaconda Jupyter 进行实作 ( 参考:使用 Anaconda ) ,并安装 OpenCV 函数库 ( 参考:OpenCV 函数库 )。
安装 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()
情绪辨识
完成后,修改程序码,在 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()
年龄、性别、人种侦测
修改 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[0]['dominant_emotion'])
print(age[0]['age'])
print(race[0]['dominant_race'])
print(gender[0]['gender'])
except:
pass
cv2.imshow('oxxostudio', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
辨识多张脸的情绪
如果图像中有“多张脸”,可以先透过“人脸侦测”的方式节取出有人脸的范围,再将该范围的图像进行情绪辨识 ( 参考“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[0]['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()
即时辨识,在画面中显示情绪
参考“读取并播放影片”文章,搭配“使用中文字型”的方法,就能透过摄影镜头即时侦测情绪反应,并将侦测到的情绪显示在画面中。
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[0]['dominant_emotion'] # 取得情緒文字
putText(0,40,emotion) # 放入文字
except:
pass
cv2.imshow('oxxostudio', img)
if cv2.waitKey(5) == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
微信扫码关注
抖音扫码关注