python 人脸识别

1.准备工作:

(1)编程环境:Anaconda–Jupyter Notebook
(2)建立一个文件夹(face_recognition),用于存放训练集图片和测试集图片。 为避免中文乱码问题,文件名统一采用英文及拼音命名。

训练集文件夹(trains)存放的第一个人
在这里插入图片描述
训练集文件夹(trains)存放的第二个人
在这里插入图片描述
存放一张测试集图片test.jpg
在这里插入图片描述

2.程序代码:

import os
import os.path
import cv2
import sklearn.neighbors
import pickle
from PIL import Image, ImageDraw, ImageFont
import face_recognition as fr
from face_recognition.face_detection_cli import image_files_in_folder

#################################
# 2-训练模型
#################################
#1.建立一个数据集x:128维度加上y一个维度,总共是129维度。
# 2.对每一个照片操作
# 3.决定n
# 4.训练出分类器
# 5.保存分类器
def train(train_dir, model_save_path="trained_knn_model.clf", n_neighbors=4, knn_algo="ball_tree"):
    '''
    功能:训练一个KNN分类器
    :train_dir: 训练目录。其下对每个已知的人,分别以其名字,建立一个文件夹
    :model_save_path:模型保存的位置
    :n_neighbors:邻居数默认为4
    :knn_algo: 支持KNN的数据结构;ball_tree是一种树型结构。
    :return: KNN分类器
    '''
    #生成训练集
    x = []  #注意x最终是18维
    y = []
    
     #遍历训练集中的每一个人
    for class_dir in os.listdir(train_dir): #os.listdir()方法,用于返回指定的文件夹包含的文件或文件夹的名字的列表。这个列表以字母顺序。 它不包括 '.' 和'..' 即使它在文件夹中。
        if not os.path.isdir(os.path.join(train_dir, class_dir)): #判断是否是目录
            continue
        # 遍历这个人的每一张照片
        for img_path in image_files_in_folder(os.path.join(train_dir, class_dir)):
            image = fr.load_image_file(img_path) #传入人脸的位置
            boxes = fr.face_locations(image) #定出人脸位置
            #  #对于当前图片,增加编码到训练集合
            x.append(fr.face_encodings(image, known_face_locations=boxes)[0])#编码返回时一个128维度的向量。
            y.append(class_dir)

    # 决定n
    if n_neighbors is None:
        n_neighbors = 3

    # 训练分类器
    knn_clf = sklearn.neighbors.KNeighborsClassifier(n_neighbors=n_neighbors)
    knn_clf.fit(x, y)
    # 保存分类器
    if model_save_path is not None:
        with open(model_save_path, "wb") as f: #wb,b二进制
            pickle.dump(knn_clf, f)  #模型存储

    # 返回
    return knn_clf

# 预测
def predict(x_img_path, knn_clf=None, model_path=None, distance_threshold=0.45):
    '''
    利用KNN分类器识别给定的照片中的人脸
    :x_imag_path:必须对应照片的地址而不是照片的文件夹
    :knn_clf:
    :distance_threshold:
    :return: [(人名1,边界盒子1),...]
    '''
    if knn_clf is None and model_path is None:
        raise Exception("必须提供KNN分类器")#KNN分类器:可选方式为knn_clf或model_path'
    # 加载训练好的KNN模型
    # rb 读入二进制数据
    if knn_clf is None:
        with open(model_path, "rb") as f: #https://www.cnblogs.com/tianyiliang/p/8192703.html
            knn_clf = pickle.load(f)

    # 加载图片,发现人脸的位置
    x_img = fr.load_image_file(x_img_path)
    x_face_location = fr.face_locations(x_img)

    # 对测试图片中的人脸进行编码
    encodings = fr.face_encodings(x_img, known_face_locations=x_face_location) #http://www.360doc.com/content/18/0403/18/48868863_742603302.shtml

    # 利用knn model找出测试人脸最匹配的人脸
    # encodings : 128个人脸的特征构成
    closest_distances = knn_clf.kneighbors(encodings, n_neighbors=1)
    are_matches = [closest_distances[0][i][0] <= distance_threshold
                   for i in range(len(x_face_location))]

    # 预测分类,并移除不在阀值内的分类
    #pred 预测值,loc头像位置
    return [(pred, loc) if rec else ("unknown", loc)
            for pred, loc, rec in zip(knn_clf.predict(encodings),
                                      x_face_location, are_matches)]


# 结果可视化
def show_names_on_image(img_path, predictions):
    '''
    人脸识别可视化
    :param img_path: 待识别图片的位置
    :param predictions: 预测的结果
    :return:
    '''
    pil_image = Image.open(img_path).convert("RGB") #将图片转换成格式  #https://blog.csdn.net/icamera0/article/details/50843172
    draw = ImageDraw.Draw(pil_image) #ImageDraw类支持各种几何图形的绘制和文本的绘制https://blog.csdn.net/guduruyu/article/details/71213717
    for name, (top, right, bottom, left) in predictions:
        # 用pillow快捷画出人脸边界盒子
        draw.rectangle(((left, top), (right, bottom)), outline=(255,0,255))

        #pillow 里可能生成UTF-8格式,所以这里做如下转换
        #这里有draw不能解码出name字体的问题。
        name = name.encode("UTF-8")
        name = name.decode("ascii")

        #在人脸下写下名字,作为标签
        text_width, text_height = draw.textsize(name)
        draw.rectangle(((left, bottom + text_height - 10), (right, bottom)),
                       fill=(255,0,255), outline=(255,0,255))
#        Font4 = ImageFont.truetype("C:\Windows\Fonts\SHOWG.TTF",48)  
#        draw.text((left + 6, bottom - text_height - 5), name, fill=(255,0,255))
        Font4 = ImageFont.truetype("C:\Windows\Fonts\Arial.ttf",20)  
        draw.text((left + 6, bottom - text_height - 5), name, font=Font4)
        #遍加名字到li_names
        li_names.append(name)
    #从内存删除draw
    del draw
    #显示结果图
    pil_image.show()

#读入测试集图片(具体到图片名)
predictions = predict('E://face_recognition/test.jpg', model_path="trained_knn_model.clf")
show_names_on_image('E://face_recognition/test.jpg', predictions)

3.识别结果:

在这里插入图片描述

  • 5
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值