人脸考勤机分为两个模块,人脸识别与人脸检测

人脸识别

常用的人脸识别算法有Haar、Hog、CNN、SSD、MTCNN。
下面来分别阐述一下在Python中如何利用OpenCv快速实现使用。
我们通用的步骤是

# 步骤
# 1、读取包含人脸的图片
# 2.使用模型识别人脸
# 3.将识别结果用矩形框画出来

Haar

import cv2
import numpy as np
img = cv2.imread('./images/faces1.jpg')
# 转为灰度图
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 构造haar检测器 https://github.com/opencv/opencv/tree/master/data/haarcascades
face_detector = cv2.CascadeClassifier('./cascades/haarcascade_frontalface_default.xml')

detections = face_detector.detectMultiscale(img_gray)
# 解析检测结果
for (x,y,w,h) in detections:
    cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),5)

output.png

detections = face_detector.detectMultiScale(img_gray,scaleFactor=1.3)

通过调整参数实现更优效果
output.png

Hog

import cv2
import numpy as np
import matplotlib.pyplot as plt
# 安装dlib
#  conda install -c conda-forge dlib
import dlib
plt.rcParams['figure.dpi']  = 200
img = cv2.imread('./images/faces2.jpg')
# 构造人脸解析器
hog_face_detector = dlib.get_frontal_face_detector()
# 检测人脸
detections = hog_face_detector(img,1)
# 解析矩形结果
for face in detections:
    x = face.left()
    y = face.top()
    r = face.right()
    b = face.bottom()
    cv2.rectangle(img,(x,y),(r,b),(0,255,0),3)

output.png

CNN

# %%
# 导入相关包
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 读取照片
img = cv2.imread('./images/faces2.jpg')
# 安装DLIB
import dlib

# %%
# 构造CNN人脸检测器
cnn_face_detector = dlib.cnn_face_detection_model_v1('./weights/mmod_human_face_detector.dat')

# 检测人脸
detections = cnn_face_detector(img,1)
# 解析矩形结果
for face in detections:
    x = face.rect.left()
    y = face.rect.top()
    r = face.rect.right()
    b = face.rect.bottom()
    #置信度
    c = face.confidence
    print(c)
    
    cv2.rectangle(img,(x,y),(r,b),(0,255,0),5)

output.png

SSD与MTCNN我不经常使用就不多做介绍,下面进行人脸检测介绍

人脸检测

这里只对resnet的使用进行介绍。

resnet

文件夹架构如下:
1675523132730.png

  • 1、图片数据预处理
  • 2、加载模型
  • 3、提取图片的68个关键点
  • 4、预测图片:找到欧氏距离最近的特征描述符
  • 5、评估测试数据集
# 导入包
import cv2
import numpy as np
import matplotlib.pyplot as plt
import dlib
# 人脸检测模型
hog_face_detector = dlib.get_frontal_face_detector()
# 关键点 检测模型
shape_detector = dlib.shape_predictor('./weights/shape_predictor_68_face_landmarks.dat')
# resnet模型
face_descriptor_extractor = dlib.face_recognition_model_v1('./weights/dlib_face_recognition_resnet_model_v1.dat')
# 提取单张图片的特征描述符,label
def getFaceFeatLabel(fileName):
    # 获取人脸labelid
    label_id = int(fileName.split('/')[-1].split('.')[0].split('subject')[-1])
    # 读取图片
    
    cap = cv2.VideoCapture(fileName)
    ret,img = cap.read()
    
    # 转为RGB
    img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
    #人脸检测
    detections = hog_face_detector(img,1)
    face_descriptor = None
    
    for face in detections:
        # 获取关键点
        points = shape_detector(img,face)
        # 获取特征描述符
        face_descriptor = face_descriptor_extractor.compute_face_descriptor(img,points)
        # 转为numpy 格式的数组
        face_descriptor = [f for f in face_descriptor]
        face_descriptor = np.asarray(face_descriptor,dtype=np.float64)
        face_descriptor = np.reshape(face_descriptor,(1,-1))
    
    return label_id,face_descriptor
# 对train文件夹进行处理
import glob
file_list =glob.glob('./yalefaces/train/*')
# 构造两个空列表
label_list = []
feature_list = None
name_list = {}
index= 0
for train_file in file_list:
    # 获取每一张图片的对应信息
    label,feat = getFaceFeatLabel(train_file)
    
    #过滤数据
    if feat is not None: 
        #文件名列表
        name_list[index] = train_file
        #label列表
        label_list.append(label)
        if feature_list is None:
            feature_list = feat
        else:
            # 特征列表
            feature_list = np.concatenate((feature_list,feat),axis=0)
        index +=1

# 评估测试数据集
file_list =glob.glob('./yalefaces/test/*')
# 构造两个空列表
predict_list = []
label_list= []
# 距离阈值
threshold = 0.5

for test_file in file_list:
    # 获取每一张图片的对应信息
    label,feat = getFaceFeatLabel(test_file)
    
    # 读取图片
    cap = cv2.VideoCapture(test_file)
    ret,img = cap.read()
    
    img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
    
    #过滤数据
    if feat is not None: 
        # 计算距离
        distances = np.linalg.norm((feat-feature_list),axis=1)
        min_index = np.argmin(distances)
        min_distance = distances[min_index]
        
        if min_distance < threshold:
            # 同一人
            
            predict_id = int(name_list[min_index].split('/')[-1].split('.')[0].split('subject')[-1])
        else:
            predict_id =  -1
            
        
        predict_list.append(predict_id)
        label_list.append(label)
        
        cv2.putText(img,'True:'+str(label),(10,30),cv2.FONT_HERSHEY_COMPLEX_SMALL,1,(0,255,0))
        cv2.putText(img,'Pred:'+str(predict_id),(10,50),cv2.FONT_HERSHEY_COMPLEX_SMALL,1,(0,255,0))
        cv2.putText(img,'Dist:'+str(min_distance),(10,70),cv2.FONT_HERSHEY_COMPLEX_SMALL,1,(0,255,0))
        
        # 显示
        plt.figure()
        plt.imshow(img)

output.png

人脸考勤机

'''
人脸注册:将人脸特征存进csv
人脸识别:将检测的人脸特征与csv中的人脸特征作比较,如果存在,则将考勤记录写入另一个csv
'''
import cv2
import numpy as np
import dlib
import time
import csv
# 人脸注册
def face_Register(label_id = 1,name='xiuye',count=3,interval=3):
    '''
    label_id 人脸ID
    name     人脸姓名
    count    采集数量
    interval 采集间隔时间
    '''
    # 检测人脸
    cap = cv2.VideoCapture(1)
    # 获取长宽
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    # 构造人脸检测器
    hog_face_detector = dlib.get_frontal_face_detector()
    # 关键点检测器
    shape_detector = dlib.shape_predictor('./face_recognition/weights/shape_predictor_68_face_landmarks.dat')
    # 特征描述符
    face_descriptor_extractor = dlib.face_recognition_model_v1('./weights/dlib_face_recognition_resnet_model_v1.dat')
    
    # 开始时间
    start_time = time.time()

    # 执行次数
    collect_count = 0

    # csv Writer
    f = open('./data/feature.csv','a',newline='')
    csv_writer = csv.writer(f)
    while True:
        ret,frame = cap.read()
        # 缩放
        frame = cv2.resize(frame,(width//2,height//2))
        # 镜像
        frame = cv2.flip(frame,1)

        # 转为灰度图
        frame_gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)

        # 检测人脸
        detections = hog_face_detector(frame,1)
        #遍历人脸    
        for face in detections:
            # 人脸坐标
            l,t,r,b = face.left(),face.top(),face.right(),face.bottom()
            # 获取人脸关键点 # 获取68个关键点
            points = shape_detector(frame,face)
            for point in points.parts():
                cv2.circle(frame,(point.x,point.y),2,(0,255,0),-1)


            # 矩形人脸框
            cv2.rectangle(frame,(l,t),(r,b),(0,255,0),2)
            
            # 采集
            if collect_count < count:
                # 当前时间
                now_time = time.time()
                if now_time - start_time > interval:
                    # 获取特征描述符
                    face_descriptor = face_descriptor_extractor.compute_face_descriptor(frame,points)
                    face_descriptor = [f for f in face_descriptor]
                    
                    # 写入csv文件
                    line = [label_id,name,face_descriptor]
                    csv_writer.writerow(line)
                    collect_count+=1

                    print(('采集次数:{collect_count}'.format(collect_count=collect_count)))
                    start_time = now_time
                else:
                    pass
            else:
                # 采集完毕
                print('采集完毕')
                return
                

        
        # 显示画面
        cv2.imshow('demo',frame)
        # 退出条件
        if cv2.waitKey(10) & 0xFF == ord('q'):
            break

    f.close()
    cap.release()
    cv2.destroyAllWindows()

# 获取并组装csv文件中的特征
def getFeatureList():
    label_list = []
    name_list = []
    feature_list = None
    with open('./data/feature.csv','r') as f:
        csv_reader = csv.reader(f)
        for line in csv_reader:
            label_id = line[0]
            label_list.append(label_id)
            name = line[1]
            name_list.append(name)
            face_descriptor = eval(line[2])
            face_descriptor = np.asarray(face_descriptor,dtype=np.float64)
            face_descriptor = np.reshape(face_descriptor,(1,-1))
            if feature_list is None:
                feature_list = face_descriptor
            else:
                feature_list = np.concatenate((feature_list,face_descriptor),axis=0)
    return label_list,name_list,feature_list
# 人脸识别
''''
1、实时获取视频中人脸的特征描述符
2、与库里特征做距离判断
3、找到预测值
4、结果存入csv
'''
def face_Recognizer(threshold):
        # 检测人脸
    cap = cv2.VideoCapture(1)
    # 获取长宽
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    # 构造人脸检测器
    hog_face_detector = dlib.get_frontal_face_detector()
    # 关键点检测器
    shape_detector = dlib.shape_predictor('./face_recognition/weights/shape_predictor_68_face_landmarks.dat')
    # 特征描述符
    face_descriptor_extractor = dlib.face_recognition_model_v1('./weights/dlib_face_recognition_resnet_model_v1.dat')
    
    # 读取特征
    label_list,name_list,feature_list = getFeatureList()
    
    # 字典记录人脸识别记录
    recog_record = {}

    # csv写入
    f = open('./data/attendance.csv','a')
    csv_writer = csv.writer(f)

    # 帧率信息
    fps_time = time.time()
    while True:
        ret,frame = cap.read()
        # 缩放
        frame = cv2.resize(frame,(width//2,height//2))
        # 镜像
        frame = cv2.flip(frame,1)

 
        # 检测人脸
        detections = hog_face_detector(frame,1)
        #遍历人脸    
        for face in detections:
            # 人脸坐标
            l,t,r,b = face.left(),face.top(),face.right(),face.bottom()
            # 获取人脸关键点 # 获取68个关键点
            points = shape_detector(frame,face)
            # 获取特征描述符
            face_descriptor = face_descriptor_extractor.compute_face_descriptor(frame,points)
            face_descriptor = [f for f in face_descriptor]

            # 计算距离
            face_descriptor = np.asarray(face_descriptor,dtype=np.float64)
            
            # face_descriptor = np.reshape(face_descriptor,(1,-1))
            
            distances = np.linalg.norm((face_descriptor-feature_list),axis=1)
            # 最短索引
            min_index = np.argmin(distances)
            # 最短距离
            min_distance = distances[min_index]
            
            if min_distance < threshold:
                predict_id = label_list[min_index]
                predict_name = name_list[min_index]
                cv2.putText(frame,predict_name + str(round(min_distance,2)),(l,b+40),cv2.FONT_HERSHEY_COMPLEX_SMALL,2,(0,255,0),1)
                now = time.time()
                need_insert = False
                # 判断是否识别过
                if predict_name in recog_record:
                    pass
                    # 隔一段时间再存
                    if now - recog_record[predict_name] > 3:
                        # 超过阈值时间 再存一次
                        need_insert = True
                        recog_record[predict_name] = now
                    
                    else:
                        need_insert = False
                        pass
                else:
                    need_insert = True
                    recog_record[predict_name] = now
                    # 存入csv文件
                if need_insert:
                    time_local = time.localtime(recog_record[predict_name])
                    time_str = time.strftime("%Y-%m-%d %H:%M:%S",time_local)
                    line = [ predict_id,predict_name,time_str] 
                    csv_writer.writerow(line)
                    print('写入成功:{name},{time}'.format(name=predict_name,time=time_str))
            else:
                print('未识别')
                    

            # 矩形人脸框
            cv2.rectangle(frame,(l,t),(r,b),(0,255,0),2)
            
        # 计算帧率
        now = time.time()
        fps = 10/(now - fps_time)
        fps_time = now

        cv2.putText(frame,str(round(fps,2)),(20,30),cv2.FONT_HERSHEY_COMPLEX_SMALL,2,(0,255,0),1)
        # 显示画面
        cv2.imshow('demo',frame)
        # 退出条件
        if cv2.waitKey(10) & 0xFF == ord('q'):
            break
    f.close()
    cap.release()
    cv2.destroyAllWindows()
# face_Register()
face_Recognizer(0.5)
相关权重文件下载链接
最后修改:2023 年 02 月 04 日
如果觉得我的文章对你有用,请随意赞赏