您现在的位置是:网站首页> PY&Rust

Python AI 相关资料

  • PY&Rust
  • 2023-07-20
  • 626人已阅读
摘要

基于Python的人脸识别(68个识别点)和焦点人物检测

python3利用Dlib19.7实现人脸68个特征点标定

如何在python环境中安装dlib库

python人脸识别

利用PYTHON编写人脸表情

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程序

流程图

1.jpg


焦点人物算法

内在逻辑:模仿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


dlib的下载地址



python人脸识别

原文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)

1.png

如你所见,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)

1.png

为人脸识别训练图像

该库的制作方式是自动查找人脸并仅处理人脸,因此你无需从图片中裁剪人脸。训练:在这个阶段,我们将训练图像转换为一些编码,并使用该图像的人名存储编码。


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 个人。你可以在此目录中添加更多图片,以便更多人识别

1.png


现在创建一个列表来存储 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()**将匹配的名称放在输出帧上。

动图封面

考勤报告

1.png

人脸识别系统面临的挑战

尽管构建面部识别看起来很容易,但在没有任何限制的情况下拍摄的现实世界图像中却并不容易。面部识别系统面临的几个挑战如下:


**照明:**它极大地改变了面部外观,观察到照明条件的轻微变化对其结果产生重大影响。

**姿势:**面部识别系统对姿势高度敏感,如果数据库仅在正面视图上进行训练,可能会导致识别错误或无法识别。

面部表情:同一个人的不同表情是另一个需要考虑的重要因素。不过,现代识别器可以轻松处理它。

低分辨率:识别器的训练必须在分辨率好的图片上进行,否则模型将无法提取特征。

**老化:**随着年龄的增长,人脸的形状、线条、纹理变化是另一个挑战。

结论

在本文中,我们讨论了如何使用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()

运行结果


1.png


第四步,锁定人脸上关键的点


为了识别表情,我们需要把脸上关键的点都给打印出来,比方说眉毛,眼睛,嘴巴等,我用的是前人训练出来的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)

运行结果

1.png

 第五步,打开摄像头,对人脸进行关键点打印


打开摄像头,对人脸进行打印关键点的操作。


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()

 

 

1.png



到这步的时候,其实已经花了接近一周的时间,项目也接近结束,不过在这个基础之上,我想,是否可以照葫芦画瓢,再做出一个图片表情识别,做了一下午,居然真的被我弄出来了,算是瞎猫碰到死耗子。


 


"""

从视屏中识别人脸,并实时标出面部特征点

"""

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()

 

 1.png




运行结果,有不足的地方还请指正,谢谢大家!! 



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版本要相同。

CUDA下载地址


例如:


本人在公司电脑上编译安装的GPU版dlib:dlib-19.22.0-py3.9-win-amd64.egg(python3.9+cuda11.3)


路径为python安装路径下的Python39\Lib\site-packages文件夹下

1.png


本人个人电脑懒得安装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())

1.png

返回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 – 要与之进行比较的人脸编码



Top