一、OpenCV表情识别介绍
OpenCV(Open Source Computer Vision Library)是一个广泛应用于计算机视觉任务的开源库,提供了丰富的图像处理和机器学习工具。表情识别则是计算机视觉领域的重要分支,旨在通过分析图像或视频中的人脸特征,判断出人物所表达的情感状态,如高兴、悲伤、愤怒、惊讶等。结合 OpenCV 进行表情识别,能借助其强大功能实现高效且准确的表情判断。
二、表情识别的基本原理
表情识别主要基于图像处理和机器学习技术。其基本流程可以分为以下几个步骤:
人脸检测:在图像或视频帧中定位出人脸的位置和大小。这是表情识别的基础,只有准确地检测到人脸,才能进行后续的表情分析。
特征提取:从检测到的人脸区域中提取出能够反映表情特征的信息,如眼睛、嘴巴等部位的形状和位置变化。常用的特征提取方法包括几何特征提取、纹理特征提取等。
表情分类:将提取到的特征输入到分类器中,根据预先训练好的模型判断人脸的表情类别,如高兴、悲伤、愤怒等。
三、代码实现
1. 导入必要的库
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):用于处理图像,特别是在图像上添加中文文本。
2. 定义函数计算嘴部纵横比(MAR)
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 值是垂直方向平均距离与水平方向距离的比值。
3. 定义函数计算嘴宽与脸颊宽的比例(MJR)
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
4. 定义函数在图像上添加中文文本
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 数组图像。
5. 初始化人脸检测器和关键点预测器
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。
6. 打开摄像头并开始循环处理视频帧
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),则退出循环。
7. 释放资源
cv2.destroyAllWindows()
cap.release()
cv2.destroyAllWindows() 关闭所有 OpenCV 窗口。
cap.release() 释放摄像头资源。
完整代码:
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 提供的丰富工具和函数,我们可以方便地实现一个简单的表情识别系统。然而,表情识别仍然面临着一些挑战,如光照变化、表情多样性等。未来,随着计算机视觉技术的不断发展,表情识别的准确率和鲁棒性将会不断提高,其应用领域也将会更加广泛。