Face Recognition 人脸识别

濮阳振海
2023-12-01

Face Recognition 人脸识别

python,face_recognition



简介

face_recognition项目是世界上最简洁的人脸识别库,可以使用Python和命令行工具提取、识别、操作人脸。
本项目的人脸识别是基于业内领先的C++开源库 dlib中的深度学习模型,用Labeled Faces in the Wild人脸数据集进行测试,有高达99.38%的准确率。但对小孩和亚洲人脸的识别准确率尚待提升。
Labeled Faces in the Wild是美国麻省大学安姆斯特分校(University of Massachusetts Amherst)制作的人脸数据集,该数据集包含了从网络收集的13,000多张面部图像。
本项目提供了简易的face_recognition命令行工具,你可以用它处理整个文件夹里的图片。

人脸识别实际上是对人脸进行编码后再去计算两两人脸的相似度,known_image是已知人脸库的图像,unknown_image是待检测的图像,分别利用face_encodings函数来映射成一个向量,再利用两个向量的内积来衡量相似度,compare_faces函数就是根据阈值确认是否是同一人脸。上述函数都是支持多个人脸计算的。另外compare_faces有个tolerance参数是控制阈值的,tolerance值越低越严格,默认为0.6


搭建环境

系统MacOS10.13.6; python3.6; IDE:pycharm.

通过python的face_recognition模块实现人脸检测功能,首先需要安装好face_recognition包:
可通过pycharm直接安装,也可以用pip安装,还可以通过anaconda安装。不知道是我家网不好还是怎么的,用pycharm没查找到face_recognition的包,所以是用后两种方法安装上的。

  • 用pip直接安装face_recognition发现它依赖于dlib,而dlib依赖Boost和cmake,所以先装这两个再装dlib最后才装得上face_recognition:
$ pip3 install CMake
$ pip3 install opencv-python
$ pip3 install dlib
$ pip3 install face_recognition
#最终出现以下打印表示安装成功
#Successfully installed Click-7.0 face-recognition-1.2.3 face-recognition-models-0.3.0
  • 用anaconda安装更简单,找到要安装的环境,直接Search Packages,注意类别要选成Not installed或者all,否则默认是在安装过的包里查找的。

以上两种安装方法安装完后,在pycharm中相应的interpreter下就能看到已经装上的包。


主要方法介绍

以下方法都是face_recognition模块中常用的函数和方法:

1. load_image_file 加载图像

import face_recognition之后直接调用face_recognition.load_image_file()读入图像,参数给文件名字符串,注意:jpg文件要和程序放在同一个文件夹下。输出图像是rgb格式(opencv中是bgr格式)。

import face_recognition
#加载图像文件
image = face_recognition.load_image_file("your_file.jpg")

2. face_locations 定位图中所有人脸

加载图像文件后直接调用face_recognition.face_locations(image),能定位所有图像中识别出的人脸位置信息,返回值是列表形式,列表中每一行是一张人脸的位置信息,包括[top, right, bottom, left],也可理解为每个人脸是一个tuple存储,分别代表框住人脸的矩形中左上角和右下角的坐标(x1,y1,x2,y2)。可遍历列表打印出每张脸的位置信息,也可以通过位置信息截出识别出的人脸的图像显示出来,代码如下:

#定位所有找到的脸的位置
face_locations = face_recognition.face_locations(image)
# 循环找到的所有人脸
for face_location in face_locations:
        # 打印每张脸的位置信息
        top, right, bottom, left = face_location
        print("A face is located at pixel location Top: {}, Left: {}, Bottom: {}, Right: {}".format(top, left, bottom, right))
        # 指定人脸的位置信息,然后显示人脸图片
        face_image = image[top:bottom, left:right]
        pil_image = Image.fromarray(face_image)
        pil_image.show()

3. face_landmarks 识别人脸关键点

加载图像后,调用face_recognition.face_landmarks(image)可识别出人脸关键点信息,包括眼睛、鼻子、嘴巴和下巴等,参数仍是加载的图像image,返回值是包含面部特征字典的列表,列表中每一项对应一张人脸,包括nose_bridge、right_eyebrow、right_eye、chine、left_eyebrow、bottom_lip、nose_tip、top_lip、left_eye几个部分,每个部分包含若干个特征点(x,y),总共有68个特征点。列表长度就是图中识别出的人脸数,可遍历此列表和字典的键值对,打印出所有面部特征点,也可在图像上画出来,代码如下:

from PIL import Image, ImageDraw
face_landmarks_list = face_recognition.face_landmarks(image)
pil_image = Image.fromarray(image)
d = ImageDraw.Draw(pil_image)
for face_landmarks in face_landmarks_list:
    #face_landmarks_list中每个元素都包含以下key的字典
    #打印此图像中每个面部特征的位置
    facial_features = [
        'chin',
        'left_eyebrow',
        'right_eyebrow',
        'nose_bridge',
        'nose_tip',
        'left_eye',
        'right_eye',
        'top_lip',
        'bottom_lip'
    ]
    for facial_feature in facial_features:
        print("The {} in this face has the following points: {}".format(facial_feature, face_landmarks[facial_feature]))
    #在图像中画出每个人脸特征!
    for facial_feature in facial_features:
        d.line(face_landmarks[facial_feature], width=5)
pil_image.show()

4. face_encodings 获取图像文件中所有面部编码

face_recognition.face_encodings(image)方法可获取每个图像文件中每个面部的面部编码,参数仍是加载的图像image,由于每个图像中可能有多个脸,所以返回的是一个编码列表,后续访问时注意加上索引号或者依次遍历。
由打印可看出每张人脸是一个128维的向量。

face_encodings = face_recognition.face_encodings(image)
for face_encoding in face_encodings:
    print("face_encoding len = {} \nencoding:{}\n\n".format(len(face_encoding),face_encoding))

5. compare_faces 由面部编码匹配脸

face_recognition.compare_faces()方法可匹配两个面部特征编码,利用两个向量的内积来衡量相似度,根据阈值确认是否是同一人脸。
位置参数:第一个参数给出一个面部编码列表(很多张脸),第二个参数给出单个面部编码(一张脸),compare_faces方法会将第二个参数的编码与第一个参数中的编码依次匹配,返回值是一个布尔值列表,匹配成功的脸返回True,匹配失败的返回False,顺序与第一个参数中脸的顺序一致。
默认参数:tolerance=0.6,可根据自己需求更改,tolerance越小匹配越严格,例如
matches = face_recognition.compare_faces(known_face_encodings, face_encoding,tolerance=0.39),将阈值改为了0.39,阈值太低容易造成无法成功识别人脸,太高容易造成人脸识别混淆,这个是根据我自己测试后慢慢试出来的一个值。

matche_result = face_recognition.compare_faces(known_faces, face_encoding[0],tolerance=0.39)[0]

实践

demo1:识别人脸特征并打印出来

# -*- coding: utf-8 -*-
# 自动识别人脸特征
# filename : find_facial_features_in_picture.py

from PIL import Image, ImageDraw
import face_recognition

# 将jpg文件加载到numpy 数组中
image = face_recognition.load_image_file("view_Mr_G.jpg")

#查找图像中所有面部的所有面部特征
face_landmarks_list = face_recognition.face_landmarks(image)

print("I found {} face(s) in this photograph.".format(len(face_landmarks_list)))
pil_image = Image.fromarray(image)
d = ImageDraw.Draw(pil_image)
for face_landmarks in face_landmarks_list:
    #打印此图像中每个面部特征的位置
    facial_features = [
        'chin',
        'left_eyebrow',
        'right_eyebrow',
        'nose_bridge',
        'nose_tip',
        'left_eye',
        'right_eye',
        'top_lip',
        'bottom_lip'
    ]
    for facial_feature in facial_features:
        print("The {} in this face has the following points: {}".format(facial_feature, face_landmarks[facial_feature]))
    #在图像中画出每个人脸特征!
    for facial_feature in facial_features:
        d.line(face_landmarks[facial_feature], width=5)

pil_image.show()

demo2 : 识别图片中的所有人脸并显示

# -*- coding: utf-8 -*-
#  识别图片中的所有人脸并显示出来
# filename : find_faces_in_picture.py

from PIL import Image
import face_recognition

# 将jpg文件加载到numpy 数组中
image = face_recognition.load_image_file("view_Mr_G.jpg")

# 使用默认的给予HOG模型查找图像中所有人脸
# 这个方法已经相当准确了,但还是不如CNN模型那么准确,因为没有使用GPU加速
# 另请参见: find_faces_in_picture_cnn.py
face_locations = face_recognition.face_locations(image)

# 使用CNN模型
# face_locations = face_recognition.face_locations(image, number_of_times_to_upsample=0, model="cnn")

# 打印:我从图片中找到了 多少 张人脸
print("I found {} face(s) in this photograph.".format(len(face_locations)))

# 循环找到的所有人脸
for face_location in face_locations:

        # 打印每张脸的位置信息
        top, right, bottom, left = face_location
        print("A face is located at pixel location Top: {}, Left: {}, Bottom: {}, Right: {}".format(top, left, bottom, right))
# 指定人脸的位置信息,然后显示人脸图片
        face_image = image[top:bottom, left:right]
        pil_image = Image.fromarray(face_image)
        pil_image.show()

demo3 : 显示未知图片中已知人物的脸

# -*- coding: utf-8 -*-
# 识别人脸鉴定是哪个人

import face_recognition
from PIL import Image, ImageDraw
import cv2
PATH = "/Users/tanyashi/Python/python project/face_recognition/一起同过窗"
VIEW_PIC_NAME="view2.jpg"
UNKNOWN_IMAGE="view_Mr_G.jpg"
#将jpg文件加载到numpy数组中
view_image = face_recognition.load_image_file(VIEW_PIC_NAME)
#要识别的图片
unknown_image = face_recognition.load_image_file(UNKNOWN_IMAGE)
results = []
#获取每个图像文件中每个面部的面部编码
#由于每个图像中可能有多个面,所以返回一个编码列表。
#但是由于我知道每个图像只有一个脸,我只关心每个图像中的第一个编码,所以我取索引0。
view_face_encoding = face_recognition.face_encodings(view_image)[0]
print("view_face_encoding:{}\n\n".format(view_face_encoding))
known_faces = [view_face_encoding]
face_locations = face_recognition.face_locations(unknown_image)
print('got {} face(s) in {}:'.format(len(face_locations), UNKNOWN_IMAGE))
for face_location in face_locations:
    top, right, bottom, left = face_location
    #print(top, right, bottom, left)
    face_image = unknown_image[top:bottom, left:right]
    face_encoding = face_recognition.face_encodings(face_image)
    if face_encoding:
        result = {}
        result['face_encoding'] = face_encoding
        result['is_view'] = face_recognition.compare_faces(known_faces, face_encoding[0])[0]
        result['location'] = face_location
        result['face_id'] = face_locations.index(face_location)
        results.append(result)
        if result['is_view']:
            print('face {} is view!!'.format(result['face_id']+1))
            #print(top, right, bottom, left)
#print("results :{}".format([i['is_view'] for i in results]))
print("please find out view in this image:")
view_face_location = [i['location'] for i in results if i['is_view']]
if view_face_location:
    top, right, bottom, left = view_face_location[0]
    #print(top, right, bottom, left)
    face_image = unknown_image[top:bottom, left:right]
    pil_image = Image.fromarray(face_image)
    pil_image.show()
else:
    print('view is not in this pic!')

demo4 : 摄像头头像识别

# -*- coding: utf-8 -*-
# 摄像头头像识别
import face_recognition
import cv2

video_capture = cv2.VideoCapture(0)

# 本地图像
chenduling_image = face_recognition.load_image_file("chenduling.jpg")
chenduling_face_encoding = face_recognition.face_encodings(chenduling_image)[0]

# 本地图像二
sunyizheng_image = face_recognition.load_image_file("sunyizheng.jpg")
sunyizheng_face_encoding = face_recognition.face_encodings(sunyizheng_image)[0]

# 本地图片三
zhangzetian_image = face_recognition.load_image_file("zhangzetian.jpg")
zhangzetian_face_encoding = face_recognition.face_encodings(zhangzetian_image)[0]

# Create arrays of known face encodings and their names
# 脸部特征数据的集合
known_face_encodings = [
    chenduling_face_encoding,
    sunyizheng_face_encoding,
    zhangzetian_face_encoding
]

# 人物名称的集合
known_face_names = [
    "michong",
    "sunyizheng",
    "chenduling"
]

face_locations = []
face_encodings = []
face_names = []
process_this_frame = True

while True:
    # 读取摄像头画面
    ret, frame = video_capture.read()

    # 改变摄像头图像的大小,图像小,所做的计算就少
    small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)

    # opencv的图像是BGR格式的,而我们需要是的RGB格式的,因此需要进行一个转换。
    rgb_small_frame = small_frame[:, :, ::-1]

    # Only process every other frame of video to save time
    if process_this_frame:
        # 根据encoding来判断是不是同一个人,是就输出true,不是为flase
        face_locations = face_recognition.face_locations(rgb_small_frame)
        face_encodings = face_recognition.face_encodings(rgb_small_frame, face_locations)

        face_names = []
        for face_encoding in face_encodings:
            # 默认为unknown
            matches = face_recognition.compare_faces(known_face_encodings, face_encoding)
            name = "Unknown"

            # if match[0]:
            #     name = "michong"
            # If a match was found in known_face_encodings, just use the first one.
            if True in matches:
                first_match_index = matches.index(True)
                name = known_face_names[first_match_index]
            face_names.append(name)

    process_this_frame = not process_this_frame

    # 将捕捉到的人脸显示出来
    for (top, right, bottom, left), name in zip(face_locations, face_names):
        # Scale back up face locations since the frame we detected in was scaled to 1/4 size
        top *= 4
        right *= 4
        bottom *= 4
        left *= 4

        # 矩形框
        cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)

        #加上标签
        cv2.rectangle(frame, (left, bottom - 35), (right, bottom), (0, 0, 255), cv2.FILLED)
        font = cv2.FONT_HERSHEY_DUPLEX
        cv2.putText(frame, name, (left + 6, bottom - 6), font, 1.0, (255, 255, 255), 1)

    # Display
    cv2.imshow('monitor', frame)

    # 按Q退出
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

video_capture.release()
cv2.destroyAllWindows()
 类似资料: