人脸考勤机项目

文章内容如下:

1)项目简介

2)开发环境和使用的技术知识

3)功能实现

4)项目源码

一。项目简介

       此项目是基于HOG和Dlib开发的一套实时无感考勤系统。首先是待考勤人员的个人信息录入。然后在过道或者入口处装置人脸考勤机,当有人经过时,摄像头抓取人脸并上传服务器,对抓取到的人脸进行人脸识别,判断此人身份,若此人在信息比对库中且第一次考勤,则考勤成功,并显示考勤人员姓名与比对距离,如非第一次考勤,并在一定时间隔外则更新考勤 。

二。开发环境和使用的技术知识

开发环境:Python,Opencv

技术知识:HOG+Dlib技术、Opencv视频读取-缩放-翻转-写入技术

三。功能实现

1. 人脸注册:将人脸特征存进feaure.csv

2. 人脸识别:将检测的人脸特征与feaure.csv人脸特征作比较,如果比中把考勤记录写入attendance.csv

1. 人脸注册:将人脸特征存进feaure.csv

①调取视频流,能显示人脸画面

cap = cv2.VideoCapture(0)"""调取摄像头"""

while True:
      ret,frame = cap.read()
      frame =  cv2.flip(frame,1)"""y轴镜像"""
      cv2.imshow('Face attendance',frame)"""展示每一帧图片"""
      if cv2.waitKey(10) & 0xFF == ord('q'):
               break
cap.release()
cv2.destroyAllWindows()

  ② 步骤如下:

第1步:启动HOG人脸检测器,读取人脸上下左右坐标,绘制人脸方框;

hog_face_detector = dlib.get_frontal_face_detector()"""启动hog人脸检测器"""
detections = hog_face_detector(frame,1)"""获取人脸参数,缩放因子为1"""
for face in detections:
    l,t,r,b = face.left(),face.top(),face.right(),face.bottom()"""获取人脸左,上,右,下的坐标"""
cv2.rectangle(frame,(l,t),(r,b),(0,255,0),2)"""绘制人脸框"""

第2步: 启动人脸关键点检测器获取人脸68个关键点,再转为特征描述符;

shape_detector = dlib.shape_predictor('./1/shape_predictor_68_face_landmarks.dat')"""启动人脸关键点检测器"""
detections = hog_face_detector(frame,1)"""获取人脸参数,缩放因子为1""" 
for face in detections:
     points = shape_detector(frame,face)"""获取人脸68关键点"""
for point in points.parts():
     cv2.circle(frame,(point.x,point.y),2,(0,255,0),-10)"""绘制68关键点"""
face_descriptor = face_descriptor_extractor.compute_face_descriptor(frame,points)"""获取(转为)特征描述符"""
face_descriptor = [f for f in face_descriptor]"""为方便转换成列表存进feaure.csv"""

  ①②组合在一起复合代码如下:

def faceRegister(label_id=1,name='Jie Wang',count=3,interval=3):
#1)-检测人脸
        #准备工作
        hog_face_detector = dlib.get_frontal_face_detector()#①启动hog人脸检测器
        shape_detector = dlib.shape_predictor('./1/shape_predictor_68_face_landmarks.dat')#①启动人脸关键点检测器
        face_descriptor_extractor = dlib.face_recognition_model_v1('./1/dlib_face_recognition_resnet_model_v1.dat')#①启动特征描述符检测器
        cap = cv2.VideoCapture(0)#②调取摄像头
        start_time = time.time()#开始时间,是为了interval设置的
        collect_count = 0#初始采集次数
        f = open('./2/feature.csv','a',newline="")#采集到的特征描述符放在这个文件里
        csv_writer = csv.writer(f)
        #采集3次特征  
        while True:
            ret,frame = cap.read()
            frame =  cv2.flip(frame,1)#y轴镜像
            detections = hog_face_detector(frame,1)#获取人脸参数,缩放因子为1
          
            for face in detections:
                l,t,r,b = face.left(),face.top(),face.right(),face.bottom()#获取人脸左,上,右,下的坐标
                points = shape_detector(frame,face)#获取人脸68关键点
                for point in points.parts():
                    cv2.circle(frame,(point.x,point.y),2,(0,255,0),-10)#绘制68关键点
                cv2.rectangle(frame,(l,t),(r,b),(0,255,0),2)#绘制人脸框
                if collect_count < count:
                    now = time.time()
                    if now - start_time > interval:
                        face_descriptor = face_descriptor_extractor.compute_face_descriptor(frame,points)#获取特征描述符
                        face_descriptor = [f for f in face_descriptor]#转换成列表方便存进feaure.csv
                        line = [label_id,name,face_descriptor]
                        csv_writer.writerow(line)#写入csv_writer
                        collect_count +=1
                        start_time = now
                        print("采集次数:{collect_count}".format(collect_count = collect_count))
                        copy_collect_count = collect_count
#                       print(face_descriptor)
                else:
                    if 3 == copy_collect_count:
                        print("采集完毕")
                        copy_collect_count = 0
                        break
            #展示   
            cv2.imshow('Face attendance',frame)#展示每一帧图片
            if cv2.waitKey(10) & 0xFF == ord('q'):
                break
        f.close()
        cap.release()
        cv2.destroyAllWindows()

faceRegister()

2. 人脸识别:将检测的人脸特征与feaure.csv人脸特征作比较,如果比中把考勤记录写入attendance.csv

①从磁盘中调取注册时的人脸特征描述符,解析它

def getFeatureList():
    label_list = []
    name_list = []
    featuree_list = None"""后面用的np.concatenate()方法决定了此处不能是空列表,否则无法拼接"""
    with open('./2/feature.csv','r') as f:
        csv_reader = csv.reader(f)
        for line in csv_reader:
            label_id = line[0]
            name = line[1]
            face_descriptor = eval(line[2])"""从csv文件拿出来的列表是字符串,需要eval处理一下转为list"""
            face_descriptor = np.asarray(face_descriptor,dtype=np.float64)
            face_descriptor = np.reshape(face_descriptor,(1,-1))"""转成1xn格式,期望就是这样"""
            label_list.append(label_id)"""label_list拼接过程"""
            name_list.append(name)"""name_list拼接过程"""
            if featuree_list is None:"""featuree_list拼接过程"""
                featuree_list = face_descriptor
            else:
                featuree_list = np.concatenate((featuree_list,face_descriptor),axis=0)
#             print(name)
    return  label_list,name_list,featuree_list

label_list,name_list,featuree_list = getFeatureList()"""读取人脸注册时的特征"""

②特征描述符比对,计算与库的距离

distance = np.linalg.norm((face_descriptor-featuree_list),axis=1)"""范数求差"""
min_index = np.argmin(distance)"""获取最短距离索引"""
min_distance = np.argmin(distance)"""获取最短距离"""
if min_distance < threshold:"""识别到打印信息"""
   predict_id = label_list[min_distance]
   predict_name = name_list[min_distance]

③依据条件确认是否记录考勤

need_insert = False"""用于后面判断是否变化了考勤,是则写入到attendance.csv文件"""
if predict_name in recog_record:"""第一次检测到考勤则记录人脸信息,记录的是名字与考勤时间组成的键值对,如这次检测与上次记录差3s,则再考勤一次。上述都不是则跳过"""
   if time.time()-recog_record[predict_name]>3:
      need_insert = True
      recog_record[predict_name] = time.time()
      print(predict_name)
   else:
      print("无需重复签到!")
      need_insert = False
      pass
else:
   need_insert = True
   recog_record[predict_name] = time.time()
   print(predict_name)

④将考勤记录写入文件

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,min_distance,time_str]
   csv_writer.writerow(line)
   print("{name} {time}考勤记录已成功更新入文件!".format(name=predict_name,time=time_str))

①-④组合在一起复合代码如下:

def faceRecognizer(threshold = 0.5):
 #1)实时获取视频流中人脸特征描述符;
        #1准备工作
        label_list,name_list,featuree_list = getFeatureList()#读取人脸注册时的特征
        hog_face_detector = dlib.get_frontal_face_detector()#①启动hog人脸检测器
        shape_detector = dlib.shape_predictor('./1/shape_predictor_68_face_landmarks.dat')#①启动人脸关键点检测器
        face_descriptor_extractor = dlib.face_recognition_model_v1('./1/dlib_face_recognition_resnet_model_v1.dat')#①启动特征描述符检测器
        cap = cv2.VideoCapture(0)#②调取摄像头
        recog_record = {}#为存考勤信息做准备
        f = open('./2/attendance.csv','a',newline="")#为文件性质记录考勤数据做准备
        csv_writer = csv.writer(f)
        fps_time = time.time()#画面显示fps
        #2获取人脸识别中采集到的特征
        while True:
            ret,frame = cap.read()
            frame =  cv2.flip(frame,1)#y轴镜像
            detections = hog_face_detector(frame,1)#获取人脸参数,缩放因子为1
            
            for face in detections:
                l,t,r,b = face.left(),face.top(),face.right(),face.bottom()#获取人脸左,上,右,下的坐标
                points = shape_detector(frame,face)#获取人脸68关键点
                cv2.rectangle(frame,(l,t),(r,b),(0,255,0),2)#绘制人脸框
                face_descriptor = face_descriptor_extractor.compute_face_descriptor(frame,points)#获取特征描述符
                face_descriptor = [f for f in face_descriptor]#转换成列表方便存进feaure.csv  
                #3计算与库的距离
                distance = np.linalg.norm((face_descriptor-featuree_list),axis=1)#范数求差
                min_index = np.argmin(distance)#获取最短距离索引
                min_distance = np.argmin(distance)#获取最短距离
                if min_distance < threshold:#识别到打印信息
                    predict_id = label_list[min_distance]
                    predict_name = name_list[min_distance]
                    #6给人脸框添加内容
                    cv2.putText(frame,predict_name+" "+str(round(min_distance,2)),(l,b+30),cv2.FONT_HERSHEY_COMPLEX_SMALL,1,(0,255,0),1)
                #4是否记录考勤  
                    need_insert = False#用于后面判断是否变化了考勤,是则写入到attendance.csv文件
                    if predict_name in recog_record:#第一次检测到考勤则记录人脸信息,记录的是名字与考勤时间组成的键值对,如这次检测与上次记录差3s,则再考勤一次。上述都不是则跳过
                        if time.time()-recog_record[predict_name]>3:
                            need_insert = True
                            recog_record[predict_name] = time.time()
                            print(predict_name)
                        else:
                            print("无需重复签到!")
                            need_insert = False
                            pass
                    else:
                        need_insert = True
                        recog_record[predict_name] = time.time()
                        print(predict_name)
                    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,min_distance,time_str]
                        csv_writer.writerow(line)
                        print("{name} {time}考勤记录已成功更新入文件!".format(name=predict_name,time=time_str))
                else:
                    print("未识别到") 
            #5增加FPS
            now = time.time()
            fps = 1/(now - fps_time)
            fps_time = now
            cv2.putText(frame,"FPS:"+str(round(fps,2)),(20,40),cv2.FONT_HERSHEY_COMPLEX_SMALL,1,(0,255,0),1)
            
            cv2.imshow('Face attendance',frame)#展示每一帧图片
            if cv2.waitKey(10) & 0xFF == ord('q'):
                break
        f.close()
        cap.release()
        cv2.destroyAllWindows()   



#读取人脸注册时的特征
def getFeatureList():
    label_list = []
    name_list = []
    featuree_list = None#后面用的np.concatenate()方法决定了此处不能是空列表,否则无法拼接
    with open('./2/feature.csv','r') as f:
        csv_reader = csv.reader(f)
        for line in csv_reader:
            label_id = line[0]
            name = line[1]
            face_descriptor = eval(line[2])#从csv文件拿出来的列表是字符串,需要eval处理一下转为list
            face_descriptor = np.asarray(face_descriptor,dtype=np.float64)
            face_descriptor = np.reshape(face_descriptor,(1,-1))#转成1xn格式,期望就是这样
            label_list.append(label_id)#label_list拼接过程
            name_list.append(name)#name_list拼接过程
            if featuree_list is None:#featuree_list拼接过程
                featuree_list = face_descriptor
            else:
                featuree_list = np.concatenate((featuree_list,face_descriptor),axis=0)
#             print(name)
    return  label_list,name_list,featuree_list



label_list,name_list,featuree_list = getFeatureList()
faceRecognizer(threshold = 10)

四。项目源码

        源码链接:点击这里

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值