自用00010

自用

# 考勤监控系统

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)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Gouzy_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值