目录
3.cv2AddChineseText(img, text, position, textColor, textSize)
这段代码是一个基于dlib和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
:一个包含机器学习算法的现代C++工具包,用于图像处理、人脸识别等。cv2
:OpenCV的Python接口,用于计算机视觉任务。sklearn.metrics.pairwise
:用于计算两点之间的欧氏距离。PIL
(Python Imaging Library):用于图像处理和文本绘制。
2.定义函数
1.MAR(shape)
def MAR(shape):
A = euclidean_distances(np.array(shape[50]),np.array(shape[58]))
B=euclidean_distances(np.array(shape[51]),np.array(shape[57]))
C=euclidean_distances(np.array(shape[52]),np.array(shape[56]))
D=euclidean_distances(np.array(shape[48]),np.array(shape[54]))
return((A+B+C)/3)/D
通过计算嘴角点之间的欧氏距离与嘴角到下巴中心点的距离的比值来得到口角的张开度(Mouth Aspect Ratio)。
2.MJR(shape)
def MJR(shape):#计算嘴宽度、脸颊宽度的比值
M= euclidean_distances(np.array(shape[48]),np.array(shape[54]))
J= euclidean_distances(np.array(shape[3]),np.array(shape[13]))
return M/J
嘴巴宽度是嘴角之间的距离,而下颌宽度是下颌两端点之间的距离,这个函数计算嘴巴宽度与下颌宽度的比值(Mouth Jaw Ratio)。
3.cv2AddChineseText(img, text, position, textColor, textSize)
# 定义一个函数,用于在OpenCV图像上添加中文文本
def cv2AddChineseText(img, text, position, textColor=(0, 255, 0), textSize=30):
# 如果输入是numpy数组,则转换为PIL Image对象
if isinstance(img, np.ndarray):
img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
draw = ImageDraw.Draw(img)
# 加载字体并设置字体样式和大小
fontStyle = ImageFont.truetype("C:\\WINDOWS\\FONTS\\SIMSUN.TTC", textSize, encoding="utf-8")
draw.text(position, text, textColor, font=fontStyle)
# 将PIL Image对象转换回numpy数组,并转换颜色空间
return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)
这个函数用于在图像上添加中文文本。先将OpenCV的BGR图像转换为PIL的RGB图像,然后在指定位置添加文本,最后再将PIL图像转换回OpenCV的BGR图像
3.主程序
1.初始化人脸检测器和关键点预测器
使用dlib的get_frontal_face_detector函数初始化人脸检测器。
使用dlib的shape_predictor函数加载人脸关键点预测模型。
2.打开摄像头
使用OpenCV的VideoCapture类打开摄像头,这里使用的是第一个摄像头(索引为1)。
3.循环读取摄像头帧
使用cap.read()函数读取摄像头的每一帧。
使用dlib的人脸检测器检测每一帧中的人脸。
对于检测到的每个人脸,使用dlib的关键点预测器预测人脸的关键点位置。
计算MAR和MJR值,并根据这些值判断表情。
使用cv2AddChineseText函数在图像上添加表情结果文本。
构造嘴巴的凸包并绘制在图像上。
使用OpenCV的imshow函数显示图像。
如果按下ESC键(ASCII码为27),则退出循环。
4.释放资源
使用cap.release()函数释放摄像头资源。
使用OpenCV的destroyAllWindows函数销毁所有创建的窗口。
# 加载人脸检测器和关键点预测器
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
# 打开摄像头
cap = cv2.VideoCapture(1)
# 设定一个窗口名称用于显示视频帧
window_name = "Face Expression Recognition"
while True:
# 读取摄像头的一帧
ret, frame = cap.read()
if not ret:
print("无法读取视频帧,请检查摄像头连接!")
break
# 转换为灰度图像,因为dlib的人脸检测器在灰度图像上运行得更快
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 使用dlib检测人脸
rects = detector(gray, 0)
# 遍历检测到的人脸
for rect in rects:
# 预测人脸关键点
shape = predictor(gray, rect)
shape_points = np.array([(p.x, p.y) for p in shape.parts()])
# 计算MAR和MJR
mar = MAR(shape_points)
mjr = MJR(shape_points)
# 根据MAR和MJR的值判断表情,并设置结果文本
result = "正常"
print(f"mar: {mar:.2f}\tmjr: {mjr:.2f}")
if mar > 0.5:
result = "大笑"
elif mjr > 0.35:
result = "微笑"
# 在图像上添加结果文本
frame = cv2AddChineseText(frame, result, (50, 100))
# 构造嘴巴的凸包并绘制
mouth_points = shape_points[48:68] # 注意:这里应该是68,因为我们需要包括嘴巴的所有点
mouthHull = cv2.convexHull(mouth_points)
cv2.drawContours(frame, [mouthHull], -1, (0, 255, 0), 1)
# 在图像上绘制人脸边界框(可选)
cv2.rectangle(frame, (rect.left(), rect.top()), (rect.right(), rect.bottom()), (0, 255, 0), 2)
# 显示视频帧
cv2.imshow(window_name, frame)
# 如果按下'q'键,退出循环
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放摄像头和窗口资源
cap.release()
cv2.destroyAllWindows()