关于OpenCV for Python入门-face_recognition实现人脸识别

face_recognition是世界上最简洁的人脸识别库,你可以使用Python和命令行工具提取、识别、操作人脸。

face_recognition的人脸识别是基于业内领先的C++开源库 dlib中的深度学习模型,用Labeled Faces in the Wild人脸数据集进行测试,有高达99.38%的准确率。但对小孩和亚洲人脸的识别准确率尚待提升。

face_recognition可以产生很多有趣的应用。

官方原文代码见:https://github.com/ageitgey/face_recognition/blob/master/examples/face_recognition_knn.py

face_recognition包括三个部分的代码

1、训练数据集

2、预测数据集

3、输出标签

训练数据集应遵循一定的数据格式,该数据格式可以是由文件夹名标识的单个图片,也可以是由文件名标识的单个图片。当然,每个人的照片越多,他们接受的训练就越多。

[En]

The training data set should follow a certain data format, which can be a single picture identified by the folder name or a single picture identified by the file name. of course, the more pictures each person has, the more training they have.

训练数据集中的第一步是检测人脸,包括多个或零个非法人脸。

[En]

The first step in the training data set is to detect faces, including multiple or zero illegal faces.

然后将图片二进制传入X,图片标识传入y,进行训练

训练图片是使用sklearn的KNN近邻分类器(KNeighborsClassifier)进行训练的,这个近邻的个数可以调节。

训练完成后再写模型文件,写模型文件的好处就是训练,以后可以直接用,毕竟训练时间太长,用户可以实时添加人脸,难点是如何增量训练?我还没有想出一个好主意。

[En]

Write the model file after the training is completed, the advantage of writing the model file is a training, which can be used directly later, after all, the training time is too long, and the user can add faces in real time, the difficulty is how to train incrementally? I haven’t thought of a good idea yet.

预测过程中最大的困惑是neighbors的返回值,以及对返回值的处理,尤其是distance,这个distance关系到预测的准确与否,无论如何knn都会返回最近的距离和标签,但这个标签正确与否就不知道了,所以阈值设置很重要,我这边设置的是0.5。

最后,在图片上标记人脸的矩形和识别出的字符标签。

[En]

Finally, the rectangle of the human face and the identified character tag are marked on the picture.

我这边是用的ORL数据集,以及从网上找到刘德华、成龙和我的照片。

import math
from sklearn import neighbors
import os
import os.path
import pickle
from PIL import Image, ImageDraw
import face_recognition
from face_recognition.face_recognition_cli import image_files_in_folder

ALLOWED_EXTENSIONS = {'bmp','png', 'jpg', 'jpeg'}

培训指定的培训图片文件夹<details><summary>*<font color='gray'>[En]</font>*</summary>*<font color='gray'>Train the specified training picture folder</font>*</details>
def train(train_dir, model_save_path=None, n_neighbors=None, knn_algo='ball_tree', verbose=False):
"""
    Trains a k-nearest neighbors classifier for face recognition.

    :param train_dir: directory that contains a sub-directory for each known person, with its name.

     (View in source code to see train_dir example tree structure)
     Structure:
        /
        ├── /
        │   ├── .jpeg
        │   ├── .jpeg
        │   ├── ...

        ├── /
        │   ├── .jpeg
        │   └── .jpeg
        └── ...

    :param model_save_path: (optional) path to save model on disk
    :param n_neighbors: (optional) number of neighbors to weigh in classification. Chosen automatically if not specified
    :param knn_algo: (optional) underlying data structure to support knn.default is ball_tree
    :param verbose: verbosity of training
    :return: returns knn classifier that was trained on the given data.

"""
    X = []
    y = []

    # 循环获取训练集图片
    for class_dir in os.listdir(train_dir):
        if not os.path.isdir(os.path.join(train_dir, class_dir)):
            continue
        # 遍历当前任务的每一张图片
        # image_files_in_folder,这个地方是获取文件夹下的所有图片文件,可以修改其中的图片类型
        # 默认是jpg|jpeg|png,后来追加了bmp
        print('training picture of {}'.format(class_dir))
        for img_path in image_files_in_folder(os.path.join(train_dir, class_dir)):
            # 加载图片文件,其实是numpy数组
            image = face_recognition.load_image_file(img_path)
            # 获取人脸检测框
            face_bounding_boxes = face_recognition.face_locations(image)
            # 多个人物或者0个人物不处理
            if len(face_bounding_boxes) != 1:
                # If there are no people (or too many people) in a training image, skip the image.

                if verbose:
                    print("Image {} not suitable for training: {}".format(img_path, "Didn't find a face" if len(face_bounding_boxes) < 1 else "Found more than one face"))
            else:

                # Add face encoding for current image to the training set
                X.append(face_recognition.face_encodings(image, known_face_locations=face_bounding_boxes)[0])
                y.append(class_dir)

    # 设置KNN分类器的近邻数
    # Determine how many neighbors to use for weighting in the KNN classifier
    if n_neighbors is None:
        # n_neighbors = int(round(math.sqrt(len(X))))
        n_neighbors = 3
        if verbose:
            print("Chose n_neighbors automatically:", n_neighbors)

    # 创建KNN分类器,并进行训练
    knn_clf = neighbors.KNeighborsClassifier(n_neighbors=n_neighbors, algorithm=knn_algo, weights='distance')
    knn_clf.fit(X, y)

    # 保存KNN训练结果
    if model_save_path is not None:
        with open(model_save_path, 'wb') as f:
            pickle.dump(knn_clf, f)

    return knn_clf

预测指定的预测画面<details><summary>*<font color='gray'>[En]</font>*</summary>*<font color='gray'>Predict the specified prediction picture</font>*</details>
def predict(X_img_path, knn_clf=None, model_path=None, distance_threshold=0.5):
"""
    Recognizes faces in given image using a trained KNN classifier
    :param X_img_path: path to image to be recognized
    :param knn_clf: (optional) a knn classifier object. if not specified, model_save_path must be specified.

    :param model_path: (optional) path to a pickled knn classifier. if not specified, model_save_path must be knn_clf.

    :param distance_threshold: (optional) distance threshold for face classification. the larger it is, the more chance
           of mis-classifying an unknown person as a known one.

    :return: a list of names and face locations for the recognized faces in the image: [(name, bounding box), ...].

        For faces of unrecognized persons, the name 'unknown' will be returned.

"""
    # 校验当前文件类型
    if not os.path.isfile(X_img_path) or os.path.splitext(X_img_path)[1][1:] not in ALLOWED_EXTENSIONS:
        raise Exception("Invalid image path: {}".format(X_img_path))

    # 校验当前模型文件和knn模型,两个不能全空
    if knn_clf is None and model_path is None:
        raise Exception("Must supply knn classifier either thourgh knn_clf or model_path")

    # 加载训练好的KNN模型
    if knn_clf is None:
        with open(model_path, 'rb') as f:
            knn_clf = pickle.load(f)

    # 加载图片,获取人脸检测框
    X_img = face_recognition.load_image_file(X_img_path)
    X_face_locations = face_recognition.face_locations(X_img)
    # print('predict {}'.format(X_img_path))
    # 如果未找到人脸,返回[]
    if len(X_face_locations) == 0:
        return []

    # 对测试图片进行编码转换,转换为numpy数组
    faces_encodings = face_recognition.face_encodings(X_img, known_face_locations=X_face_locations)

    # 通过KNN模型找到最佳匹配的人脸
    closest_distances = knn_clf.kneighbors(faces_encodings, n_neighbors=3)
    # # 返回值indices:第0列元素为参考点的索引,后面是(n_neighbors - 1)个与之最近的点的索引
    # # 返回值distances:第0列元素为与自身的距离(为0),后面是(n_neighbors - 1)个与之最近的点与参考点的距离
    # closest_distances= [[0.34997745 0.3750366  0.37819395]]
    # closest_distances= [[ 5 12 11]]
    # for i in closest_distances:
    #     print('closest_distances=',i)
    are_matches = []
    # are_matches = [closest_distances[0][i][0]

人物1的识别,分类准确,距离为0

关于OpenCV for Python入门-face_recognition实现人脸识别

人物2的识别,分类准确,距离为0

关于OpenCV for Python入门-face_recognition实现人脸识别

合影的身份包括周星驰、刘德华、李连杰和成龙,但周星驰和李连杰不在训练组,周星驰没有识别他们,刘德华和成龙被正确识别。但李连杰找出了最近的距离,甚至比刘德华自己还近。

[En]

The identification of the group photo includes Zhou Xingchi, Andy Lau, Jet Li and Jackie Chan, but Stephen Chow and Jet Li are not in the training set, Zhou Xingchi did not identify them, and Andy Lau and Jackie Chan were correctly identified. but Jet Li identified the closest distance even closer than Andy Lau himself.

关于OpenCV for Python入门-face_recognition实现人脸识别

刘德华自己的身份,分类准确,距离在0.35左右。

[En]

Andy Lau’s own identification, the classification is accurate, the distance is about 0.35.

关于OpenCV for Python入门-face_recognition实现人脸识别

刘亦菲的识别准确无误,距离约为0.68。

[En]

The recognition of Liu Yifei is accurate, and the distance is about 0.68.

关于OpenCV for Python入门-face_recognition实现人脸识别

我的身份,分类准确,距离在0.42左右,我只有两张训练照,一张是身份证,一张是正片。

[En]

My identification, the classification is accurate, the distance is about 0.42, I only have two training photos, one is my ID card, the other is a positive photo.

关于OpenCV for Python入门-face_recognition实现人脸识别

最后,感谢您的关注和支持!

[En]

Finally, thank you for your attention and support!

关于OpenCV for Python入门-face_recognition实现人脸识别

Original: https://blog.csdn.net/baoqiangwang/article/details/124013221
Author: python与大数据分析
Title: 关于OpenCV for Python入门-face_recognition实现人脸识别

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/497630/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球