您现在的位置是:网站首页> PY&Rust
Python AI 相关资料
- PY&Rust
- 2023-07-20
- 622人已阅读
face_recognition 是一个开源的、人脸识别的Python库
基于Python的人脸识别(68个识别点)和焦点人物检测
写在前面的话
基于dlib库的模型,实现人脸识别和焦点人物的检测。最后呈现的效果为焦点人物的识别框颜色与其他人物框不一样。
准备工作
需要安装好python环境,安装好cmake、boost、opencv-python和dlib库等,具体可以看报错信息(可以使用PyCharm来运行和编辑py文件),然后把需要的库补全,文章最后会有完整代码,但是需要与shape_predictor_68_face_landmarks.dat模型文件同处一个路径下,然后启用。(百度可以下载到)
设计过程
因为是在自己电脑完成的必做题设计,所以前期还经历了相应的Python安装与环境配置,相应的资源库安装,例如dlib、opencv-python等等。
然后运行综合了(68个人脸特征点检测模型完成静止图像的人脸检测与标注)和(完成实时摄制视频的人脸检测与定位)的参考文件opencv_webcam_face_detection.py,发现可以实现实时视频的人脸检测。
对参考文件的代码进行分析,理解每一句代码的意思。对比查找设计需要的功能模块,实现1280x720视频输出,实现类win10相机的焦点人物识别。
上网查找并学习相应资料,参考win10相机的算法,创建自己的基于距离与面积的焦点人物算法,根据自己的需要对源代码进行添加及修改。
最后对代码进行测试,且不断修改成最适合的版本。
Python程序
流程图
焦点人物算法
内在逻辑:模仿win10相机,当有多于1个人时,优先选择最居中的为焦点人物,但若在其他地方的人脸面积大于4倍中心的人脸面积,则选择其他地方的作为焦点人物。
实际代码
import dlib
import cv2
import math# 摄像头参数设置
cam = cv2.VideoCapture(0) # 参数0,调用计算机的摄像头
cam.set(3, 1280) # 参数3,设定宽度分辨为1280
cam.set(4, 720) # 参数4,设定高度分辨为720# 设定人脸框的边框颜色及宽度,便于分辨焦点人物
color_focus = (255, 0, 255) # 设定焦点人脸框的颜色,紫红色
color_other = (255, 255, 255) # 设定其余人脸框的颜色,白色
lineWidth_focus = 2 # 设定焦点人脸框的宽度
lineWidth_other = 1 # 设定其他人脸框的宽度# 设定计算的一些参数
w = cam.get(3) / 2 # 设定屏幕中心的横坐标X
h = cam.get(4) / 2 # 设定屏幕中心的纵坐标Y
d_center = 10000 # 预设人脸框到屏幕中心的距离
index_center = 0 # 预设距离优先时的人脸框序号
index_area = 0 # 预设面积优先时的人脸框序号
area_center = -1 # 预设距离中心最近人脸框的面积
area = -1 # # 预设人脸框面积最大时的面积
detector = dlib.get_frontal_face_detector() # 加载这个库自带的人脸检测器
predictor_path = "shape_predictor_68_face_landmarks.dat" # 设置人脸预测模型的路径位置
predictor = dlib.shape_predictor(predictor_path) # 人脸预测实例化
while True:
# 当获取到视频输入时
ret_val, img = cam.read() # 读取视频每一帧,颜色格式为BGR格式,
rgb_image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 颜色BGR格式转为RGB格式
faces = detector(rgb_image) # 返回RGB格式人脸捕捉框# 逻辑算法:当有多于1个人时,优先选择最居中的为焦点人物,但若其他地方的人脸面积大于4倍中心的人脸面积,则选择该为焦点人物。
# 这个for循环先求出距离屏幕中心最近时的人脸框的序号和距离优先面积
for i, det in enumerate(faces): # 遍历所有人脸框,i是人脸框序号,det是每个人脸框
d = math.sqrt((w-(det.left()+(det.right()-det.left())/2))**2+(h-(det.top()+(det.bottom()-det.top())/2))**2)# 计算该人脸框到屏幕中心的距离
if d < d_center: # 对比刚计算出的距离与设定的最近距离,达成选择更小
index_center = i # 更新距离最近时的人脸框序号
d_center = d # 更新最近距离
area_center = abs((det.right() - det.left()) * (det.bottom() - det.top())) # 算出该人脸框的面积(距离更近优先)
# 这个for循环求出面积最大的人脸框的序号和面积优先面积
for i, det in enumerate(faces): # 遍历所有人脸框,i是人脸框序号,det是每个人脸框
if abs((det.right() - det.left()) * (det.bottom() - det.top())) > area: # 对比该人脸面积与设定的最大面积,实现选择更大
index_area = i # 更新面积更大时的人脸框序号
area = abs((det.right() - det.left()) * (det.bottom() - det.top())) # 算出该人脸框的面积(面积更大优先)
if area > 5*area_center: # 判断依据,若面积优先面积大于距离优先面积的5倍,就实现面积优先选择焦点人物,否则就距离优先。
index_center = index_area # 面积优先时,使用面积最大的人脸框序号
for i, det in enumerate(faces): # 遍历所有人脸框
if i == index_center: # 确定焦点人脸框的序号
print(d_center, i) # 输出焦点人物的距离中心位置,方便调试
cv2.rectangle(img, (det.left(), det.top()), (det.right(), det.bottom()), color_focus, lineWidth_focus)# 绘出焦点人脸框
shape = predictor(img, det) # 从预测模型处,得到68个人物特征点
for p in shape.parts(): # 遍历68个人物特征点
cv2.circle(img, (p.x, p.y), 2, (124, 252, 0), -1) # 设定焦点人物的68个点的形状颜色,茶绿色、实心
else:cv2.rectangle(img, (det.left(), det.top()), (det.right(), det.bottom()), color_other, lineWidth_other)# 绘出其他人脸框
shape = predictor(img, det) # 从预测模型处,得到68个人物特征点
for p in shape.parts(): # 遍历68个人物特征点
cv2.circle(img, (p.x, p.y), 2, (255, 255, 255), -1) # 设定其他人物的68个点的形状颜色,白色、实心
cv2.imshow('my webcam', img) # 输出绘好框后的帧动画
if cv2.waitKey(1) == 27: # 设置一个滞留时间,等待用户触发事件,若用户按下 ESC(ASCII码为27),则执行 if 体break # (if主体)退出
cv2.destroyAllWindows() # 销毁所有输出图像窗
运行情况
为了容易分辨焦点人物与其他人物,首先将焦点人物框的宽度设为2,颜色设为紫红色,68个识别点设为茶绿色;其他人物框的宽度设为1,颜色设为白色,68个识别点设为白色。
然后进行多次测试,通过整理测试结果,发现算法没有错误,焦点人物按照距离和面积两个因素来决定。成功运行图如下:
不展示图了,但是主人物为紫红框,其他人物为白色圈。与预期一致。
python3利用Dlib19.7实现人脸68个特征点标定
0.引言
利用Dlib官方训练好的模型“shape_predictor_68_face_landmarks.dat”进行68点标定,利用OpenCv进行图像化处理,在人脸上画出68个点,并标明序号;
1.开发环境
python:3.6.3
dlib:19.7
OpenCv, numpy
需要调用的库:
import dlib #人脸识别的库dlib
import numpy as np #数据处理的库numpy
import cv2 #图像处理的库OpenCv
2.设计流程
工作内容主要以下两大块:68点标定和OpenCv绘点
68点标定:
借助官方的Demo(face_landmark_detection.py,在之前另一篇博客里面介绍过学习Python3 Dlib19.7进行人脸面部识别)实现;
OpenCv绘点:
介绍了用到的 画圆函数cv2.circle() 和 输出字符串函数 cv2.putText() ;
流程:
1.调用dlib库来进行人脸识别,调用预测器“shape_predictor_68_face_landmarks.dat”进行68点标定
2.存入68个点坐标
3.利用cv2.circle来画68个点
4.利用cv2.putText()函数来画数字1-68
3.源码
?
# 68-points
# 2017-12-28
# By TimeStamp
# #cnblogs: http://www.cnblogs.com/AdaminXie/
import dlib #人脸识别的库dlib
import numpy as np #数据处理的库numpy
import cv2 #图像处理的库OpenCv
# dlib预测器
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
path="********************"
# cv2读取图像
img=cv2.imread(path+"test.jpg")
# 取灰度
img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
# 人脸数rects
rects = detector(img_gray, 0)
for i in range(len(rects)):
landmarks = np.matrix([[p.x, p.y] for p in predictor(img, rects[i]).parts()])
for idx, point in enumerate(landmarks):
# 68点的坐标
pos = (point[0, 0], point[0, 1])
# 利用cv2.circle给每个特征点画一个圈,共68个
cv2.circle(img, pos, 5, color=(0, 255, 0))
# 利用cv2.putText输出1-68
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img, str(idx+1), pos, font, 0.8, (0, 0, 255), 1, cv2.LINE_AA)
cv2.namedWindow("img", 2)
cv2.imshow("img", img)
cv2.waitKey(0)
如何在python环境中安装dlib库
方法一:直接使用pip命令安装(我的成功了)
我使用的是anacnda,所以从anaconda prompt里面进去,激活环境activate 环境名
然后:pip install dlib -i https://pypi.tuna.tsinghua.edu.cn/simple/(后面是清华的镜像网)。然后就可以了,如果报错的话,可能是cmake库没有安装,那就先:
pip install cmake -i https://pypi.tuna.tsinghua.edu.cn/simple/
然后再
pip install dlib -i https://pypi.tuna.tsinghua.edu.cn/simple/
就可以啦
方法二:在dlib官网下载对应的whl文件安装
官网:https://pypi.org/project/dlib/
下载后存在文件夹里,然后从anaconda prompt进入到whl所在的文件夹后,使用以下方式安装:
pip install dlib版本名.whl
例如:pip install dlib-18.17.100-cp35-none-win_amd64.whl
方法三:在dlib官网下载对应的zip文件安装
解压后在dlib的文件夹下有一个setup.py文件。在Anaconda Prompt中转到解压后的文件夹,输入命令:python setup.py install
python人脸识别
构建人脸识别系统的步骤
安装库
我们需要安装 2 个库来实现人脸识别。
dlib:dlib是一个现代 C++ 工具包,包含机器学习算法和工具,用于在 C++ 中创建复杂的软件以解决实际问题。
# installing dlib
pip install dlib
脸部识别:将face_recognition库,创建和维护 Adam Geitgey(https://adamgeitgey.com/),包含了dlib人脸识别功能。
# installing face recognition
pip install face recognition
Opencv用于一些图像预处理。
# installing opencv
pip install opencv
注意:如果你在安装dlib 时遇到任何错误 **,**我建议你使用vs_code 社区版安装 C++ 开发工具包:https://visualstudio.microsoft.com/vs/community/
导入库
现在你已经下载了所有重要的库,让我们导入它们来构建系统。
import cv2
import numpy as np
import face_recognition
加载图像
导入库后,你需要加载图像。face_recognition 库以 BGR 的形式加载图像,为了打印图像,你应该使用 OpenCV 将其转换为 RGB。
imgelon_bgr = face_recognition.load_image_file('elon.jpg')
imgelon_rgb = cv2.cvtColor(imgelon_bgr,cv2.COLOR_BGR2RGB)
cv2.imshow('bgr', imgelon_bgr)
cv2.imshow('rgb', imgelon_rgb)
cv2.waitKey(0)
如你所见,RGB 看起来很自然,因此你将始终把通道更改为 RGB。
查找人脸位置并绘制边界框
你需要在人脸周围绘制一个边界框,以显示是否已检测到人脸。
imgelon =face_recognition.load_image_file('elon.jpg')
imgelon = cv2.cvtColor(imgelon,cv2.COLOR_BGR2RGB)
#----------Finding face Location for drawing bounding boxes-------
face = face_recognition.face_locations(imgelon_rgb)[0]
copy = imgelon.copy()
#-------------------Drawing the Rectangle-------------------------
cv2.rectangle(copy, (face[3], face[0]),(face[1], face[2]), (255,0,255), 2)
cv2.imshow('copy', copy)
cv2.imshow('elon',imgelon)
cv2.waitKey(0)
为人脸识别训练图像
该库的制作方式是自动查找人脸并仅处理人脸,因此你无需从图片中裁剪人脸。训练:在这个阶段,我们将训练图像转换为一些编码,并使用该图像的人名存储编码。
train_elon_encodings = face_recognition.face_encodings(imgelon)[0]
测试:为了测试,我们加载图像并将其转换为编码,然后在训练期间将编码与存储的编码进行匹配,这种匹配基于寻找最大相似度。当你找到与测试图像匹配的编码时,你将获得与训练编码相关联的名称。
# lets test an image
test = face_recognition.load_image_file('elon_2.jpg')
test = cv2.cvtColor(test, cv2.COLOR_BGR2RGB)
test_encode = face_recognition.face_encodings(test)[0]
print(face_recognition.compare_faces([train_encode],test_encode))
face_recognition.compare_faces,如果两个图像中的人相同,返回True,否则返回False。
构建人脸识别系统
导入必要的库
import cv2
import face_recognition
import os
import numpy as np
from datetime import datetime
import pickle
定义将存储训练图像数据集的文件夹路径
path = 'student_images'
注意:对于训练,我们只需要将训练图片放到path目录下,图片名称必须是person_name.jpg/jpeg格式。
例如:正如你在我的 student_images 路径中看到的,有 6 个人。因此我们的模型只能识别这 6 个人。你可以在此目录中添加更多图片,以便更多人识别
现在创建一个列表来存储 person_name 和图像数组。
遍历path目录中存在的所有图像文件,读取图像,并将图像数组附加到图像列表,并将文件名附加到classNames。
images = []
classNames = []mylist = os.listdir(path)
for cl in mylist:
curImg = cv2.imread(f'{path}/{cl}')
images.append(curImg)
classNames.append(os.path.splitext(cl)[0])
创建一个函数来对所有训练图像进行编码并将它们存储在一个变量encoding_face_train 中。
def findEncodings(images):
encodeList = []
for img in images:
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
encoded_face = face_recognition.face_encodings(img)[0]
encodeList.append(encoded_face)
return encodeList
encoded_face_train = findEncodings(images)
创建一个函数,该函数将创建一个Attendance.csv文件来存储考勤时间。
注意:这里需要手动创建Attendance.csv文件并在函数中给出路径
def markAttendance(name):
with open('Attendance.csv','r+') as f:
myDataList = f.readlines()
nameList = []
for line in myDataList:
entry = line.split(',')
nameList.append(entry[0])
if name not in nameList:
now = datetime.now()
time = now.strftime('%I:%M:%S:%p')
date = now.strftime('%d-%B-%Y')
f.writelines(f'n{name}, {time}, {date}')
**with open(“filename.csv”,'r+')创建一个文件,'r+'**模式用于打开文件进行读写。我们首先检查出席者的名字是否已经在attenting .csv中可用。如果出席者的名字在attends.csv中不可用,我们将在函数调用的时间中写入出席者的名字。
阅读网络摄像头进行实时识别
# take pictures from webcam
cap = cv2.VideoCapture(0)while True:
success, img = cap.read()
imgS = cv2.resize(img, (0,0), None, 0.25,0.25)
imgS = cv2.cvtColor(imgS, cv2.COLOR_BGR2RGB)
faces_in_frame = face_recognition.face_locations(imgS)
encoded_faces = face_recognition.face_encodings(imgS, faces_in_frame)for encode_face, faceloc in zip(encoded_faces,faces_in_frame):
matches = face_recognition.compare_faces(encoded_face_train, encode_face)
faceDist = face_recognition.face_distance(encoded_face_train, encode_face)
matchIndex = np.argmin(faceDist)
print(matchIndex)
if matches[matchIndex]:
name = classNames[matchIndex].upper().lower()
y1,x2,y2,x1 = faceloc
# since we scaled down by 4 times
y1, x2,y2,x1 = y1*4,x2*4,y2*4,x1*4
cv2.rectangle(img,(x1,y1),(x2,y2),(0,255,0),2)
cv2.rectangle(img, (x1,y2-35),(x2,y2), (0,255,0), cv2.FILLED)
cv2.putText(img,name, (x1+6,y2-5), cv2.FONT_HERSHEY_COMPLEX,1,(255,255,255),2)
markAttendance(name)
cv2.imshow('webcam', img)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
仅将识别部分的图像大小调整为 1/4。输出帧将是原始大小。
调整大小可提高每秒帧数。
face_recognition.face_locations()在调整大小的图像(imgS)上被调用。对于人脸边界框坐标必须乘以 4 才能覆盖在输出帧上。
**face_recognition.distance()**返回测试图像的距离数组,其中包含我们训练目录中存在的所有图像。
最小人脸距离的索引将是匹配的人脸。
找到匹配的名称后,我们调用markAttendance函数。
使用**cv2.rectangle()**绘制边界框。
我们使用**cv2.putText()**将匹配的名称放在输出帧上。
动图封面
考勤报告
人脸识别系统面临的挑战
尽管构建面部识别看起来很容易,但在没有任何限制的情况下拍摄的现实世界图像中却并不容易。面部识别系统面临的几个挑战如下:
**照明:**它极大地改变了面部外观,观察到照明条件的轻微变化对其结果产生重大影响。
**姿势:**面部识别系统对姿势高度敏感,如果数据库仅在正面视图上进行训练,可能会导致识别错误或无法识别。
面部表情:同一个人的不同表情是另一个需要考虑的重要因素。不过,现代识别器可以轻松处理它。
低分辨率:识别器的训练必须在分辨率好的图片上进行,否则模型将无法提取特征。
**老化:**随着年龄的增长,人脸的形状、线条、纹理变化是另一个挑战。
结论
在本文中,我们讨论了如何使用face_recognition库创建人脸识别系统并制作了考勤系统。你可以使用Tkinter或Pyqt进一步设计用于人脸识别考勤系统的GUI。
利用PYTHON编写人脸表情
最近闲来无事,和一个学妹完成了一个SRT,主要是关于元宇宙什么的,不过我在其中主要的工作是用python写一个人脸识别系统,发到这里和大家分享一下
注:我利用了几个包,包括opencv,dlib,numpy等,所有包都会显示在代码开头import后
第一步,利用PyCharm先做灰度图
想要识别表情,计算机就需要转换人脸图片转化为灰度的图,计算机不如人脑聪明,要把这张图变成到电脑看得懂的形式。
import cv2 as cv
img=cv.imread('img.png')
#灰度
gray_img=cv.cvtColor(img,cv.COLOR_BGR2GRAY)
cv.imshow('gray',gray_img)
cv.imwrite('gray_face1.jpg',gray_img)
#修改尺寸
cv.imshow('read_img',img)
cv.waitKey(0)
cv.destroyAllWindows()
第二步,改变灰度图大小
每张图片大小都是不固定的,一运行忽然很大总会吓你一跳,也不便于观察,这一步,我们先把灰度图的尺寸改变一下
import cv2 as cv
img=cv.imread('img.png')
resize_img=cv.resize(img,dsize=(200,200))
cv.imshow('img',img)
cv.imshow('resize_img',resize_img)
print('修改前:',img.shape)
print('修改后:',resize_img.shape)
while True:
if ord('q')==cv.waitKey(0):
break
cv.destroyAllWindows()
第三步,锁定人脸
基础部分都学完了,该做正事了,这一步我们要锁定人脸,好让后续的工作继续进行
import cv2 as cv
img=cv.imread('3575ce750fbfb4906ac6d74909de2d6.jpg')
def face_detect_demo():
gary = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
face_detect=cv.CascadeClassifier('C:/Users/SGB/Downloads/opencv/sources/data/haarcascades/haarcascade_frontalface_alt2.xml')//调用了一个数据包
face=face_detect.detectMultiScale(gary)
for x,y,w,h in face:
cv.rectangle(img,(x,y),(x+w,y+h),color=(0,0,255),thickness=2)
cv.imshow('result',img)
face_detect_demo()
while True:
if ord('q')==cv.waitKey(0):
break
cv.destroyAllWindows()
运行结果
第四步,锁定人脸上关键的点
为了识别表情,我们需要把脸上关键的点都给打印出来,比方说眉毛,眼睛,嘴巴等,我用的是前人训练出来的68点制。
import cv2
import numpy as np
import dlib
img_path = "3575ce750fbfb4906ac6d74909de2d6.jpg"
# 加载dlib 人脸检测器
detector = dlib.get_frontal_face_detector()
# 加载dlib 人脸关键点
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
# 读入人脸图片
img = cv2.imread(img_path)
cv2.imshow('img', img)
cv2.waitKey(0)
# 转化为灰度图
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow('img_gray', img_gray)
cv2.waitKey(0)
# 检测人脸
dets = detector(img_gray, 1)
# 遍历每张人脸
for face in dets:
# 获取人脸关键点(对遍历到的这张脸进行关键点检测)
shape = predictor(img_gray, face)
# 获取每个点的坐标,并标记在图片上
for pt in shape.parts():
# 转换坐标
pt_pos = (pt.x, pt.y)
# 画点
img_face = cv2.circle(img, pt_pos, 1, (0,255,0), 2)
cv2.imshow('face', img_face)
cv2.waitKey(0)
运行结果
第五步,打开摄像头,对人脸进行关键点打印
打开摄像头,对人脸进行打印关键点的操作。
import cv2
import numpy as np
import dlib
# 加载dlib 人脸检测器
detector = dlib.get_frontal_face_detector()
# 加载dlib 人脸关键点
predictor = dlib.shape_predictor('./shape_predictor_68_face_landmarks.dat')
# 打开摄像头
cap = cv2.VideoCapture(0)
while(1):
flag, frame = cap.read()#获取视频内容
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)#加载灰度图像
b, g, r = cv2.split(frame)
frame_RGB = cv2.merge((r, g ,b))
rets = detector(frame_gray, 0)#定位
for face in rets:
pots = predictor(frame_gray, face)#点
for i in pots.parts():
pos_pot = (i.x, i.y)
frame_face = cv2.circle(frame, pos_pot, 1, (0,255,0), 2)
cv2.imshow('face', frame_face)
k = cv2.waitKey(1)
if k & 0xff == ord('q'):#关闭摄像头用Q
break
cap.release()
cv2.destroyAllWindows()
第五步,打开摄像头进行表情分析
利用之前的关键点,对其进行算法分析,比方说眉毛下压是生气,眼睛眯起来是开心等。
"""
从视屏中识别人脸,并实时标出面部特征点
"""
import sys
import dlib # 人脸识别的库dlib
import numpy as np # 数据处理的库numpy
import cv2 # 图像处理的库OpenCv
img_path = "img.png"
class face_emotion():
def __init__(self):
# 使用特征提取器get_frontal_face_detector
self.detector = dlib.get_frontal_face_detector()
# dlib的68点模型,使用作者训练好的特征预测器
self.predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
# 建cv2摄像头对象,这里使用电脑自带摄像头,如果接了外部摄像头,则自动切换到外部摄像头
self.cap = cv2.VideoCapture(0)
# 设置视频参数,propId设置的视频参数,value设置的参数值
self.cap.set(3, 480)
# 截图screenshoot的计数器
self.cnt = 0
def learning_face(self):
# 眉毛直线拟合数据缓冲
line_brow_x = []
line_brow_y = []
# cap.isOpened() 返回true/false 检查初始化是否成功
while (self.cap.isOpened()):
# cap.read()
# 返回两个值:
# 一个布尔值true/false,用来判断读取视频是否成功/是否到视频末尾
# 图像对象,图像的三维矩阵
flag, im_rd = self.cap.read()
# 每帧数据延时1ms,延时为0读取的是静态帧
k = cv2.waitKey(1)
# 取灰度
img_gray = cv2.cvtColor(im_rd, cv2.COLOR_RGB2GRAY)
#im_rd的意思是img
# 使用人脸检测器检测每一帧图像中的人脸。并返回人脸数rects
faces = self.detector(img_gray, 0)
# 待会要显示在屏幕上的字体
font = cv2.FONT_HERSHEY_SIMPLEX
# 如果检测到人脸
if (len(faces) != 0):
# 对每个人脸都标出68个特征点
for i in range(len(faces)):
# enumerate方法同时返回数据对象的索引和数据,k为索引,d为faces中的对象
for k, d in enumerate(faces):
# 用红色矩形框出人脸
cv2.rectangle(im_rd, (d.left(), d.top()), (d.right(), d.bottom()), (0, 0, 255))
# 计算人脸热别框边长
self.face_width = d.right() - d.left()
# 使用预测器得到68点数据的坐标
shape = self.predictor(im_rd, d)
# 圆圈显示每个特征点
for i in range(68):
cv2.circle(im_rd, (shape.part(i).x, shape.part(i).y), 2, (0, 255, 0), -1, 8)
# cv2.putText(im_rd, str(i), (shape.part(i).x, shape.part(i).y), cv2.FONT_HERSHEY_SIMPLEX, 0.5,
# (255, 255, 255))
# 分析任意n点的位置关系来作为表情识别的依据
mouth_width = (shape.part(54).x - shape.part(48).x) / self.face_width # 嘴巴咧开程度
mouth_higth = (shape.part(66).y - shape.part(62).y) / self.face_width # 嘴巴张开程度
# print("嘴巴宽度与识别框宽度之比:",mouth_width_arv)
# print("嘴巴高度与识别框高度之比:",mouth_higth_arv)
# 通过两个眉毛上的10个特征点,分析挑眉程度和皱眉程度
brow_sum = 0 # 高度之和
frown_sum = 0 # 两边眉毛距离之和
for j in range(17, 21):
brow_sum += (shape.part(j).y - d.top()) + (shape.part(j + 5).y - d.top())
frown_sum += shape.part(j + 5).x - shape.part(j).x
line_brow_x.append(shape.part(j).x)
line_brow_y.append(shape.part(j).y)
# self.brow_k, self.brow_d = self.fit_slr(line_brow_x, line_brow_y) # 计算眉毛的倾斜程度
tempx = np.array(line_brow_x)
tempy = np.array(line_brow_y)
z1 = np.polyfit(tempx, tempy, 1) # 拟合成一次直线
self.brow_k = -round(z1[0], 3) # 拟合出曲线的斜率和实际眉毛的倾斜方向是相反的
brow_hight = (brow_sum / 10) / self.face_width # 眉毛高度占比
brow_width = (frown_sum / 5) / self.face_width # 眉毛距离占比
# print("眉毛高度与识别框高度之比:",round(brow_arv/self.face_width,3))
# print("眉毛间距与识别框高度之比:",round(frown_arv/self.face_width,3))
# 眼睛睁开程度
eye_sum = (shape.part(41).y - shape.part(37).y + shape.part(40).y - shape.part(38).y +
shape.part(47).y - shape.part(43).y + shape.part(46).y - shape.part(44).y)
eye_hight = (eye_sum / 4) / self.face_width
# print("眼睛睁开距离与识别框高度之比:",round(eye_open/self.face_width,3))
# 分情况讨论
# 张嘴,可能是开心或者惊讶
if round(mouth_higth >= 0.03):
if eye_hight >= 0.056:
cv2.putText(im_rd, "amazing", (d.left(), d.bottom() + 20), cv2.FONT_HERSHEY_SIMPLEX,
0.8,
(0, 0, 255), 2, 4)
else:
cv2.putText(im_rd, "happy", (d.left(), d.bottom() + 20), cv2.FONT_HERSHEY_SIMPLEX, 0.8,
(0, 0, 255), 2, 4)
# 没有张嘴,可能是正常和生气
else:
if self.brow_k <= -0.3:
cv2.putText(im_rd, "angry", (d.left(), d.bottom() + 20), cv2.FONT_HERSHEY_SIMPLEX, 0.8,
(0, 0, 255), 2, 4)
else:
cv2.putText(im_rd, "nature", (d.left(), d.bottom() + 20), cv2.FONT_HERSHEY_SIMPLEX, 0.8,
(0, 0, 255), 2, 4)
# 标出人脸数
cv2.putText(im_rd, "Faces: " + str(len(faces)), (20, 50), font, 1, (0, 0, 255), 1, cv2.LINE_AA)
else:
# 没有检测到人脸
cv2.putText(im_rd, "No Face", (20, 50), font, 1, (0, 0, 255), 1, cv2.LINE_AA)
# 添加说明
im_rd = cv2.putText(im_rd, "S: screenshot", (20, 400), font, 0.8, (0, 0, 255), 1, cv2.LINE_AA)
im_rd = cv2.putText(im_rd, "Q: quit", (20, 450), font, 0.8, (0, 0, 255), 1, cv2.LINE_AA)
# 按下s键截图保存
if (k == ord('s')):
self.cnt += 1
cv2.imwrite("screenshoot" + str(self.cnt) + ".jpg", im_rd)
# 按下q键退出
if (k == ord('q')):
break
# 窗口显示
cv2.imshow("camera", im_rd)
# 释放摄像头
self.cap.release()
# 删除建立的窗口
cv2.destroyAllWindows()
if __name__ == "__main__":
my_face = face_emotion()
my_face.learning_face()
到这步的时候,其实已经花了接近一周的时间,项目也接近结束,不过在这个基础之上,我想,是否可以照葫芦画瓢,再做出一个图片表情识别,做了一下午,居然真的被我弄出来了,算是瞎猫碰到死耗子。
"""
从视屏中识别人脸,并实时标出面部特征点
"""
import sys
import dlib # 人脸识别的库dlib
import imutils
import numpy as np # 数据处理的库numpy
import cv2 # 图像处理的库OpenCv
img_path = "img_4.png"
class face_emotion():
def __init__(self):
# 使用特征提取器get_frontal_face_detector
self.detector = dlib.get_frontal_face_detector()
# dlib的68点模型,使用作者训练好的特征预测器
self.predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
self.image = cv2.imread("img.png")
self.image = imutils.resize(self.image, width=500)
gray = cv2.cvtColor(self.image, cv2.COLOR_BGR2GRAY)
self.cap = cv2.imread("img.png")
# 截图screenshoot的计数器
def learning_face(self):
# 眉毛直线拟合数据缓冲
line_brow_x = []
line_brow_y = []
# cap.isOpened() 返回true/false 检查初始化是否成功
while (1):
# 返回两个值:
# 图像对象,图像的三维矩阵
im_rd = cv2.imread(img_path)
# 每帧数据延时1ms,延时为0读取的是静态帧
k = cv2.waitKey(1)
# 取灰度
img_gray = cv2.cvtColor(im_rd, cv2.COLOR_RGB2GRAY)
# 使用人脸检测器检测每一帧图像中的人脸。并返回人脸数rects
faces = self.detector(img_gray, 0)
# 待会要显示在屏幕上的字体
font = cv2.FONT_HERSHEY_SIMPLEX
# 如果检测到人脸
if (len(faces) != 0):
# 对每个人脸都标出68个特征点
for i in range(len(faces)):
# enumerate方法同时返回数据对象的索引和数据,k为索引,d为faces中的对象
for k, d in enumerate(faces):
# 用红色矩形框出人脸
cv2.rectangle(im_rd, (d.left(), d.top()), (d.right(), d.bottom()), (0, 0, 255))
# 计算人脸热别框边长
self.face_width = d.right() - d.left()
# 使用预测器得到68点数据的坐标
shape = self.predictor(im_rd, d)
# 圆圈显示每个特征点
for i in range(68):
cv2.circle(im_rd, (shape.part(i).x, shape.part(i).y), 2, (0, 255, 0), -1, 8)
# cv2.putText(im_rd, str(i), (shape.part(i).x, shape.part(i).y), cv2.FONT_HERSHEY_SIMPLEX, 0.5,
# (255, 255, 255))
# 分析任意n点的位置关系来作为表情识别的依据
mouth_width = (shape.part(54).x - shape.part(48).x) / self.face_width # 嘴巴咧开程度
mouth_higth = (shape.part(66).y - shape.part(62).y) / self.face_width # 嘴巴张开程度
# print("嘴巴宽度与识别框宽度之比:",mouth_width_arv)
# print("嘴巴高度与识别框高度之比:",mouth_higth_arv)
# 通过两个眉毛上的10个特征点,分析挑眉程度和皱眉程度
brow_sum = 0 # 高度之和
frown_sum = 0 # 两边眉毛距离之和
for j in range(17, 21):
brow_sum += (shape.part(j).y - d.top()) + (shape.part(j + 5).y - d.top())
frown_sum += shape.part(j + 5).x - shape.part(j).x
line_brow_x.append(shape.part(j).x)
line_brow_y.append(shape.part(j).y)
# self.brow_k, self.brow_d = self.fit_slr(line_brow_x, line_brow_y) # 计算眉毛的倾斜程度
tempx = np.array(line_brow_x)
tempy = np.array(line_brow_y)
z1 = np.polyfit(tempx, tempy, 1) # 拟合成一次直线
self.brow_k = -round(z1[0], 3) # 拟合出曲线的斜率和实际眉毛的倾斜方向是相反的
brow_hight = (brow_sum / 10) / self.face_width # 眉毛高度占比
brow_width = (frown_sum / 5) / self.face_width # 眉毛距离占比
# print("眉毛高度与识别框高度之比:",round(brow_arv/self.face_width,3))
# print("眉毛间距与识别框高度之比:",round(frown_arv/self.face_width,3))
# 眼睛睁开程度
eye_sum = (shape.part(41).y - shape.part(37).y + shape.part(40).y - shape.part(38).y +
shape.part(47).y - shape.part(43).y + shape.part(46).y - shape.part(44).y)
eye_hight = (eye_sum / 4) / self.face_width
# print("眼睛睁开距离与识别框高度之比:",round(eye_open/self.face_width,3))
# 分情况讨论
# 张嘴,可能是开心或者惊讶
if round(mouth_higth >= 0.03):
if eye_hight >= 0.056:
cv2.putText(im_rd, "amazing", (d.left(), d.bottom() + 20), cv2.FONT_HERSHEY_SIMPLEX,
0.8,
(0, 0, 255), 2, 4)
else:
cv2.putText(im_rd, "happy", (d.left(), d.bottom() + 20), cv2.FONT_HERSHEY_SIMPLEX, 0.8,
(0, 0, 255), 2, 4)
# 没有张嘴,可能是正常和生气
else:
if self.brow_k <= -0.3:
cv2.putText(im_rd, "angry", (d.left(), d.bottom() + 20), cv2.FONT_HERSHEY_SIMPLEX, 0.8,
(0, 0, 255), 2, 4)
else:
cv2.putText(im_rd, "nature", (d.left(), d.bottom() + 20), cv2.FONT_HERSHEY_SIMPLEX, 0.8,
(0, 0, 255), 2, 4)
# 标出人脸数
cv2.putText(im_rd, "Faces: " + str(len(faces)), (20, 50), font, 1, (0, 0, 255), 1, cv2.LINE_AA)
else:
# 没有检测到人脸
cv2.putText(im_rd, "No Face", (20, 50), font, 1, (0, 0, 255), 1, cv2.LINE_AA)
# 添加说明
im_rd = cv2.putText(im_rd, "S: screenshot", (20, 400), font, 0.8, (0, 0, 255), 1, cv2.LINE_AA)
im_rd = cv2.putText(im_rd, "Q: quit", (20, 450), font, 0.8, (0, 0, 255), 1, cv2.LINE_AA)
# 按下s键截图保存
if (k == ord('s')):
self.cnt += 1
cv2.imwrite("screenshoot" + str(self.cnt) + ".jpg", im_rd)
# 按下q键退出
if (k == ord('q')):
break
# 窗口显示
cv2.imshow("camera", im_rd)
# 删除建立的窗口
cv2.destroyAllWindows()
if __name__ == "__main__":
my_face = face_emotion()
my_face.learning_face()
运行结果,有不足的地方还请指正,谢谢大家!!
face_recognition 是一个开源的、人脸识别的Python库
face_recognition是一款免费、开源、实时、离线的Python人脸识别库,是目前世界上最简洁的人脸识别库。
face_recognition是基于业内领先的C++开源库dlib中的深度学习模型,用Labeled Faces in the Wild人脸数据集进行测试,有高达99.38%的准确率。因此,安装face_recognition前需要安装dlib库。
一、face_recognition安装
1.dlib安装:
CPU版:
CPU安装很简单pip3 install dlib
GPU版:
GPU版比CPU版速度快精度高、建议安装使用GPU版,但是GPU安装过程复杂
首先,需要正确安装CUDA和CUDNN,CUDA、CUDNN是必须要安装的(本人安装的是CUDA11.3)
另外,还需要VS编译环境(本人安装的VS2019)和CMake(pip3 install cmake)
之后就是dlib GPU版的编译和安装(cmd命令行操作):
1.git clone https://github.com/davisking/dlib.git 或者 dlib C++ Library下载dlib库,解压后离线编译
2.cd dlib
3.mkdir build
4.cd build
5.cmake .. -DDLIB_USE_CUDA=1 -DUSE_AVX_INSTRUCTIONS=1
6.cmake --build .
7.cd..
8.python setup.py install
骚操作 如果你电脑不想安装VS、cmake编译怎么办?
那就安装别人编译好的dlib库,但是python版本和CUDA版本要相同。
例如:
本人在公司电脑上编译安装的GPU版dlib:dlib-19.22.0-py3.9-win-amd64.egg(python3.9+cuda11.3)
路径为python安装路径下的Python39\Lib\site-packages文件夹下
本人个人电脑懒得安装VS,将dlib-19.22.0-py3.9-win-amd64.egg文件拷贝至个人电脑
打开dlib-19.22.0-py3.9-win-amd64.egg文件,将其中四个子文件拷贝至个人电脑中的Python\Lib\site-packages中即可。
注意:一定要python版本和CUDA版本相同。
测试dlib GPU版是否安装成功:
import dlib
print(dlib.DLIB_USE_CUDA)
print(dlib.cuda.get_num_devices())
返回True即为成功。
2.face_recognition安装:
安装dlib后,安装face_recognition库
pip3 install face_recognition
二、face_recognition函数介绍
face_recognition做为目前最简单的人脸识别库(网站:https://github.com/ageitgey/face_recognition/),两行代码即可实现人脸识别:
import face_recognition
image = face_recognition.load_image_file("face.jpg")
face_locations = face_recognition.face_locations(image)
face_locations为(顶部、右侧、底部、左侧)顺序找到的人脸位置的元组列表
face_recognition API 文档:https://face-recognition.readthedocs.io/en/latest/face_recognition.html
face_recognition只有几个函数:
face_recognition.load_image_file(file,mode='RGB')
加载图像,mode – "RGB"(8 位 RGB,3 个通道)或 "L"(黑白)
face_recognition.face_locations(img,number_of_times_to_upsample=1,model='hog')
返回图像中每张人脸的人脸特征位置列表;
number_of_times_to_upsample – 对图像进行多少次上采样以查找人脸。数字越大,人脸越小;
model – "hog"不太准确,但在CPU上更快。"cnn"是GPU / CUDA加速的一个更准确的深度学习模型。
face_recognition.batch_face_locations(images, number_of_times_to_upsample=1, batch_size=128)
使用 cnn 人脸检测器批量识别图像中人脸边界框的 2D 数组。没有 GPU,则不需要此功能。
number_of_times_to_upsample – 对图像进行多少次上采样以查找人脸。数字越大,人脸越小。
batch_size – 每个 GPU 处理批处理中要包含的图像数。
注意:batch_size的上线取决于GPU显存的大小;如果GPU显存小,则减小batch_size值。
face_recognition.face_landmarks(face_image, face_locations=None, model='large')
返回图像中每张人脸的人脸特征位置(眼睛、鼻子等)的字典。
face_locations – (可选)提供要检查的人脸位置列表。
model – “large” (默认) 或 “small”仅返回5个点,但速度更快。
face_recognition.face_encodings(face_image, known_face_locations=None, num_jitters=1, model='small')
返回图像中每张人脸的 128 维人脸编码。
known_face_locations - 可选 - 每个面孔的边界框(如果已经知道它们)。
num_jitters – 计算编码时重新采样人脸的次数。越高越准确,但速度越慢(即 100 表示慢 100 倍)。
model – “large” (默认) 或 “small”仅返回5个点,但速度更快。
face_recognition.compare_faces(known_face_encodings, face_encoding_to_check, tolerance=0.6)
将人脸编码列表与候选编码进行比较,以查看它们是否匹配。
known_face_encodings – 已知人脸编码的列表
face_encoding_to_check – 与列表进行比较的单张脸编码
tolerance – 将人脸之间的距离视为匹配。越低越严格。0.6 是典型的最佳值。
face_recognition.face_distance(face_encodings, face_to_compare)
给定人脸编码列表,将它们与已知的人脸编码进行比较,并得到每个比较人脸的欧氏距离。距离大小为面孔的相似程度。
face_encodings – 要比较的人脸编码列表
face_to_compare – 要与之进行比较的人脸编码
上一篇:如何用Python开发你的网站
下一篇:python视频教程