自用
# 考勤监控系统
import argparse
import copy
import cv2
import matplotlib.pyplot as plt
import numpy as np
import os
import pandas as pd
import signal
from STESDK import *
import time
# from exam3 import face_feature_extract,cal_sim
# 声明人脸识别类
fd = FaceDetector('models/detection/M_Detect_Hunter_SmallFace_Gray_360_3.1.0.model')
# 声明肢体检测类
bd = BodyDetector()
def cal_sim(feature1, feature2):
"""
!重要:本函数也会在exam4.py中被直接使用 !
子任务二:计算两个人脸特征的相似度
参数:
>>> feature1,feature2 :人脸特征列表
返回值:人脸特征相似度
提示:利用余弦相似度计算特征的相似度
"""
'''在此填写你的代码'''
a = np.dot(feature1, feature2) / (np.linalg.norm(feature1) * np.linalg.norm(feature2))
a = "{:.4f}".format(a)
return a
# 人脸特征提取
def face_feature_extract(img_read, face_box):
"""
!重要:本函数也会在exam4.py中被直接使用 !
子任务一:给定图像与某个人脸位置,提取该人脸特征
参数:
>>> img_read:人脸图像
>>> face_box: 单个人脸位置坐标
返回值:人脸特征列表
提示:运用全局变量face_aligner, face_extractor
"""
global face_aligner, face_extractor
'''在此填写你的代码'''
key_points = face_aligner.align(img_read, face_box)
crop_face = face_aligner.crop_face(img_read, key_points)
return face_extractor.extract(crop_face)
# 加载图片
def IO_for_read(path, file_name):
"""
你可以使用这个函数读取图像文件
>>> path: 素材根目录地址,即exam4文件夹地址
>>> file_name: 你希望读取的图像文件名
"""
return cv2.VideoCapture(path+"videos/" + file_name)
# 写入结果
def IO_for_write(path, result):
"""
你可以使用这个函数将结果写入一个Excel文件
>>> path:文件保存地址
>>> result: 检测结果,字典类型
"""
df = pd.DataFrame(list(result.items()))
df.to_excel(path+'result.xlsx', sheet_name='result', index=False, header=["姓名","考勤结果"])
# 读取人脸特征
def get_features(path):
"""
datasets文件夹的表格中存储了人脸特征,读取该特征,并将其存储至字典中。
参数:
>>> path:素材地址
返回值:人脸特征字典(姓名作为键,特征列表作为值),如{"Jack":特征列表,"Jacob":特征列表}
"""
# 人脸样本库
sample_list = os.listdir(path+"datasets/")
sample_feature_dict = {}
for i in range(len(sample_list)):
tmp = list()
dirc = sample_list[i]
sample_feature_df = pd.read_excel(path+"datasets/"+ dirc + '/' + 'feature-' + dirc + '.xlsx')
tmp.append(list(sample_feature_df.columns))
sample_feature_dict[dirc] = tmp.copy()
tmp.clear()
return sample_feature_dict
# IOU区域检测
def cal_iou(boxA,boxB):
"""
你可以使用这个函数计算两个box框的IOU,该值越大,表示两个框的重合度越大
>>> boxA:人体区域
>>> boxB:打卡区域
"""
boxA = [int(x) for x in boxA]
boxB = [int(x) for x in boxB]
xA = max(boxA[0], boxB[0])
yA = max(boxA[1], boxB[1])
xB = min(boxA[2], boxB[2])
yB = min(boxA[3], boxB[3])
interArea = max(0, xB - xA + 1) * max(0, yB - yA + 1)
boxAArea = (boxA[2] - boxA[0] + 1) * (boxA[3] - boxA[1] + 1)
boxBArea = (boxB[2] - boxB[0] + 1) * (boxB[3] - boxB[1] + 1)
iou = interArea / float(boxAArea + boxBArea - interArea)
return iou
# 设定考勤区域
def Monitor_area(canvas_shape):
"""
设定打卡区域,我们将画面左边1/5到右边3/5作为打卡区域。
>>> canvas_shape:画布大小
"""
leftx = int((1/5) * canvas_shape[1])
lefty = 0
rightx = int((3/5) * canvas_shape[1])
righty = canvas_shape[0]
attendance_area = (leftx,lefty, rightx, righty)#元组类型
return attendance_area
###############################################################
#### 不可修改本行之上的任何已有代码,利用本行之上的程序完成下方任务 ####
###############################################################
# 检测指定区域
def enter_designated_area(frame):
"""
子任务一:检测给定图像中是否有人经过设定的考勤区域
参数:
>>> frame: 当前图像
返回值:True/False,有人通过打卡区域,返回True,没有人通过打卡区域,返回False
提示一:调用Monitor_area函数设定打卡区域;
提示二:调用cal_iou函数计算两个目标框的位置重合度(iou值),当值大于等于0.4时表示有人进入打卡区域
提示三:调用人体检测模型中合适方法检测图像中的人体位置
"""
global bd
'''在此填写你的代码'''
h=frame.shape[0]
w=frame.shape[1]
attendance_area=Monitor_area([h,w])
boxA=bd.detect(frame)
boxB=attendance_area
if cal_iou(boxA[0],list(boxB))>=0.4:#boxB是元组类型变成列表
return True
return False
# 人脸识别
def face_recognition(face_boxes,frame, sample_feature_dict):
"""
子任务二:给定人脸边框列表及当前帧,识别出当前帧中的人脸
参数:
>>> face_boxes:人脸位置列表(可能是多人)
>>> frame:当前图像帧
>>> sample_feature_dict:人脸样本库特征字典,如{"Jack":特征列表,"Jacob":特征列表}
返回值:图像中人脸名字(列表)
提示一:直接调用exam3.py中的face_feature_extract()函数提取人脸特征,调用exam3.py中的cal_sim()函数计算特征之间的相似度
提示三:以最大相似度作为人脸识别的结果,无需考虑阈值。
"""
people = list()
'''在此填写你的代码'''
lm=[]
for face_box in face_boxes:
l=face_feature_extract(frame,face_box)
for key,value in sample_feature_dict.items():#把字典变成元组
lm.append(cal_sim(l,value[0]))
b=lm.idex(max(lm))
people.append(list(sample_feature_dict.key())[b])
return people
class p:
def __init__(self,attend_time,end_time):
self.attend_time = attend_time
self.end_time = end_time
# 主函数-智能考勤打卡监控
if __name__ == '__main__':
### 注意:设定保存地址,不可修改此三行代码 ###
parser = argparse.ArgumentParser()
parser.add_argument("--dest_path",default= '/home/senseedu/Desktop/competition_2/exam4/', help="files save path")
# args.dest_path = '/home/senseedu/Desktop/competition_2/exam4/'
args = parser.parse_args()
### 注意:不可修改三行,修改会导致程序错误 ###
"""
子任务三:统计每个人的考勤信息(正常上班、早退、迟到)并保存至excel表格中;
提示一:考勤结果分为“正常上班”、“迟到+早退”、“迟到”、“早退”;
提示二:将统计结果以字典列表形式存储,使用IO_for_write存储结果,文件的存储路径需设置为参数args.dest_path
"""
# 获取视频名称
video_list = os.listdir(args.dest_path+"videos/") # 使用参数args.dest_path设置素材根目录地址
# 获取样本库人脸特征
sample_feature_dict = get_features(args.dest_path)
# 存储考勤结果
result = {}
print('开始考勤......')
'''在此填写你的代码'''
cap = IO_for_read(args.dest_path,video_list[0])#读取视频,读的是一个列表
total_frame=cap.get(cv2.CAP_PROP_FRAME_COUNT)
tmp=[]
for i in tqdm(range(int(total_frame)),desc='processing'):
ret,frame=cap.read()
face_boxes=fd.detect(frame)
ok=False
j=[]
if len(face_boxes)!=0:
ok=enter_designated_area(frame)#判断给定图像是否有人经过考勤区域,返回TF
j=face_recognition(face_boxes,frame,sample_feature_dict)#返回图像人名列表
tmp.append([i,ok,j])
df=pd.DataFrame(np.array(tmp))
#写入文件中
# df1.to_csv('data.csv')
# df=pd.read_csv('data.csv')
a=df[(df['1']==True)&(df['2']=="['Jacob']")]
b=df[(df['1']==True)&(df['2']=="['David']")]
c=df[(df['1']==True)&(df['2']=="['Jack']")]
a_f_t = list(a['0'].iloc[0:1])[0] #取第一列,第一个转换成列表,取第一个
b_f_t = list(b['0'].iloc[0:1])[0]
c_f_t = list(c['0'].iloc[0:1])[0]
a_e_t = list(a['0'].iloc[-1:])[0]#取第一列,最后一个转换为列表,取第一个
b_e_t = list(b['0'].iloc[-1:])[0]
c_e_t = list(c['0'].iloc[-1:])[0]
Jacob = p(a_f_t,a_e_t)
David = p(b_f_t, b_e_t)
Jack = p(c_f_t, c_e_t)
def f(p):
if p.f_t>50 and (p.e_t-p.f_t)<200:
return '迟到+早退'
elif p.f_t>50:
return '迟到'
elif (p.e_t-p.f_t)<200:
return '早退'
return '正常上班'
result['David']=f(David)
result['Jacob']=f(Jacob)
result['Jack']=f(Jack)
print(result)
IO_for_read(args.dest_path,result)
print('任务已完成!!!')
cap=IO_for_read(args.dest_path,video_list[0])#读取视频
total_num=cap.get(cv2.CAP_PROP_FRAME_COUNT)
frame_num=0
dic={}#字典
dict={}
while True and frame_num<total_num:
frame_num+=1
_, frame=cap.imread()
attend_area=enter_designated_area(frame)#返回TorF
if attend_area=='True':
rect=fd.detect(frame)
name=face_recognition(rect,frame,sample_feature_dict)#返回人名
a=dic.get(name,1)
if a==1:#第一次遇到
dic.update({name,frame_num})
else:
dict.update({name,frame_num})
for key in dic.items():
interval=int(dict.get(key))-int(dic.get(key))
if interval<200 and int(dic.get(key))>50:
result.update({key,'迟到+早退'})
elif interval<200:
result.update({key,'早退'})
elif int(dic.get(key))>50:
result.update({key,'迟到'})
else:
result.update({key,'正常上班'})
print(result)
IO_for_write(args.dest_path,result)