目录
一、了解代码
1、简介
2、流程
二、案例实现
1、脸部关键点位置
2、字体文件
3、完整代码
1)调试模式
2)运行结果
一、了解代码
1、简介
代码内容为一个人脸表情识别程序,它使用dlib库进行人脸检测和形状预测(即关键点定位),然后基于这些关键点计算特征值来判断人脸的表情(正常、微笑、大笑)。程序还使用opencv-python(cv2)库来处理视频帧和绘制结果,以及PIL库来在图像上添加中文文本。
2、流程
- 定义两个函数MAR和MJR,用于计算嘴的宽高比和嘴宽度与脸颊宽度的比值。
- 定义一个函数cv2AddChineseText,用于向图片中添加中文。
- 使用dlib库中的get_frontal_face_detector()函数构造脸部位置检测器detector,并使用shape_predictor()函数读取人脸关键点定位模型predictor。
- 打开视频文件,用cv2.VideoCapture()函数捕获视频。
- 进入视频读取的循环中,读取一帧视频数据。
- 使用detector函数检测脸部位置,返回检测到的脸部区域。
- 遍历每个检测到的脸部区域,使用predictor函数获取关键点位置。
- 将关键点位置转换为坐标形式。
- 调用MAR和MJR函数计算嘴的宽高比和嘴宽度与脸颊宽度的比值。
- 根据计算结果判断表情,并将表情结果添加到图像中。
- 使用cv2AddChineseText函数将中文结果添加到图像中。
- 使用cv2.drawContours函数绘制嘴型的凸包。
- 显示带有结果标记的图像
二、案例实现
1、脸部关键点位置
2、字体文件
地址:C:\Windows\Fonts
3、完整代码
import numpy as np
import dlib
import cv2
from sklearn.metrics.pairwise import euclidean_distances
from PIL import Image, ImageDraw, ImageFontdef MAR(shape): # 计算嘴的宽高比x = shape[50] # 举例,此处表示第50个特征点的坐标y = shape[50].reshape(1,2) # reshape重塑坐标点的形状为一个1行2列的数组# euclidean_distances函数为计算两个点之间的欧几里得距离A = euclidean_distances(shape[50].reshape(1, 2), shape[58].reshape(1,2)) # 计算特征点50到58之间的距离,即嘴唇第一个位置高度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/Jdef cv2AddChineseText(img,text,position,textColor=(0,255,0),textSize=30):"""向图片中添加中文"""if (isinstance(img,np.ndarray)): # 判断是否0penCV图片类型img = Image.fromarray(cv2.cvtColor(img,cv2.COLOR_BGR2RGB)) # 实现array到image的转换draw = ImageDraw.Draw(img) # 在img图片上创建一个绘图的对象# 字体的格式fontStyle = ImageFont.truetype("STXINGKA.TTF",textSize,encoding = "utf-8") # STXINGKA.TTF为Windows自带的字体风格文件 地址为C:\Windows\Fontsdraw.text(position,text,textColor,font=fontStyle)return cv2.cvtColor(np.asarray(img),cv2.COLOR_BGR2RGB) # 转换回0penCV格式detector = dlib.get_frontal_face_detector() # 构造脸部位置检测器
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat') # 读取人脸68关键点定位模型
cap = cv2.VideoCapture('特朗普.mp4') # 打开视频
while True:ret,frame = cap.read() # 读取每一帧照片faces = detector(frame,0) # 调用脸部检测器对每一帧图像进行检测,0表示进行0次上采样,返回检测到的人脸矩形框坐标,左上角和右下角坐标for face in faces: # 遍历检测到的人脸shape = predictor(frame,face) # 根据检测到的面部位置,查找原图frame中脸部位置的特征点# 将关键点转换为坐标(x,y)形式shape = np.array([[p.x,p.y] for p in shape.parts()]) # shape.parts()表示获取面部特征点的迭代器,通过迭代返回每个特征点的坐标,共68组,转化为数组类型mar = MAR(shape) # 计算嘴部的高宽比mjr = MJR(shape) # 计算嘴宽/脸颊宽result = "正常" # 默认是正常表情print("mar", mar, "\tmjr", mjr) # 测试一下实际值,可以根据该值确定if mar > 0.5: # 可更具项目要求调整闽值。result = "大笑"elif mjr > 0.45: # 超过阈值为微笑result = "微笑"# frame = cv2AddChineseText(frame, result,(50,100)) # 输出中文,在指定位置坐标展示# cv2.putText # 只能输出英文mouthHull = cv2.convexHull(shape[48:61]) # 计算嘴型构造的点集的凸包,位置为关键点48到60# 凸包是一个最小的凸多边形,它能够包含给定点集中的所有点。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()