Dlib模型实现人脸识别

文章目录

  • 一、安装dlib库
  • 二、利用dlib实现人脸68个关键点检测并标注
  • 三、人脸特征提取
  • 四、人脸识别
  • 参考链接

环境说明:
python3.6+spyder
第三方库的说明
skimage,playsound
安装命令:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple scikit-image
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple playsound

一、安装dlib库

  1. 下载Dlib安装包
    下载链接:http://dlib.net/files/
    本文章下载的是dlib-19.14.zip,下载完成后解压安装dlib
  2. 安装Cmake
    下载链接:https://cmake.org/download/
    下载安装包直接点击安装就行,注意环境变量的设置
  3. 下载boost
    下载链接:http://www.boost.org/
    下载之后将其解压缩,进入解压后的文件夹中,找到bootstrap.bat批处理文件,双击运行,等待运行完成后(命令行自动消失)会生成文件b2.exe
    win+R,打开命令行,进入b2.exe所在的文件夹,运行下面命令
    b2 install
    
    b2编译库文件
    b2 -a -python address-model=64 toolset=msvc runtime-link=static
    #cmake下载的64位这里(address-model)写64,如果是32位的就把之前的64改成32
    
    安装完成后配置boost环境变量
    Dlib模型实现人脸识别_第1张图片
  4. 安装dlib
    命令行进入dlib的文件夹中
    python setup.py install
    
    安装完成后,在文件夹下面会出现dlib,dlib.egg-info,dist的三个文件夹
    将dlib 和dlib.egg-info 复制对应python环境下的Lib文件,同时将build\lib.win-amd64-3.6文件夹下的dlib.cp36-win_amd64.pyd复制到对应python环境下的DLL文件夹
    测试是否安装成功(没有报错,表示安装成功)
    Dlib模型实现人脸识别_第2张图片

二、利用dlib实现人脸68个关键点检测并标注

  1. 下载官方的训练模型
    下载链接:
    http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2
  2. 人脸检测和标注
    import numpy as np
    import cv2
    import dlib 
    
    #detector = dlib.get_frontal_face_detector()
    detector=dlib.get_frontal_face_detector()
    predictor = dlib.shape_predictor('E:\\PersonRecognitionDlib\\shape_predictor_68_face_landmarks.dat\\shape_predictor_68_face_landmarks.dat')
    
    # cv2读取图像
    img = cv2.imread("E:\\PersonRecognitionDlib\\text.jpg")
    #print(img)
    # 取灰度
    img_gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
    
    # 人脸数rects
    rects = detector(img_gray, 1)
    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])
            print(idx,pos)
    
            # 利用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)
    
    标注结果
    Dlib模型实现人脸识别_第3张图片
    问题描述:module 'dlib' has no attribute 'get_frontal_face_detector'
    解决方法:将python环境更换为3.6

三、人脸特征提取

  1. 人脸数据集
    ①使用摄像头采集(视频流截图)
    采集的过程,最好使用同一设备同一光线下进行采集
    import cv2
    import dlib
    import os
    import sys
    import random
    # 存储位置
    output_dir = 'D:/myworkspace/JupyterNotebook/People/person/person1'
    size = 64
     
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)
    # 改变图片的亮度与对比度
     
    def relight(img, light=1, bias=0):
        w = img.shape[1]
        h = img.shape[0]
        #image = []
        for i in range(0,w):
            for j in range(0,h):
                for c in range(3):
                    tmp = int(img[j,i,c]*light + bias)
                    if tmp > 255:
                        tmp = 255
                    elif tmp < 0:
                        tmp = 0
                    img[j,i,c] = tmp
        return img
     
    #使用dlib自带的frontal_face_detector作为我们的特征提取器
    detector = dlib.get_frontal_face_detector()
    # 打开摄像头 参数为输入流,可以为摄像头或视频文件
    camera = cv2.VideoCapture(0)
    index = 1
    while True:
        if (index <= 15):#存储15张人脸特征图像
            print('Being processed picture %s' % index)
            # 从摄像头读取照片
            success, img = camera.read()
            # 转为灰度图片
            gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            # 使用detector进行人脸检测
            dets = detector(gray_img, 1)
     
            for i, d in enumerate(dets):
                x1 = d.top() if d.top() > 0 else 0
                y1 = d.bottom() if d.bottom() > 0 else 0
                x2 = d.left() if d.left() > 0 else 0
                y2 = d.right() if d.right() > 0 else 0
     
                face = img[x1:y1,x2:y2]
                # 调整图片的对比度与亮度, 对比度与亮度值都取随机数,这样能增加样本的多样性
                face = relight(face, random.uniform(0.5, 1.5), random.randint(-50, 50))
     
                face = cv2.resize(face, (size,size))
     
                cv2.imshow('image', face)
     
                cv2.imwrite(output_dir+'/'+str(index)+'.jpg', face)
     
                index += 1
            key = cv2.waitKey(30) & 0xff
            if key == 27:
                break
        else:
            print('Finished!')
            # 释放摄像头 release camera
            camera.release()
            # 删除建立的窗口 delete all the windows
            cv2.destroyAllWindows()
            break
    
    Dlib模型实现人脸识别_第4张图片
    在对应的输出目录下,会得到15张摄像头采集得到的图片。
    ②网络爬虫获取
    具体内容可以参考链接:
    https://blog.csdn.net/cungudafa/article/details/87862687
  2. 数据集的处理
  3. 获取特征点
    ①下载dlib的人脸识别模型
    下载链接:
    https://pan.baidu.com/s/1sBH4TvIfIYLFYs7zCTH4nA
    提取码:b8zu
    ②获取每个人68个特征数据并保存到csv中
    from cv2 import cv2 as cv2
    import os
    import dlib
    from skimage import io
    import csv
    import numpy as np
    
    # 要读取人脸图像文件的路径
    path_images_from_camera = "E:/PersonRecognitionDlib/Person/"
    
    # Dlib 正向人脸检测器
    detector = dlib.get_frontal_face_detector()
    
    # Dlib 人脸预测器
    predictor = dlib.shape_predictor("E:/PersonRecognitionDlib/model/shape_predictor_68_face_landmarks.dat")
    
    # Dlib 人脸识别模型
    # Face recognition model, the object maps human faces into 128D vectors
    face_rec = dlib.face_recognition_model_v1("E:/PersonRecognitionDlib/model/dlib_face_recognition_resnet_model_v1.dat")
    
    
    # 返回单张图像的 128D 特征
    def return_128d_features(path_img):
        img_rd = io.imread(path_img)
        img_gray = cv2.cvtColor(img_rd, cv2.COLOR_BGR2RGB)
        faces = detector(img_gray, 1)
    
        print("%-40s %-20s" % ("检测到人脸的图像 / image with faces detected:", path_img), '\n')
    
        # 因为有可能截下来的人脸再去检测,检测不出来人脸了
        # 所以要确保是 检测到人脸的人脸图像 拿去算特征
        if len(faces) != 0:
            shape = predictor(img_gray, faces[0])
            face_descriptor = face_rec.compute_face_descriptor(img_gray, shape)
        else:
            face_descriptor = 0
            print("no face")
    
        return face_descriptor
    
    
    # 将文件夹中照片特征提取出来, 写入 CSV
    def return_features_mean_personX(path_faces_personX):
        features_list_personX = []
        photos_list = os.listdir(path_faces_personX)
        if photos_list:
            for i in range(len(photos_list)):
                # 调用return_128d_features()得到128d特征
                print("%-40s %-20s" % ("正在读的人脸图像 / image to read:", path_faces_personX + "/" + photos_list[i]))
                features_128d = return_128d_features(path_faces_personX + "/" + photos_list[i])
                #  print(features_128d)
                # 遇到没有检测出人脸的图片跳过
                if features_128d == 0:
                    i += 1
                else:
                    features_list_personX.append(features_128d)
        else:
            print("文件夹内图像文件为空 / Warning: No images in " + path_faces_personX + '/', '\n')
    
        # 计算 128D 特征的均值
        # N x 128D -> 1 x 128D
        if features_list_personX:
            features_mean_personX = np.array(features_list_personX).mean(axis=0)
        else:
            features_mean_personX = '0'
    
        return features_mean_personX
    
    
    # 读取某人所有的人脸图像的数据
    people = os.listdir(path_images_from_camera)
    people.sort()
    
    with open("E:/PersonRecognitionDlib/feature/features2_all.csv", "w", newline="") as csvfile:
        writer = csv.writer(csvfile)
        for person in people:
            print("##### " + person + " #####")
            # Get the mean/average features of face/personX, it will be a list with a length of 128D
            features_mean_personX = return_features_mean_personX(path_images_from_camera + person)
            writer.writerow(features_mean_personX)
            print("特征均值 / The mean of features:", list(features_mean_personX))
            print('\n')
        print("所有录入人脸数据存入 / Save all the features of faces registered into: D:/myworkspace/JupyterNotebook/People/feature/features_all2.csv")
    
    Dlib模型实现人脸识别_第5张图片

四、人脸识别

  1. 计算距离——欧氏距离
    将要识别的对象与已经存在的对象进行距离计算
    def return_euclidean_distance(feature_1, feature_2):
        feature_1 = np.array(feature_1)
        feature_2 = np.array(feature_2)
        dist = np.sqrt(np.sum(np.square(feature_1 - feature_2)))
        return dist
    
  2. 实现人脸识别
    # 摄像头实时人脸识别
    import os
    import winsound # 系统音效
    from playsound import playsound # 音频播放
    import dlib          # 人脸处理的库 Dlib
    import csv # 存入表格
    import time
    import sys
    import numpy as np   # 数据处理的库 numpy
    from cv2 import cv2 as cv2           # 图像处理的库 OpenCv
    import pandas as pd  # 数据处理的库 Pandas
    
    
    # 人脸识别模型,提取128D的特征矢量
    # face recognition model, the object maps human faces into 128D vectors
    # Refer this tutorial: http://dlib.net/python/index.html#dlib.face_recognition_model_v1
    facerec = dlib.face_recognition_model_v1("E:/PersonRecognitionDlib/model/dlib_face_recognition_resnet_model_v1.dat")
    
    
    # 计算两个128D向量间的欧式距离
    # compute the e-distance between two 128D features
    def return_euclidean_distance(feature_1, feature_2):
        feature_1 = np.array(feature_1)
        feature_2 = np.array(feature_2)
        dist = np.sqrt(np.sum(np.square(feature_1 - feature_2)))
        return dist
    
    
    # 处理存放所有人脸特征的 csv
    path_features_known_csv = "E:/PersonRecognitionDlib/feature/features2_all.csv"
    csv_rd = pd.read_csv(path_features_known_csv, header=None)
    
    
    # 用来存放所有录入人脸特征的数组
    # the array to save the features of faces in the database
    features_known_arr = []
    
    # 读取已知人脸数据
    # print known faces
    for i in range(csv_rd.shape[0]):
        features_someone_arr = []
        for j in range(0, len(csv_rd.iloc[i, :])):
            features_someone_arr.append(csv_rd.iloc[i, :][j])
        features_known_arr.append(features_someone_arr)
    print("Faces in Database:", len(features_known_arr))
    
    # Dlib 检测器和预测器
    # The detector and predictor will be used
    detector = dlib.get_frontal_face_detector()
    predictor = dlib.shape_predictor('E:/PersonRecognitionDlib/model/shape_predictor_68_face_landmarks.dat')
    
    # 创建 cv2 摄像头对象
    # cv2.VideoCapture(0) to use the default camera of PC,
    # and you can use local video name by use cv2.VideoCapture(filename)
    cap = cv2.VideoCapture(0)
    
    # cap.set(propId, value)
    # 设置视频参数,propId 设置的视频参数,value 设置的参数值
    cap.set(3, 480)
    
    # cap.isOpened() 返回 true/false 检查初始化是否成功
    # when the camera is open
    while cap.isOpened():
    
        flag, img_rd = cap.read()
        kk = cv2.waitKey(1)
    
        # 取灰度
        img_gray = cv2.cvtColor(img_rd, cv2.COLOR_RGB2GRAY)
    
        # 人脸数 faces
        faces = detector(img_gray, 0)
    
        # 待会要写的字体 font to write later
        font = cv2.FONT_HERSHEY_COMPLEX
    
        # 存储当前摄像头中捕获到的所有人脸的坐标/名字
        # the list to save the positions and names of current faces captured
        pos_namelist = []
        name_namelist = []
    
        # 按下 q 键退出
        # press 'q' to exit
        if kk == ord('q'):
            break
        else:
            # 检测到人脸 when face detected
            if len(faces) != 0:  
                # 获取当前捕获到的图像的所有人脸的特征,存储到 features_cap_arr
                # get the features captured and save into features_cap_arr
                features_cap_arr = []
                for i in range(len(faces)):
                    shape = predictor(img_rd, faces[i])
                    features_cap_arr.append(facerec.compute_face_descriptor(img_rd, shape))
    
                # 遍历捕获到的图像中所有的人脸
                # traversal all the faces in the database
                for k in range(len(faces)):
                    print("##### camera person", k+1, "#####")
                    # 让人名跟随在矩形框的下方
                    # 确定人名的位置坐标
                    # 先默认所有人不认识,是 unknown
                    # set the default names of faces with "unknown"
                    name_namelist.append("unknown")
    
                    # 每个捕获人脸的名字坐标 the positions of faces captured
                    pos_namelist.append(tuple([faces[k].left(), int(faces[k].bottom() + (faces[k].bottom() - faces[k].top())/4)]))
    
                    # 对于某张人脸,遍历所有存储的人脸特征
                    # for every faces detected, compare the faces in the database
                    e_distance_list = []
                    for i in range(len(features_known_arr)):
                        # 如果 person_X 数据不为空
                        if str(features_known_arr[i][0]) != '0.0':
                            print("with person", str(i + 1), "the e distance: ", end='')
                            e_distance_tmp = return_euclidean_distance(features_cap_arr[k], features_known_arr[i])
                            print(e_distance_tmp)
                            e_distance_list.append(e_distance_tmp)
                        else:
                            # 空数据 person_X
                            e_distance_list.append(999999999)
                    # 找出最接近的一个人脸数据是第几个
                    # Find the one with minimum e distance
                    similar_person_num = e_distance_list.index(min(e_distance_list))
                    print("Minimum e distance with person", int(similar_person_num)+1)
                    
                    # 计算人脸识别特征与数据集特征的欧氏距离
                    # 距离小于0.4则标出为可识别人物
                    if min(e_distance_list) < 0.4:
                        # 这里可以修改摄像头中标出的人名
                        # Here you can modify the names shown on the camera
                        # 1、遍历文件夹目录
                        folder_name = 'E:/PersonRecognitionDlib/Person'
                        # 最接近的人脸
                        sum=similar_person_num+1
                        key_id=1 # 从第一个人脸数据文件夹进行对比
                        # 获取文件夹中的文件名:LQH、YYQX、WY、WL...
                        file_names = os.listdir(folder_name)
                        for name in file_names:
                            # print(name+'->'+str(key_id))
                            if sum ==key_id:
                                #winsound.Beep(300,500)# 响铃:300频率,500持续时间
                                name_namelist[k] = name[0:]#人名删去第一个数字(用于视频输出标识)
                            key_id += 1
                        # 播放欢迎光临音效
                        #playsound('D:/myworkspace/JupyterNotebook/People/music/welcome.wav')
                        # print("May be person "+str(int(similar_person_num)+1))
                        # -----------筛选出人脸并保存到visitor文件夹------------
                        for i, d in enumerate(faces):
                            x1 = d.top() if d.top() > 0 else 0
                            y1 = d.bottom() if d.bottom() > 0 else 0
                            x2 = d.left() if d.left() > 0 else 0
                            y2 = d.right() if d.right() > 0 else 0
                            face = img_rd[x1:y1,x2:y2]
                            size = 64
                            face = cv2.resize(face, (size,size))
                            # 要存储visitor人脸图像文件的路径
                            path_visitors_save_dir = "E:/PersonRecognitionDlib/visitor/known"
                            # 存储格式:2019-06-24-14-33-40LQH.jpg
                            now_time = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
                            save_name = str(now_time)+str(name_namelist[k])+'.jpg'
                            # print(save_name)
                            # 本次图片保存的完整url
                            save_path = path_visitors_save_dir+'/'+ save_name    
                            # 遍历visitor文件夹所有文件名
                            visitor_names = os.listdir(path_visitors_save_dir)
                            visitor_name=''
                            for name in visitor_names:
                                # 名字切片到分钟数:2019-06-26-11-33-00LQH.jpg
                                visitor_name=(name[0:16]+'-00'+name[19:])
                            # print(visitor_name)
                            visitor_save=(save_name[0:16]+'-00'+save_name[19:])
                            # print(visitor_save)
                            # 一分钟之内重复的人名不保存
                            if visitor_save!=visitor_name:
                                cv2.imwrite(save_path, face)
                                print('新存储:'+path_visitors_save_dir+'/'+str(now_time)+str(name_namelist[k])+'.jpg')
                            else:
                                print('重复,未保存!')
                                
                    else:
                        # 播放无法识别音效
                        #playsound('D:/myworkspace/JupyterNotebook/People/music/sorry.wav')
                        print("Unknown person")
                        # -----保存图片-------
                        # -----------筛选出人脸并保存到visitor文件夹------------
                        for i, d in enumerate(faces):
                            x1 = d.top() if d.top() > 0 else 0
                            y1 = d.bottom() if d.bottom() > 0 else 0
                            x2 = d.left() if d.left() > 0 else 0
                            y2 = d.right() if d.right() > 0 else 0
                            face = img_rd[x1:y1,x2:y2]
                            size = 64
                            face = cv2.resize(face, (size,size))
                            # 要存储visitor-》unknown人脸图像文件的路径
                            path_visitors_save_dir = "E:/PersonRecognitionDlib/visitor/unknown"
                            # 存储格式:2019-06-24-14-33-40unknown.jpg
                            now_time = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
                            # print(save_name)
                            # 本次图片保存的完整url
                            save_path = path_visitors_save_dir+'/'+ str(now_time)+'unknown.jpg'
                            cv2.imwrite(save_path, face)
                            print('新存储:'+path_visitors_save_dir+'/'+str(now_time)+'unknown.jpg')
                    
                    # 矩形框
                    # draw rectangle
                    for kk, d in enumerate(faces):
                        # 绘制矩形框
                        cv2.rectangle(img_rd, tuple([d.left(), d.top()]), tuple([d.right(), d.bottom()]), (0, 255, 255), 2)
                    print('\n')
    
                # 在人脸框下面写人脸名字
                # write names under rectangle
                for i in range(len(faces)):
                    cv2.putText(img_rd, name_namelist[i], pos_namelist[i], font, 0.8, (0, 255, 255), 1, cv2.LINE_AA)
    
        print("Faces in camera now:", name_namelist, "\n")
    
        #cv2.putText(img_rd, "Press 'q': Quit", (20, 450), font, 0.8, (84, 255, 159), 1, cv2.LINE_AA)
        cv2.putText(img_rd, "Face Recognition", (20, 40), font, 1, (0, 0, 255), 1, cv2.LINE_AA)
        cv2.putText(img_rd, "Visitors: " + str(len(faces)), (20, 100), font, 1, (0, 0, 255), 1, cv2.LINE_AA)
    
        # 窗口显示 show with opencv
        cv2.imshow("camera", img_rd)
    
    # 释放摄像头 release camera
    cap.release()
    
    # 删除建立的窗口 delete all the windows
    cv2.destroyAllWindows()
    
    整个过程是先进行人脸的检测,检测摄像头所采集到的人脸,然后将检测到的人脸对象与数据集中的人脸68个特征点进行一个距离计算,然后,选出最接近的那个人,接着判断距离小于0.4,就可以标识出识别人物。
    Dlib模型实现人脸识别_第6张图片
    Dlib模型实现人脸识别_第7张图片

参考链接

  1. python3.7添加dlib模块
  2. python+OpenCv+dlib实现人脸68个关键点检测并标注
  3. 基于dlib库人脸特征提取【构建自己的人脸识别数据集】

你可能感兴趣的:(机器学习,dlib,人脸识别)