一、OpenCV表情识别介绍
OpenCV(Open Source Computer Vision Library)是一个广泛应用于计算机视觉任务的开源库,提供了丰富的图像处理和机器学习工具。表情识别则是计算机视觉领域的重要分支,旨在通过分析图像或视频中的人脸特征,判断出人物所表达的情感状态,如高兴、悲伤、愤怒、惊讶等。结合 OpenCV 进行表情识别,能借助其强大功能实现高效且准确的表情判断。
二、表情识别的基本原理
表情识别主要基于图像处理和机器学习技术。其基本流程可以分为以下几个步骤:
人脸检测:在图像或视频帧中定位出人脸的位置和大小。这是表情识别的基础,只有准确地检测到人脸,才能进行后续的表情分析。
特征提取:从检测到的人脸区域中提取出能够反映表情特征的信息,如眼睛、嘴巴等部位的形状和位置变化。常用的特征提取方法包括几何特征提取、纹理特征提取等。
表情分类:将提取到的特征输入到分类器中,根据预先训练好的模型判断人脸的表情类别,如高兴、悲伤、愤怒等。
三、代码实现
- 导入必要的库
python
import numpy as np
import dlib
import cv2
from sklearn.metrics.pairwise import euclidean_distances
from PIL import Image, ImageDraw, ImageFont
numpy:用于处理数值计算和数组操作。
dlib:一个强大的机器学习库,用于人脸检测和关键点定位。
cv2:OpenCV 库,用于计算机视觉任务,如读取视频帧、绘制图形等。
euclidean_distances:用于计算两点之间的欧几里得距离。
PIL(Python Imaging Library):用于处理图像,特别是在图像上添加中文文本。
- 定义函数计算嘴部纵横比(MAR)
python
def MAR(shape):
A = euclidean_distances(shape[50].reshape(1, 2), shape[58].reshape(1, 2))
B = euclidean_distances(shape[51].reshape(1, 2), shape[57].reshape(1, 2))
C = euclidean_distances(shape[52].reshape(1, 2), shape[56].reshape(1, 2))
D = euclidean_distances(shape[48].reshape(1, 2), shape[54].reshape(1, 2))
return ((A + B + C) / 3) / D
shape 是一个包含 68 个人脸关键点坐标的数组。
A、B、C 分别计算了嘴部垂直方向上三对关键点之间的欧几里得距离。
D 计算了嘴部水平方向上两个关键点之间的欧几里得距离。
最终返回的 MAR 值是垂直方向平均距离与水平方向距离的比值。
- 定义函数计算嘴宽与脸颊宽的比例(MJR)
python
def MJR(shape):
M = euclidean_distances(shape[48].reshape(1, 2), shape[54].reshape(1, 2)) # 嘴宽度
J = euclidean_distances(shape[3].reshape(1, 2), shape[13].reshape(1, 2)) # 下颌的宽度
return M / J
- 定义函数在图像上添加中文文本
python
def cv2AddchineseText(img, text, position, textcolor=(0, 255, 0), textSize=30):
if isinstance(img, np.ndarray):
img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
draw = ImageDraw.Draw(img)
fontStyle = ImageFont.truetype("simhei.ttf", textSize, encoding="utf-8")
draw.text(position, text, textcolor, font=fontStyle)
return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)
由于 OpenCV 本身不支持直接添加中文文本,因此使用 PIL 库来实现。
首先将 OpenCV 的 numpy 数组图像转换为 PIL 图像。
使用 ImageDraw 在图像上绘制文本,使用 ImageFont 指定字体和字号。
最后将 PIL 图像转换回 numpy 数组图像。
- 初始化人脸检测器和关键点预测器
python
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
detector 用于检测图像中的人脸。
predictor 用于预测人脸的 68 个关键点坐标,需要提供预训练的模型文件 shape_predictor_68_face_landmarks.dat。
- 打开摄像头并开始循环处理视频帧
python
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
faces = detector(frame, 0) # 获取图片中全部人脸位置
for face in faces:
shape = predictor(frame, face) # 获取关键点
# 将关键点转换为坐标(x,y)的形式
shape = np.array([[p.x, p.y] for p in shape.parts()])
mar = MAR(shape)
# 计算嘴部的纵横比
mjr = MJR(shape)
# 计算"嘴宽/脸颊宽"
result = "正常"
print("mar", mar, "\tmjr", mjr)
if mar > 0.5:
result = "大笑"
elif mjr > 0.45:
result = "微笑"
mouthHull = cv2.convexHull(shape[48:61]) # 嘴型构造凸包
frame = cv2AddchineseText(frame, result, mouthHull[0, 0])
cv2.drawContours(frame, [mouthHull], -1, (0, 255, 0), 1)
cv2.imshow("Frame", frame)
if cv2.waitKey(1) == 27:
break
cap = cv2.VideoCapture(0) 打开默认摄像头。
在循环中,使用 cap.read() 读取一帧视频。
detector(frame, 0) 检测当前帧中的人脸。
对于每个检测到的人脸,使用 predictor 预测其 68 个关键点坐标,并将其转换为 numpy 数组。
调用 MAR 和 MJR 函数计算嘴部的纵横比和嘴宽与脸颊宽的比例。
根据 MAR 和 MJR 的值判断表情状态(正常、大笑、微笑)。
cv2.convexHull(shape[48:61]) 构造嘴部关键点的凸包。
使用 cv2AddchineseText 函数在图像上添加表情结果文本。
使用 cv2.drawContours 函数在图像上绘制嘴部的凸包。
使用 cv2.imshow 显示处理后的帧。
如果按下 Esc 键(键码为 27),则退出循环。
- 释放资源
python
cv2.destroyAllWindows()
cap.release()
cv2.destroyAllWindows() 关闭所有 OpenCV 窗口。
cap.release() 释放摄像头资源。
完整代码:
python
import numpy as np
import dlib
import cv2
from sklearn.metrics.pairwise import euclidean_distances
from PIL import Image,ImageDraw, ImageFont
def MAR(shape):
A = euclidean_distances(shape[50].reshape(1,2),shape[58].reshape(1, 2))
B= euclidean_distances(shape[51].reshape(1,2),shape[57].reshape(1, 2))
C=euclidean_distances(shape[52].reshape(1,2),shape[56].reshape(1, 2))
D= euclidean_distances(shape[48].reshape(1,2),shape[54].reshape(1, 2))
return((A+B+C)/3)/D
def MJR(shape):
M = euclidean_distances(shape[48].reshape(1, 2), shape[54].reshape(1,2)) # 嘴宽度
J=euclidean_distances(shape[3].reshape(1,2),shape[13].reshape(1, 2))#下颌的宽度
return M / J
def cv2AddchineseText(img, text, position, textcolor=(0,255, 0), textSize=30):
if isinstance(img, np.ndarray):
img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
draw = ImageDraw.Draw(img)
fontStyle = ImageFont.truetype("simhei.ttf", textSize, encoding="utf-8")
draw.text(position, text, textcolor, font=fontStyle)
return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
cap=cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
faces = detector(frame,0) # 获取图片中全部人验位置
for face in faces:
shape = predictor(frame,face) # 获取关键点
# 将关键点转换为坐标(x,y)的形式
shape = np.array([[p.x, p.y]for p in shape.parts()])
mar = MAR(shape)
# 计算嘴部的商宽比
mjr = MJR(shape)
# 计算"嘴宽/脸颊宽"
result = "正常"
print( "mar",mar,"\tmjr",mjr)
if mar>0.5:
result="大笑"
elif mjr>0.45:
result="微笑"
mouthHull = cv2.convexHull(shape[48:61]) # 嘴型构造凸包
frame = cv2AddchineseText(frame, result, mouthHull[0, 0])
cv2.drawContours(frame,[mouthHull],-1,(0,255,0),1)
cv2.imshow("Frame",frame)
if cv2.waitKey(1) == 27:
break
cv2.destroyAllWindows()
cap.release()
四、表情识别的应用案例
人机交互
在人机交互中,表情识别可以让计算机更好地理解用户的情感状态,从而提供更加个性化的服务。例如,智能客服系统可以根据用户的表情判断用户的情绪,提供更加贴心的服务。
安防监控
在安防监控中,表情识别可以用于检测人员的异常表情,如愤怒、恐惧等,及时发现潜在的安全隐患。
市场调研
在市场调研中,表情识别可以用于分析消费者对产品或广告的反应,了解消费者的喜好和需求。
五、总结与展望
本文介绍了使用 OpenCV 进行表情识别的基本原理和具体实现方法,包括人脸检测、特征提取和表情分类。通过 OpenCV 提供的丰富工具和函数,我们可以方便地实现一个简单的表情识别系统。然而,表情识别仍然面临着一些挑战,如光照变化、表情多样性等。未来,随着计算机视觉技术的不断发展,表情识别的准确率和鲁棒性将会不断提高,其应用领域也将会更加广泛。