基于python版本的dlib库进行人脸识别(代码片段)

Console_K Console_K     2022-12-23     323

关键词:

最近冒出做人脸识别的想法,在github上正巧看到这个项目,在了解了大概思路之后打算自己独立复刻出这个人脸识别项目。由于笔者自身代码水平并不高,若有地方错误或者不合适的,还希望大神能够指出,感谢交流!写完这篇文章后感觉又收获不少东西。

 项目特点

  • 可自行建立人脸特征库
  • 可实时对单张或多张人脸进行识别

dlib库简介

Dlib 是一个现代C++工具包,包含机器学习算法和工具,用于在C++中创建复杂的软件,以解决现实世界中的问题。按照dlib官网的叙述,其特点主要有:

  1. 丰富的帮助文档:dlib官网为每个类与功能都提供了完整的帮助文档,且官网提供有非常多的例程。作者在官网有说如果有东西文件没记录或者不清楚的可以联系他更改。
  2. 高质量的可移植代码:dlib库不需要第三方库且符合ISO C++标准,支持Windows, Linux, Mac OS X系统。
  3. 丰富的机器学习算法:dlib库中包括深度学习算法、SVM以及一些常用的聚类算法等。
  4. 图像处理:支持读写windows BMP文件、可实现各种色彩空间的图像变换、包括物体检测的一些工具以及高质量的人脸识别功能。
  5. 线程:提供了简单可移植的线程API。

环境建立

笔者实验时的主要环境如下:

python = 3.6.4

dlib = 19.8.1

opencv = 3.4.1.15

tqdm = 4.62.1

  1. 首先是建立环境。打开Anaconda Prompt,输入如下命令新建名为dlibTest(可更改,后续激活注意对应)、python版本为3.6.4的环境,这个环境专门用来存放该实验所用到的库。建立完成后输入第二行命令激活环境。
    conda create -n dlibTest python=3.6.4
    conda activate dlibTest
  2. 继续输入如下命令安装与实验对应版本的库,安装opencv时会自动帮我们安装numpy库。
    pip install dlib==19.8.1
    pip install opencv-python==3.4.1.15
    pip install tqdm

使用dlib库进行人脸识别

一、采集人脸数据 

先在代码中定义dlib用于人脸识别的检测器和特征提取器

detector = dlib.get_frontal_face_detector()                                         # 人脸检测器
# detector = dlib.cnn_face_detection_model_v1(model_path)

predictor = dlib.shape_predictor(shape_predictor_path)                              # 人脸68点提取器
# shape_predictor_path = 'data_dlib/shape_predictor_68_face_landmarks.dat'

recognition_model = dlib.face_recognition_model_v1(recognition_model_path)          # 基于resnet的128维特征向量提取器
# recognition_model_path = 'data_dlib/dlib_face_recognition_resnet_model_v1.dat'

 其中,人脸检测器detector也可用cnn进行检测。

人脸数据可以用网上的照片,也可以自己通过摄像头采集。

通过摄像头获取图像进行人脸识别的代码如下,运行过程中可收集人脸数据,检测到人脸后按下“n”可新建人脸文件夹,之后再按下“s”可对人脸图像进行保存。因为一次采集的数据均放在一个文件夹下,故一次采集应只对一人进行。

import cv2 as cv
import time
import os
import config

class face_detect():
    def __init__(self):
        self.start_time = 0                     # 用于计算帧率
        self.fps = 0                            # 帧率

        self.image = None
        self.face_img = None

        self.face_num = 0                       # 这一帧的人脸个数
        self.last_face_num = 0                  # 上一帧的人脸个数

        self.face_num_change_flag = False       # 当前帧人脸数量变化的标志位,用于后续人脸识别提高帧率
        self.quit_flag = False                  # 退出程序标志位
        self.buildNewFolder = False             # 按下"n"新建文件夹标志位
        self.save_flag = False                  # 按下“s”保存人脸数据标志位
        self.face_flag = False                  # 人脸检测标志位

        self.img_num = 0                        # 人脸数据文件夹内的图像个数

        self.collect_face_data = True           # 是否进行人脸数据的采集,只有为真时才会进行采集

    def get_fps(self):
        now = time.time()
        time_period = now - self.start_time
        self.fps = 1.0 / time_period
        self.start_time = now
        color = (0,255,0)
        if self.fps < 15:
            color = (0,0,255)
        cv.putText(self.image, str(self.fps.__round__(2)), (20, 50), cv.FONT_HERSHEY_DUPLEX, 1, color)

    def key_scan(self, key):
        if self.collect_face_data == True:
            if self.save_flag == True and self.buildNewFolder == True:
                if self.face_img.size > 0:
                    cv.imwrite(
                        config.faceData_path + 'person_/.png'.format(config.num_of_person_in_lib - 1, self.img_num),
                        self.face_img)
                    self.img_num += 1

            if key == ord('s'):
                self.save_flag = not self.save_flag

            if key == ord('n'):
                os.makedirs(config.faceData_path + 'person_'.format(config.num_of_person_in_lib))
                config.num_of_person_in_lib += 1
                print("新文件夹建立成功!!")
                self.buildNewFolder = True
        if key == ord('q'): self.quit_flag = True

    def face_detecting(self):
        face_location = []
        all_face_location = []

        faces = config.detector(self.image, 0)
        self.face_num = len(faces)

        if self.face_num != self.last_face_num:
            self.face_num_change_flag = True
            print("脸数改变,由张变为张".format(self.last_face_num, self.face_num))
            self.check_times = 0
            self.last_face_num = self.face_num
        else:
            self.face_num_change_flag = False

        if len(faces) != 0:
            self.face_flag = True

            for i, face in enumerate(faces):
                face_location.append(face)
                w, h = (face.right() - face.left()), (face.bottom() - face.top())
                left, right, top, bottom = face.left() - w//4, face.right() + w//4, face.top() - h//2, face.bottom() + h//4

                all_face_location.append([left, right, top, bottom])

            return face_location, all_face_location
        else:
            self.face_flag = False

        return None

    def show(self, camera):
        while camera.isOpened() and not self.quit_flag:
            val, self.image = camera.read()
            if val == False: continue

            key = cv.waitKey(1)

            res = self.face_detecting()
            if res is not None:
                _, all_face_location = res

                for i in range(self.face_num):
                    [left, right, top, bottom] = all_face_location[i]
                    self.face_img = self.image[top:bottom, left:right]
                    cv.rectangle(self.image, (left, top), (right, bottom), (0, 0, 255))

                    if self.collect_face_data == True:
                        cv.putText(self.image, "Face", (int((left + right) / 2) - 50, bottom + 20), cv.FONT_HERSHEY_COMPLEX, 1,
                                   (255, 255, 255))

                self.key_scan(key)

            self.get_fps()

            cv.namedWindow('camera', 0)
            cv.imshow('camera', self.image)

        camera.release()
        cv.destroyAllWindows()

def main():
    try:
        cam = cv.VideoCapture(0)
        face_detect().show(cam)
    finally:
        cam.release()
        cv.destroyAllWindows()
        print("程序退出!!")

if __name__ == '__main__':
    main()

具体检测效果如下图所示,马赛克为后期增加

 

 采集的人脸数据在工程文件夹faceData下,这里三个文件夹分别存放刘德华、王冰冰、西野七濑的图片:

 

  

 下一步再对记录人脸名字的txt文件进行修改,注意顺序与faceData内存放人脸图像的文件夹顺序对应。

 

二、获取128维特征向量

 首先是对前一步采集到的人脸图像进行人脸检测(避免有时候cv展示的图像上检测到人脸,但保存下来的图像却检测不到而报错),再对检测到人脸的图像进行68个人脸关键点的提取,提取效果如下图所示:

 之后再将这68个点的值输入到resnet模型中抽象出128维的人脸特征向量,进而保存在csv文件夹中从而建立了一个人脸数据库。

获取特征向量的函数如下:

def get_128_features(person):                    # person代表第几个人脸数据文件夹
    num = 0
    features = []
    imgs_folder = config.imgs_folder_path[person]
    points_faceImage_path = config.points_faceData_path + imgs_folder

    imgs_path = config.faceData_path + imgs_folder + '/'
    list_imgs = os.listdir(imgs_path)
    imgs_num = len(list_imgs)

    if os.path.exists(config.points_faceData_path + imgs_folder):
        shutil.rmtree(points_faceImage_path)
    os.makedirs(points_faceImage_path)
    print("人脸点图文件夹建立成功!!")

    with tqdm(total=imgs_num) as pbar:
        pbar.set_description(str(imgs_folder))
        for j in range(imgs_num):
            image = cv.imread(os.path.join(imgs_path, list_imgs[j]))

            faces = config.detector(image, 1)           # 经查阅资料,这里的1代表采样次数
            if len(faces) != 0:
                for z, face in enumerate(faces):
                    shape = config.predictor(image, face)       # 获取68点的坐标

                    w, h = (face.right() - face.left()), (face.bottom() - face.top())
                    left, right, top, bottom = face.left() - w // 4, face.right() + w // 4, face.top() - h // 2, face.bottom() + h // 4
                    im = image

                    cv.rectangle(im, (left, top), (right, bottom), (0, 0, 255))
                    cv.imwrite(points_faceImage_path + '/.png'.format(j), im)

                    if config.get_points_faceData_flag == True:
                        for p in range(0, 68):
                            cv.circle(image, (shape.part(p).x, shape.part(p).y), 2, (0,0,255))
                        cv.imwrite(points_faceImage_path + '/.png'.format(j), image)

                    the_features = list(config.recognition_model.compute_face_descriptor(image, shape)) # 获取128维特征向量
                    features.append(the_features)
                    #print("第张图片,第张脸,特征向量为:".format(j+1, z+1, the_features))
                    num += 1
            pbar.update(1)

    np_f = np.array(features)
    #res = np.mean(np_f, axis=0)
    res = np.median(np_f, axis=0)

    return res

三、人脸识别

建立好人脸数据库后就可开始进行人脸识别了,其过程也是和之前类似。先获取图像、对图像进行人脸检测、检测到人脸后进行特征抽象、将库内的特征向量逐个与当前的特征向量进行欧氏距离的计算、根据阈值判断是否属于库内人脸。

其中,n维空间计算欧氏距离的公式如下:

 运用numpy库计算向量间欧式距离的代码如下:

    def calculate_EuclideanDistance(self, feature1, feature2):          # 计算欧氏距离
        np_feature1 = np.array(feature1)
        np_feature2 = np.array(feature2)

        EuclideanDistance = np.sqrt(np.sum(np.square(np_feature1 - np_feature2)))

        return EuclideanDistance

人脸识别代码中进行了5次的人脸识别,之后取每个特征分量的中值得到最终预测的特征向量,尽量减少干扰。self.init_process()是进行加载库以及名字的操作:

    def recognition_from_cam(self):
        self.init_process()
        while self.camera.isOpened() and not self.quit_flag:
            val, self.image = self.camera.read()
            if val == False: continue

            #self.image = cv.imread('./data/test/test_bb.jpg')

            key = cv.waitKey(1)

            res = self.face_detecting()         # 0.038s

            if res is not None:
                face, self.all_face_location = res

                for i in range(self.face_num):
                    [left, right, top, bottom] = self.all_face_location[i]
                    self.middle_point = [(left + right) /2, (top + bottom) / 2]

                    self.face_img = self.image[top:bottom, left:right]

                    cv.rectangle(self.image, (left, top), (right, bottom), (0, 0, 255))

                    shape = config.predictor(self.image, face[i])       # 0.002s

                    if self.face_num_change_flag == True or self.check_times <= 5:
                        if self.face_num_change_flag == True:       # 人脸数量有变化,重新进行五次检测
                            self.check_times = 0
                            self.last_now_middlePoint_eDistance = [99999 for _ in range(self.available_max_face_num)]
                            for z in range(self.available_max_face_num):    self.check_features_from_cam[z] = []

                        if self.check_times < 5:
                            the_features_from_cam = list(config.recognition_model.compute_face_descriptor(self.image, shape))   # 耗时主要在这步 0.32s
                            if self.check_times == 0:           # 初始帧
                                self.check_features_from_cam[i].append(the_features_from_cam)
                                self.last_frame_middle_point[i] = self.middle_point
                            else:
                                this_face_index = self.track_link()         # 后续帧需要与初始帧的人脸序号对应
                                self.check_features_from_cam[this_face_index].append(the_features_from_cam)

                        elif self.check_times == 5:
                            features_after_filter = self.middle_filter(self.check_features_from_cam[i])
                            self.check_features_from_cam[i] = []
                            for person in range(config.num_of_person_in_lib):
                                e_distance = self.calculate_EuclideanDistance(self.all_features[person],
                                                                              features_after_filter)  # 几乎不耗时

                                self.all_e_distance[i].append(e_distance)

                            if min(self.all_e_distance[i]) < config.recognition_threshold:
                                self.person_name[i] = self.all_name[self.all_e_distance[i].index(min(self.all_e_distance[i]))]
                                cv.putText(self.image, self.person_name[i],
                                           (int((left + right) / 2) - 50, bottom + 20),
                                           cv.FONT_HERSHEY_COMPLEX, 1, (255, 255, 255))
                            else:
                                self.person_name[i] = "Unknown"

                            print("预测结果为:, 与库中各人脸的欧氏距离为:".format(self.person_name[i], self.all_e_distance[i]))

                    else:
                        this_face_index = self.track_link()
                        #print(this_face_index, self.person_name)
                        cv.putText(self.image, self.person_name[this_face_index], (int((left + right) / 2) - 50, bottom + 20),
                                   cv.FONT_HERSHEY_COMPLEX, 1, (255, 255, 255))
                self.check_times += 1

                for j in range(self.available_max_face_num):
                    self.all_e_distance[j] = []

                self.key_scan(key)

            self.get_fps()
            cv.namedWindow('camera', 0)
            cv.imshow('camera', self.image)

        self.camera.release()
        cv.destroyAllWindows()

具体识别效果如下图所示

单张人脸

 多张人脸

由于库中没有薛之谦的人脸数据,故识别出来为Unknown。

实例给的是直接读取图片,观赏效果会比较好。也可以摄像头读取图像进行识别,但若每次都进行特征向量提取,则会浪费大量时间从而导致帧率过低。原项目作者是根据前后帧的人脸数量是否发生变化来判断是否进行特征提取的,若人脸数量发生变化,则对每张人脸进行特征提取;否则就只进行人脸检测+人脸跟踪。这样就省掉了后续帧不必要的特征提取,提高了帧率。

实际效果如下图所示(13帧左右)

一般情况下的帧率(15帧左右)

我的代码放在consolas-K/dlib_faceRecognition: 使用dlib进行人脸识别 (github.com),原项目作者的代码在参考资料中。

参考资料

人脸识别基于dlib库实现人脸特征值提取(代码片段)

目录一、Dlib库介绍与安装1.Dlib库简介2.安装Dlib库二、OpenCV介绍即安装1.OpenCV简介2.OpenCV安装三、提取人脸特征点四、在眼睛处绘制黑色的实心圆五、总结六、参考一、Dlib库介绍与安装1.Dlib库简介  Dlib库是一个机器学习的开源... 查看详情

如何线上部署用python基于dlib写的人脸识别算法

python使用dlib进行人脸检测与人脸关键点标记Dlib简介:首先给大家介绍一下DlibDlib是一个跨平台的C++公共库,除了线程支持,网络支持,提供测试以及大量工具等等优点,Dlib还是一个强大的机器学习的C++库,包含了许多机器学习... 查看详情

基于dlib进行人脸识别demo(代码片段)

环境准备:win10,python3.9,cv2,numpy,dlib项目所要达到的目的:实现人脸识别(输入几张图片,人脸检测、关键点检测、人脸关键点进行编码存储起来,再传进来一张图片,判断新传来来这... 查看详情

基于dlib进行人脸识别demo(代码片段)

环境准备:win10,python3.9,cv2,numpy,dlib项目所要达到的目的:实现人脸识别(输入几张图片,人脸检测、关键点检测、人脸关键点进行编码存储起来,再传进来一张图片,判断新传来来这... 查看详情

基于python如何建立人脸库

您好,基于Python建立人脸库的方法如下:1.安装Python和相关包:首先,您需要安装Python和相关的包,如OpenCV、NumPy等,以便使用Python来处理图像和视频。2.获取人脸数据:您需要获取足够多的人脸数据,以便训练模型。3.提取特征... 查看详情

dlib库包的介绍与使用,opencv+dlib检测人脸框opencv+dlib进行人脸68关键点检测,opencv+dlib实现人脸识别,dlib进行人脸特征聚类dlib视频目标跟踪(代码片段)

...区域关键点连线3.1dlib人脸关键点检测源码3.2opencv+dlib进行人脸关键点检测4dlib人脸识别4.1dlib进行人脸识别逻辑4.2opencv+dlib进行人脸识别4.3人脸识别总结5dlib人脸聚类6dlib视频目标跟踪1dlib库介绍dlib官网:http://dlib.net/dlib模... 查看详情

dlib人脸识别(代码片段)

...络?所以dlib识别准确率,要比opencv(cv2)高?pipinstallopencv-python?我们就可以在代码中,导包了?dlib调用相应方法,识别人脸?face_detector=dlib.get_frontal_face_detector()?调用:?人脸坐标数据?faces=face_detector(image,1)?绘制:forfaceinfaces:left=face.le... 查看详情

基于dlib人脸检测(图像视频)demo(代码片段)

1、Dlib是一个深度学习开源工具,基于C++开发,也支持Python开发接口2、由于Dlib对于人脸特征提取支持很好,很多训练好的人脸特征提取模型提供开发者使用,所以Dlib人脸识别开发很适合做人脸项目开发官网... 查看详情

基于dlib人脸检测(图像视频)demo(代码片段)

1、Dlib是一个深度学习开源工具,基于C++开发,也支持Python开发接口2、由于Dlib对于人脸特征提取支持很好,很多训练好的人脸特征提取模型提供开发者使用,所以Dlib人脸识别开发很适合做人脸项目开发官网... 查看详情

[深度学习工具]·极简安装dlib人脸识别库(代码片段)

...小。推荐使用清华源,下载安装,选择合适的平台版本。python==3.6安装dlib以管理员身份进入CMD,执行condainstall-cconda-forgedlib测试代码#%%importdlibfromimageioimportimreadimportglobdetector=dlib.get_frontal_face_detector()win=dlib.image_window()paths=glob.glob(... 查看详情

用20行python代码实现人脸识别!

...可以使用Python和命令行工具进行提取、识别、操作人脸。基于业内领先的C++开源库dlib中的深度学习模型,用LabeledFacesintheWild人脸数据集进行测试,有高达99.38%的准确率。1.安装最好是使用Linux或Mac环境来安装,Windows下安装会有很... 查看详情

[深度学习]python人脸识别库face_recognition使用教程(代码片段)

Python人脸识别库face_recognition使用教程face_recognition号称是世界上最简单的开源人脸识别库,可以通过Python或命令行识别和操作人脸。face_recognition提供了十分完整的技术文档和应用实例,人脸识别初学者建议研究该库上手... 查看详情

人脸识别完整项目实战:完整项目案例运行演示

...节的代码设计、运行演示和执行结果输出;模型训练篇:基于人脸识别区域检测和人俩识别特征点标定两个应用场景,介绍数据样本采集、算法模型训练和算法模型测试的过程,让大家都人脸识别有一个完整的直观的认识;算法... 查看详情

基于python的人脸识别和焦点人物检测(代码片段)

写在前面的话基于dlib库的模型,实现人脸识别和焦点人物的检测。最后呈现的效果为焦点人物的识别框颜色与其他人物框不一样。准备工作需要安装好python环境,安装好dlib、opencv-python库等,具体可以看报错信息࿰... 查看详情

用dlib进行简单的人脸特征提取特征向量到csv文件中,用knn进行预测识别(代码片段)

目标要求:基于收集的全班人脸数据实现分类识别,要求基于图片进行比对识别。任务流程大致分为以下过程:1)模型准备:下载并部署一个人脸特征提取模型(功能包括人脸检测、人脸特征提取,不限算法,比... 查看详情

山东大学项目实训四——face_recognition使用opencv和dlib实现基于视频的人脸识别(代码片段)

Face_Recognition使用Opencv和Dlib实现基于视频的人脸识别文件夹介绍1、Resources\\pictures此文件夹下存放人脸保存结果2、Resources\\video此文件夹下存放带标注视频保存结果3、Resources\\faceS此文件夹下存放各个人物的图片,用于人脸库... 查看详情

人脸识别----face_recognition安装与应用(附代码)(代码片段)

  face_recognition号称是世界上最简单的基于python的人脸识别库,是在大名鼎鼎的深度学习框架dlib上做的整合,dlib模型在LFW(LabeledFacesintheWild)能有99.38的准确率。另外face_recognition提供了相应的命令行工具,可以通过命令... 查看详情

python3利用dlib实现摄像头实时人脸识别(代码片段)

引言利用python开发,对于输入的摄像头视频流,借助Dlib提供的检测识别模式来进行人脸识别,首先,从摄像头中录入(裁剪)人脸图片存蓄到本地,然后提取特征,构建预设人脸特征,根据抠... 查看详情