5

Python 人脸识别,比对,机器训练,离线识别.人脸采集的功能实现及code

博主还是抱着开源精神,因为下面这些code是经过了上千次baidu和google搜索出来得到的结果及其想法,提供给大家共同学习进步,注释的都很清楚,功能完全实现
先上一下效果图

image.png
(我知道我很帅,请勿吐槽,谢谢.否则请直接exit())

很长时间没发文了,今天跟大家分享一下关于Python原生的人脸识别(不调用任何第三方的接口),离线版本.

刚开始编写的时候,参考了很多的文章,首先在此先进行感谢一波!

文章可能讲的比较片面,但是你把我在文章的code copy下去,肯定包你能用,识别率可以达到百分之90以上,代码性能有待优化.但是授之以鱼,不如授之以渔.下方我会开始从环境的部署开始讲解.有讲错或者bug的地方,欢迎给我留言.
  • 文章会从所调用的库进行介绍.而后介绍库的安装及部署,希望大家耐心看:

    1. OPENCVOpenCV是一个基于BSD许可(开源)发行的跨平台计算机视觉库,可以运行在Linux、Windows、Android和Mac OS操作系统上。它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了Python、Ruby、MATLAB等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法
    2. Dlib is a modern C++ toolkit containing machine learning algorithms and tools for creating complex software in C++ to solve real world problems. It is used in both industry and academia in a wide range of domains including robotics, embedded devices, mobile phones, and large high performance computing environments. Dlib's open source licensing allows you to use it in any application, free of charge.摘抄自于DLIB的官网
    3. face_recognition 这是整个我们需要进行人脸识别,比对.欧式距离分析比较重要的库
    4. 剩下比较重要的两个库,在此不做简绍:json numpy.
  • 下面将会介绍库的导入,请务必按照文中顺序跟随(文中环境,命令以mac为主)

    1. 在安装dlib之前,首先必须安装cmake库,直接命令pip3 install cmake
    2. 安装完cmake之后继续安装boost库,命令:pip3 install boost
    3. 安装opecv库,命令 pip3 install opencv.导入的时候注意,code为:import cv2;为什么是cv2,我google查过,因为版本迭代的问题.所以无需太在意
    4. 安装完上述两个库之后,到了最麻烦的dlib库,首先还是用命令:pip3 install dlib 进行安装.但是这只是下载下来,如下载过程比较慢,建议使用切换一下源,建议使用阿里巴巴源或者清华大学的源,下载完毕后,会提示你运行setup.py文件.这时候你需要打开python3的库的目录(以mac示例:路径为:/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/),刚才下载的dilb库就在这里,这时候你需要用命令进入该目录.执行(请注意):python setup.py install命令,请别敲错了.
    5. 如果你成功完成了上一步,下面就很简单了.我们继续安装face_recognition库,命令还是:pip3 install face_recognition
    6. 然后剩下的常用库不再做简绍
完成上述步骤后,首先得恭喜你,完成了opencv,face_recognition,dlib的部署.继续下面的工作,您需要先进行阅读下面的文章:来自Github的face_recognition介绍,中文翻译为同济大学的子豪兄Tommy;

看完子豪兄Tommy的github翻译之后,请继续看face_recognition的方法介绍,这是经过博主综合评估及踩坑之后力荐的;

好的,如果你看完了上述资料,那么我开始给大家讲解这次整个人脸识别程序的流程

  1. 打开电脑的摄像头
    camera = cv2.VideoCapture(0) # 调用笔记本内置摄像头,所以参数为0,如果有其他的摄像头可以调整参数为1,2
  2. 调用dlib的面部68点识别训练库文件(这个已经是训练好了的库,请直接使用)直接附上下载链接 传送门文件90多M,慢慢下.
    predictor = dlib.shape_predictor("lib/shape_predictor_68_face_landmarks.dat")
  3. 使用dlib进行面部识别
    detector = dlib.get_frontal_face_detector();

5.然后开始while死循环.进行检测.
6.检测到人脸后,生成特征码face_recognition.face_encodings,而后利用face_recognition的compare_faces方法进行比对
7.返回识别结果

8.文件目录
image.png

ok,废话已经很多.so,下面直接上code,首先从功能性示范开始(代码注释的已经非常详细了,因为我是python菜鸡)
import numpy as np;
import cv2;
import dlib;

camera = cv2.VideoCapture(0)  # 调用笔记本内置摄像头,所以参数为0,如果有其他的摄像头可以调整参数为1,2

# 注释掉opencv的面部分类识别器,因为感觉不是很好使
# detector = cv2.CascadeClassifier('lib/haarcascade_frontalface_default.xml')  # 加载面部识别的分类器

# 改用dlib的面部识别
detector = dlib.get_frontal_face_detector();

# 调用dlib的面部68点识别训练库文件
predictor = dlib.shape_predictor("lib/shape_predictor_68_face_landmarks.dat")


while True:
    result, img = camera.read()  # 因为read方法反回了两个变量.所以需要定义两个变量进行接收该方法的返回值
    # exit();
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 转换图片为灰度
    faces = detector(gray, 1) # 检测出人脸数
    # len(faces) > 1
    # 利用cv2.putText输出
    for i in range(len(faces)):
        landmarks = np.matrix([[p.x, p.y] for p in predictor(img, faces[i]).parts()])
        # enumerate是一个Python的内置方法,用于遍历索引
        # index是序号;face是dets中取出的dlib.rectangle类的对象,包含了人脸的区域等信息
        # left()、top()、right()、bottom()都是dlib.rectangle类的方法,对应矩形四条边的位置
        for index, face in enumerate(faces):
            # 这里画出人脸框
            left = face.left()
            top = face.top()
            right = face.right()
            bottom = face.bottom()
            cv2.rectangle(img, (left, top), (right, bottom), (0, 255, 0), 3)

            shape = predictor(img, face)  # 寻找人脸的68个标定点
            print(shape)
            print(shape.num_parts)
            # 遍历所有点,打印出其坐标,并用蓝色的圈表示出来
            for index, pt in enumerate(shape.parts()):
                print('Part {}: {}'.format(index, pt))
                pt_pos = (pt.x, pt.y)
                cv2.circle(img, pt_pos, 2, (0, 255, 0), 1)
                
                cv2.imshow('frame', img)  # 展示

    if cv2.waitKey(1) & 0xFF == ord('q'):  # 监听键盘 每一秒检测一下是否按下了Q.
        break
    else:
        pass  


camera.release()  # 释放摄像头资源
cv2.destroyAllWindows(); # 关闭所有弹出的窗口
下面的是人脸采集
import numpy as np
import cv2
import dlib
import face_recognition

# 注释掉opencv的面部分类识别器,因为感觉不是很好使
# detector = cv2.CascadeClassifier('xml/haarcascade_frontalface_default.xml')

# 改用dlib的面部识别
detector = dlib.get_frontal_face_detector()

# 调用dlib的面部68点识别训练库文件
predictor = dlib.shape_predictor("lib/shape_predictor_68_face_landmarks.dat")


camera = cv2.VideoCapture(0)  # 调用笔记本内置摄像头,所以参数为0,如果有其他的摄像头可以调整参数为1,2

i = 0 # 设置计步器

UID = input('enter your id: ')

while True:
    result, img = camera.read() # 接收噶你方法返回的结果

    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换为灰度

    faces = detector(gray, 1)  # 检测出人脸数

    if len(faces) == 1:

        for index, face in enumerate(faces):
            left = face.left()
            top = face.top()
            right = face.right()
            bottom = face.bottom()
            cv2.rectangle(img, (left, top), (right, bottom), (0, 255, 0), 3) # 画出框子
            
            i += 1 #计步器自增
            cv2.imwrite("img/user." + str(UID) + '.' + str(i) +
                        ".jpg", gray[top:bottom, left:right])  # 存储照片

            cv2.imshow('frame', img) # 展示图片
    else:
        cv2.putText(img, "Warning: can only appear for one person", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
        cv2.imshow('frame', img)
    

    if cv2.waitKey(100) & 0xFF == ord('q'): #每秒检查是否按下Q
        break
    elif i >= 20: # 20次后自动退出
        break

camera.release()
cv2.destroyAllWindows()
下面的是人脸训练
import cv2
import os
import numpy as np
from PIL import Image
import face_recognition
import json

def get_images_and_labels(path):
    image_paths = [os.path.join(path, f) for f in os.listdir(path)]
    # print(image_paths);
    faces = []
    for src in image_paths:
        data = {}
        img = cv2.imread(src)
        list_of_face_encodings = face_recognition.face_encodings(img)
        # print(list_of_face_encodings)
        if len(list_of_face_encodings):
            data['face'] = list_of_face_encodings[0].tolist()
            image_id = int(src.split('.')[1])
            data['id'] = image_id
            # print(data)
            faces.append(data)
            print(faces)
            

    return faces


result = get_images_and_labels('img')
# print(result);exit();
# print(json.jumps(result))
with open("data/data.json", "w") as f:
    json.dump(result, f, sort_keys=True, indent=4, ensure_ascii=False)
    print("加载入文件完成...")
人脸识别
import cv2
import numpy as np
import dlib
import face_recognition
import json


def bejson():
    f = open("data/data.json", encoding='utf-8') # 设置以utf-8解码模式读取文件,encoding参数必须设置,否则默认以gbk模式读取文件,当文件中包含中文时,会报错
    data = json.load(f)
    faces = []
    ids = []
    for value in data:
        faces.append(np.asarray(value['face']));
        ids.append(value['id']);
    return ids, faces


camera = cv2.VideoCapture(0)  # 调用笔记本内置摄像头,所以参数为0,如果有其他的摄像头可以调整参数为1,2

# 改用dlib的面部识别
detector = dlib.get_frontal_face_detector()

# 调用dlib的面部68点识别训练库文件
predictor = dlib.shape_predictor("lib/shape_predictor_68_face_landmarks.dat")


font = cv2.FONT_HERSHEY_SIMPLEX


def max_count(lt):
    # 定义一个字典,记录元素及次数
    d = {}
    # 记录最大次数的元素
    max_key = None
    for i in lt:
        # 判断字典中是否没有该元素
        if i not in d:
            # 计算该元素在列表中出现的次数
            count = lt.count(i)
            # 保存到字典中
            d[i] = count
            # 记录最大元素
            if count > d.get(max_key, 0):
                max_key = i
    # for key in d:
    #     if d.get(max_key, 0) < d[key]:
    #         max_key = key
    return max_key


while True:
    result, img = camera.read()  # 因为read方法反回了两个变量.所以需要定义两个变量进行接收该方法的返回值
    # exit();
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 转换图片为灰度
    faces = detector(gray, 1)  # 检测出人脸数
    if len(faces) == 1:
        # print(face_recognition.face_encodings(img))
        face_encoding_to_check = face_recognition.face_encodings(img)
        # print(face_encoding_to_check[0]);exit()
        # 读取json
        ids,data = bejson();
        # print(data);exit();
        result = face_recognition.compare_faces(
            data, face_encoding_to_check[0], tolerance=0.4)
        print(result)
        uidArray = []  # 识别通过的id
        for index, value in enumerate(result):
            # print(value)
            if value:
                uidArray.append(index);
        # print(uidArray)

        if uidArray:
            key = max_count(uidArray)
                # 根据索引找到json中的这个人的id
                # print(ids[key])
            cv2.putText(img, "Verify Success User: No--" +
                            str(ids[key])+"--", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 2)
        else:
            cv2.putText(img, "Verify Fail-2", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 0), 2)

        # 利用cv2.putText输出
        for i in range(len(faces)):
            landmarks = np.matrix([[p.x, p.y] for p in predictor(img, faces[i]).parts()])
            # enumerate是一个Python的内置方法,用于遍历索引
            # index是序号;face是dets中取出的dlib.rectangle类的对象,包含了人脸的区域等信息
            # left()、top()、right()、bottom()都是dlib.rectangle类的方法,对应矩形四条边的位置
            for index, face in enumerate(faces):
                # 这里画出人脸框
                left = face.left()
                top = face.top()
                right = face.right()
                bottom = face.bottom()
                cv2.rectangle(img, (left, top), (right, bottom), (0, 255, 0), 3)

                shape = predictor(img, face)  # 寻找人脸的68个标定点
                # print(shape)
                # print(shape.num_parts)
                # 遍历所有点,打印出其坐标,并用蓝色的圈表示出来
                for index, pt in enumerate(shape.parts()):
                    # print('Part {}: {}'.format(index, pt))
                    pt_pos = (pt.x, pt.y)
                    cv2.circle(img, pt_pos, 2, (0, 255, 0), 1)
    else:
        cv2.putText(img, "Warning: can only appear for one person", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
    cv2.imshow('face verify-3', img)
    if cv2.waitKey(10) & 0xFF == ord('q'):
        break

camera.release()
cv2.destroyAllWindows()

因为博主并不是很精通python,如果有不太ok的地方,望谅解.仅供学习!

happy coding! bye see you!


Leoappyjj
181 声望22 粉丝

PHP全栈工程师