├── IOT_FaceRecogition_Attendance ├── .idea │ ├── .gitignore │ ├── IOT人脸识别签到系统.iml │ ├── inspectionProfiles │ │ ├── Project_Default.xml │ │ └── profiles_settings.xml │ ├── misc.xml │ └── modules.xml ├── Attendance.csv ├── IOT人脸识别签到系统测试版V0.99说明.md ├── Images │ ├── EDC.png │ ├── GodFather.png │ └── JW.png ├── README.MD ├── icon.png ├── logo.png ├── mainwindow.py ├── mainwindow.spec ├── mainwindow.ui ├── mianwindow.spec ├── out_window.py ├── outputwindow.ui ├── resource.qrc └── resource_rc.py └── README.md /IOT_FaceRecogition_Attendance/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /IOT_FaceRecogition_Attendance/.idea/IOT人脸识别签到系统.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /IOT_FaceRecogition_Attendance/.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | -------------------------------------------------------------------------------- /IOT_FaceRecogition_Attendance/.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /IOT_FaceRecogition_Attendance/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /IOT_FaceRecogition_Attendance/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /IOT_FaceRecogition_Attendance/Attendance.csv: -------------------------------------------------------------------------------- 1 | BIGBOSS,22/04/20 04:15:23,Clock In 2 | BIGBOSS,22/04/20 04:15:32,Clock Out 3 | BIGBOSS,22/04/20 04:21:42,Clock In 4 | BIGBOSS,22/04/20 04:21:51,Clock Out 5 | 6 | 人脸识别签到系统测试 7 | 8 | BIGBOSS,22/04/20 04:23:32,Clock In 9 | BIGBOSS,22/04/20 04:28:42,Clock Out 10 | BIGBOSS,22/04/20 05:24:35,Clock In 11 | BIGBOSS,22/04/20 05:24:39,Clock Out 12 | BIGBOSS,22/04/20 05:25:38,Clock In 13 | BIGBOSS,22/04/20 05:25:41,Clock Out 14 | BIGBOSS,22/04/20 05:26:00,Clock In 15 | BIGBOSS,22/04/20 05:26:06,Clock Out 16 | 17 | 人脸识别签到系统测试2: 18 | 19 | BIGBOSS,22/04/20 05:28:10,Clock In 20 | BIGBOSS,22/04/20 05:30:52,Clock Out 21 | BIGBOSS,22/04/21 00:51:12,Clock In 22 | BIGBOSS,22/04/21 00:51:16,Clock Out 23 | BIGBOSS,22/04/21 00:57:57,Clock In 24 | BIGBOSS,22/04/21 00:58:08,Clock Out 25 | BIGBOSS,22/04/21 00:59:25,Clock In 26 | BIGBOSS,22/04/21 01:01:38,Clock Out 27 | 28 | 测试3 29 | 30 | GODFATHER,22/04/21 01:42:23,Clock In 31 | GODFATHER,22/04/21 01:43:13,Clock Out 32 | -------------------------------------------------------------------------------- /IOT_FaceRecogition_Attendance/IOT人脸识别签到系统测试版V0.99说明.md: -------------------------------------------------------------------------------- 1 | # IOT人脸识别签到系统测试版V0.99 2 | 3 | ## 使用注意事项: 4 | 5 | ## 本项目集成项目运行所需的环境,并打包了EXE文件,直接运行mainwindow.exe文件即可 6 | 7 | ### 1.使用中如果报错: 8 | 9 | ![01](C:\Users\12294\Desktop\01.png) 10 | 11 | **则是系统文件中face_recogition_models文件未识别到** 12 | 13 | 将**face-model**压缩包中的文件解压到**mainwindow文件夹**中,进行**替换** 14 | 15 | ### 2.mainwindow文件夹必须是父级目录!!! -------------------------------------------------------------------------------- /IOT_FaceRecogition_Attendance/Images/EDC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BIGBOSS-dedsec/Python-Face-recognition-Attendance/7c7987e9102047f54ba06ba11e232e5c00dcd9b8/IOT_FaceRecogition_Attendance/Images/EDC.png -------------------------------------------------------------------------------- /IOT_FaceRecogition_Attendance/Images/GodFather.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BIGBOSS-dedsec/Python-Face-recognition-Attendance/7c7987e9102047f54ba06ba11e232e5c00dcd9b8/IOT_FaceRecogition_Attendance/Images/GodFather.png -------------------------------------------------------------------------------- /IOT_FaceRecogition_Attendance/Images/JW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BIGBOSS-dedsec/Python-Face-recognition-Attendance/7c7987e9102047f54ba06ba11e232e5c00dcd9b8/IOT_FaceRecogition_Attendance/Images/JW.png -------------------------------------------------------------------------------- /IOT_FaceRecogition_Attendance/README.MD: -------------------------------------------------------------------------------- 1 | # 前言 2 | 本项目为IOT实验室人员签到考勤设计,系统实现功能: 3 | **1.人员人脸识别并完成签到/签退 4 | 2.考勤时间计算 5 | 3.保存考勤数据为CSV格式(Excel表格)** 6 | 7 | *PS:本系统2D人脸识别,节约了繁琐的人脸识别训练部分,简洁快捷* 8 | 9 | **该项目为测试版,正式版会加入更多的功能,持续更新中.....** 10 | *测试版项目地址我会放到结尾* 11 | ## 项目效果图 12 | **系统初始化登陆界面** 13 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/f48f7936b3ff4a5496e188c13c64dc36.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQklHQk9TU3lpZmk=,size_20,color_FFFFFF,t_70,g_se,x_16) 14 | **主界面展示图:** 15 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/c2d5b4d272ad4a7eac5ae8107dfb56e9.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQklHQk9TU3lpZmk=,size_20,color_FFFFFF,t_70,g_se,x_16) 16 | **签到功能展示** 17 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/61685dd4b9184bdb8c33379f0e52833d.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQklHQk9TU3lpZmk=,size_20,color_FFFFFF,t_70,g_se,x_16) 18 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/0a2258078cc84c16b941cc4220a7aca0.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQklHQk9TU3lpZmk=,size_20,color_FFFFFF,t_70,g_se,x_16) 19 | **签退功能展示** 20 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/4cc3fd36c2584623b277994dbe1c9b1e.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQklHQk9TU3lpZmk=,size_20,color_FFFFFF,t_70,g_se,x_16) 21 | **后台签到数据记录** 22 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/f752bbde1e7b4a4bba2090f38d46ae2b.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQklHQk9TU3lpZmk=,size_20,color_FFFFFF,t_70,g_se,x_16) 23 | **是否签到/退判断** 24 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/eadfab52443c4c29b1829a653a41887f.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQklHQk9TU3lpZmk=,size_20,color_FFFFFF,t_70,g_se,x_16) 25 | # 项目需要的环境 26 | *核心环境:* 27 | **OpenCV-Python 4.5.5.64** 28 | **face_recognition 1.30 29 | face_recognition_model 0.3.0 30 | dlib 19.23.1** 31 | 32 | *UI窗体界面:* 33 | **PyQt5 5.15.4 34 | pyqt5-plugins 5.15.4.2.2 35 | PyQt5-Qt5 5.15.2 36 | PyQt5-sip 12.10.1 37 | pyqt5-tools 5.15.4.3.2** 38 | 39 | ## 编译器 40 | **Pycham 2021.1.3** 41 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/ba2d84f8b9704abfbfa359b5bf616fea.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQklHQk9TU3lpZmk=,size_18,color_FFFFFF,t_70,g_se,x_16) 42 | **Python版本 3.9.12** 43 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/3050ef31da794f1f98d32fb05a5ae651.png) 44 | **Anaconda** 45 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/47462d375b0a4e08a22cf33bc50b0d71.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQklHQk9TU3lpZmk=,size_20,color_FFFFFF,t_70,g_se,x_16) 46 | ### 辅助开发QT-designer 47 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/d7e826c9112f4f27b462f3a1b3e3b891.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQklHQk9TU3lpZmk=,size_20,color_FFFFFF,t_70,g_se,x_16) 48 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/e9bef28e2e0241828bcd633769542490.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQklHQk9TU3lpZmk=,size_20,color_FFFFFF,t_70,g_se,x_16) 49 | #### 项目配置 50 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/b8c6fa4783d243f2b2ba4702c1ae52e3.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQklHQk9TU3lpZmk=,size_19,color_FFFFFF,t_70,g_se,x_16) 51 | 52 | # 代码部分 53 | ## 核心代码 54 | **MainWindow.py** 55 | *UI文件加载:* 56 | ```python 57 | class Ui_Dialog(QDialog): 58 | def __init__(self): 59 | super(Ui_Dialog, self).__init__() 60 | loadUi("mainwindow.ui", self) #加载QTUI文件 61 | 62 | self.runButton.clicked.connect(self.runSlot) 63 | 64 | self._new_window = None 65 | self.Videocapture_ = None 66 | ``` 67 | *摄像头调用:* 68 | 69 | ```python 70 | def refreshAll(self): 71 | print("当前调用人俩检测摄像头编号(0为笔记本内置摄像头,1为USB外置摄像头):") 72 | self.Videocapture_ = "0" 73 | ``` 74 | **OutWindow.py** 75 | *获取当前系统时间* 76 | ```python 77 | class Ui_OutputDialog(QDialog): 78 | def __init__(self): 79 | super(Ui_OutputDialog, self).__init__() 80 | loadUi("./outputwindow.ui", self) #加载输出窗体UI 81 | 82 | #datetime 时间模块 83 | now = QDate.currentDate() 84 | current_date = now.toString('ddd dd MMMM yyyy') #时间格式 85 | current_time = datetime.datetime.now().strftime("%I:%M %p") 86 | self.Date_Label.setText(current_date) 87 | self.Time_Label.setText(current_time) 88 | 89 | self.image = None 90 | ``` 91 | *签到时间计算* 92 | 93 | ```python 94 | def ElapseList(self,name): 95 | with open('Attendance.csv', "r") as csv_file: 96 | csv_reader = csv.reader(csv_file, delimiter=',') 97 | line_count = 2 98 | 99 | Time1 = datetime.datetime.now() 100 | Time2 = datetime.datetime.now() 101 | for row in csv_reader: 102 | for field in row: 103 | if field in row: 104 | if field == 'Clock In': 105 | if row[0] == name: 106 | Time1 = (datetime.datetime.strptime(row[1], '%y/%m/%d %H:%M:%S')) 107 | self.TimeList1.append(Time1) 108 | if field == 'Clock Out': 109 | if row[0] == name: 110 | Time2 = (datetime.datetime.strptime(row[1], '%y/%m/%d %H:%M:%S')) 111 | self.TimeList2.append(Time2) 112 | ``` 113 | *人脸识别部分* 114 | 115 | ```python 116 | # 人脸识别部分 117 | faces_cur_frame = face_recognition.face_locations(frame) 118 | encodes_cur_frame = face_recognition.face_encodings(frame, faces_cur_frame) 119 | 120 | for encodeFace, faceLoc in zip(encodes_cur_frame, faces_cur_frame): 121 | match = face_recognition.compare_faces(encode_list_known, encodeFace, tolerance=0.50) 122 | face_dis = face_recognition.face_distance(encode_list_known, encodeFace) 123 | name = "unknown" #未知人脸识别为unknown 124 | best_match_index = np.argmin(face_dis) 125 | if match[best_match_index]: 126 | name = class_names[best_match_index].upper() 127 | y1, x2, y2, x1 = faceLoc 128 | cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2) 129 | cv2.rectangle(frame, (x1, y2 - 20), (x2, y2), (0, 255, 0), cv2.FILLED) 130 | cv2.putText(frame, name, (x1 + 6, y2 - 6), cv2.FONT_HERSHEY_COMPLEX, 0.5, (255, 255, 255), 1) 131 | mark_attendance(name) 132 | 133 | return frame 134 | ``` 135 | *签到数据保存与判断* 136 | 137 | ```python 138 | # csv表格保存数据 139 | def mark_attendance(name): 140 | """ 141 | :param name: 人脸识别部分 142 | :return: 143 | """ 144 | if self.ClockInButton.isChecked(): 145 | self.ClockInButton.setEnabled(False) 146 | with open('Attendance.csv', 'a') as f: 147 | if (name != 'unknown'): #签到判断:是否为已经识别人脸 148 | buttonReply = QMessageBox.question(self, '欢迎 ' + name, '开始签到' , 149 | QMessageBox.Yes | QMessageBox.No, QMessageBox.No) 150 | if buttonReply == QMessageBox.Yes: 151 | 152 | date_time_string = datetime.datetime.now().strftime("%y/%m/%d %H:%M:%S") 153 | f.writelines(f'\n{name},{date_time_string},Clock In') 154 | self.ClockInButton.setChecked(False) 155 | 156 | self.NameLabel.setText(name) 157 | self.StatusLabel.setText('签到') 158 | self.HoursLabel.setText('开始签到计时中') 159 | self.MinLabel.setText('') 160 | 161 | self.Time1 = datetime.datetime.now() 162 | self.ClockInButton.setEnabled(True) 163 | else: 164 | print('签到操作失败') 165 | self.ClockInButton.setEnabled(True) 166 | elif self.ClockOutButton.isChecked(): 167 | self.ClockOutButton.setEnabled(False) 168 | with open('Attendance.csv', 'a') as f: 169 | if (name != 'unknown'): 170 | buttonReply = QMessageBox.question(self, '嗨呀 ' + name, '确认签退?', 171 | QMessageBox.Yes | QMessageBox.No, QMessageBox.No) 172 | if buttonReply == QMessageBox.Yes: 173 | date_time_string = datetime.datetime.now().strftime("%y/%m/%d %H:%M:%S") 174 | f.writelines(f'\n{name},{date_time_string},Clock Out') 175 | self.ClockOutButton.setChecked(False) 176 | 177 | self.NameLabel.setText(name) 178 | self.StatusLabel.setText('签退') 179 | self.Time2 = datetime.datetime.now() 180 | 181 | self.ElapseList(name) 182 | self.TimeList2.append(datetime.datetime.now()) 183 | CheckInTime = self.TimeList1[-1] 184 | CheckOutTime = self.TimeList2[-1] 185 | self.ElapseHours = (CheckOutTime - CheckInTime) 186 | self.MinLabel.setText("{:.0f}".format(abs(self.ElapseHours.total_seconds() / 60)%60) + 'm') 187 | self.HoursLabel.setText("{:.0f}".format(abs(self.ElapseHours.total_seconds() / 60**2)) + 'h') 188 | self.ClockOutButton.setEnabled(True) 189 | else: 190 | print('签退操作失败') 191 | self.ClockOutButton.setEnabled(True) 192 | ``` 193 | 194 | ### 项目目录结构 195 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/985c4a761fce457cb773e87fde0903ee.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQklHQk9TU3lpZmk=,size_8,color_FFFFFF,t_70,g_se,x_16) 196 | # 后记 197 | ***因为本系统没有进行人脸训练建立模型,系统误识别率较高,安全性较低 198 | 系统优化较差,摄像头捕捉帧数较低(8-9),后台占有高,CPU利用率较高 199 | 数据保存CSV格式,安全性较低*** 200 | ## 正式版改进 201 | **1.加入TensorFlow深度学习,提高系统人脸识别安全性与准确性 202 | 2.加入MySQL数据库,对签到数据进行更安全保护,不易被修改 203 | 3.美化优化UI设计** -------------------------------------------------------------------------------- /IOT_FaceRecogition_Attendance/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BIGBOSS-dedsec/Python-Face-recognition-Attendance/7c7987e9102047f54ba06ba11e232e5c00dcd9b8/IOT_FaceRecogition_Attendance/icon.png -------------------------------------------------------------------------------- /IOT_FaceRecogition_Attendance/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BIGBOSS-dedsec/Python-Face-recognition-Attendance/7c7987e9102047f54ba06ba11e232e5c00dcd9b8/IOT_FaceRecogition_Attendance/logo.png -------------------------------------------------------------------------------- /IOT_FaceRecogition_Attendance/mainwindow.py: -------------------------------------------------------------------------------- 1 | # Author BIGBOSS 2 | # April 2022 3 | # IOT人脸识别签到系统 4 | # WX:BIGBOSSyifi 5 | # Mail:bigbossyifi@gmail.com 6 | # *- 7 | 8 | import sys 9 | from PyQt5.uic import loadUi 10 | from PyQt5 import QtWidgets 11 | from PyQt5.QtCore import pyqtSlot 12 | from PyQt5.QtWidgets import QApplication, QDialog 13 | import resource_rc #加载资源文件 14 | # from model import Model 15 | from out_window import Ui_OutputDialog 16 | 17 | 18 | class Ui_Dialog(QDialog): 19 | def __init__(self): 20 | super(Ui_Dialog, self).__init__() 21 | loadUi("mainwindow.ui", self) #加载QTUI文件 22 | 23 | self.runButton.clicked.connect(self.runSlot) 24 | 25 | self._new_window = None 26 | self.Videocapture_ = None 27 | 28 | def refreshAll(self): 29 | print("当前调用人俩检测摄像头编号(0为笔记本内置摄像头,1为USB外置摄像头):") 30 | self.Videocapture_ = "0" 31 | 32 | @pyqtSlot() 33 | def runSlot(self): 34 | print("IOT人脸识别签到系统运行中...") 35 | self.refreshAll() 36 | print(self.Videocapture_) 37 | ui.hide() # UI隐藏 38 | self.outputWindow_() # 创建新的窗体 39 | 40 | def outputWindow_(self): 41 | """ 42 | 在GUI中创建人脸识别区域的窗体 43 | """ 44 | self._new_window = Ui_OutputDialog() 45 | self._new_window.show() 46 | self._new_window.startVideo(self.Videocapture_) 47 | print("人脸识别功能初始化中....") 48 | print("人脸识别功能初始化完成!") 49 | 50 | 51 | if __name__ == "__main__": 52 | app = QApplication(sys.argv) 53 | ui = Ui_Dialog() 54 | ui.show() 55 | sys.exit(app.exec_()) 56 | -------------------------------------------------------------------------------- /IOT_FaceRecogition_Attendance/mainwindow.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: python ; coding: utf-8 -*- 2 | 3 | 4 | block_cipher = None 5 | 6 | 7 | a = Analysis( 8 | ['mainwindow.py'], 9 | pathex=[], 10 | binaries=[], 11 | datas=[], 12 | hiddenimports=[], 13 | hookspath=[], 14 | hooksconfig={}, 15 | runtime_hooks=[], 16 | excludes=[], 17 | win_no_prefer_redirects=False, 18 | win_private_assemblies=False, 19 | cipher=block_cipher, 20 | noarchive=False, 21 | ) 22 | pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) 23 | 24 | exe = EXE( 25 | pyz, 26 | a.scripts, 27 | a.binaries, 28 | a.zipfiles, 29 | a.datas, 30 | [], 31 | name='mainwindow', 32 | debug=False, 33 | bootloader_ignore_signals=False, 34 | strip=False, 35 | upx=True, 36 | upx_exclude=[], 37 | runtime_tmpdir=None, 38 | console=False, 39 | disable_windowed_traceback=False, 40 | argv_emulation=False, 41 | target_arch=None, 42 | codesign_identity=None, 43 | entitlements_file=None, 44 | ) 45 | -------------------------------------------------------------------------------- /IOT_FaceRecogition_Attendance/mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Dialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 800 10 | 600 11 | 12 | 13 | 14 | 15 | 800 16 | 600 17 | 18 | 19 | 20 | 21 | 800 22 | 600 23 | 24 | 25 | 26 | IOT人脸识别签到考勤系统-测试版V0.99 27 | 28 | 29 | 30 | :/icon/icon.png:/icon/icon.png 31 | 32 | 33 | 34 | 35 | 0 36 | 500 37 | 801 38 | 101 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 800 47 | 600 48 | 49 | 50 | 51 | 52 | 黑体 53 | 30 54 | 55 | 56 | 57 | IOT来电 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 0 67 | 0 68 | 886 69 | 425 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 884 78 | 432 79 | 80 | 81 | 82 | 83 | 84 | 85 | :/logo/logo.png 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 230 95 | 440 96 | 331 97 | 61 98 | 99 | 100 | 101 | 102 | 600 103 | 800 104 | 105 | 106 | 107 | 108 | Roboto Condensed 109 | 14 110 | 75 111 | true 112 | 113 | 114 | 115 | IOT人脸识别签到系统—测试版V0.98 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /IOT_FaceRecogition_Attendance/mianwindow.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: python ; coding: utf-8 -*- 2 | 3 | 4 | block_cipher = None 5 | 6 | 7 | a = Analysis( 8 | ['mianwindow.py'], 9 | pathex=[], 10 | binaries=[], 11 | datas=[], 12 | hiddenimports=[], 13 | hookspath=[], 14 | hooksconfig={}, 15 | runtime_hooks=[], 16 | excludes=[], 17 | win_no_prefer_redirects=False, 18 | win_private_assemblies=False, 19 | cipher=block_cipher, 20 | noarchive=False, 21 | ) 22 | pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) 23 | 24 | exe = EXE( 25 | pyz, 26 | a.scripts, 27 | a.binaries, 28 | a.zipfiles, 29 | a.datas, 30 | [], 31 | name='mianwindow', 32 | debug=False, 33 | bootloader_ignore_signals=False, 34 | strip=False, 35 | upx=True, 36 | upx_exclude=[], 37 | runtime_tmpdir=None, 38 | console=False, 39 | disable_windowed_traceback=False, 40 | argv_emulation=False, 41 | target_arch=None, 42 | codesign_identity=None, 43 | entitlements_file=None, 44 | ) 45 | -------------------------------------------------------------------------------- /IOT_FaceRecogition_Attendance/out_window.py: -------------------------------------------------------------------------------- 1 | # Author BIGBOSS 2 | # April 2022 3 | # IOT人脸识别签到系统 4 | # WX:BIGBOSSyifi 5 | # Mail:bigbossyifi@gmail.com 6 | # *- 7 | 8 | from PyQt5.QtGui import QImage, QPixmap 9 | from PyQt5.uic import loadUi 10 | from PyQt5.QtCore import pyqtSlot, QTimer, QDate, Qt 11 | from PyQt5.QtWidgets import QDialog,QMessageBox 12 | import cv2 13 | import face_recognition 14 | import numpy as np 15 | import datetime 16 | import os 17 | import csv 18 | 19 | class Ui_OutputDialog(QDialog): 20 | def __init__(self): 21 | super(Ui_OutputDialog, self).__init__() 22 | loadUi("./outputwindow.ui", self) #加载输出窗体UI 23 | 24 | #datetime 时间模块 25 | now = QDate.currentDate() 26 | current_date = now.toString('ddd dd MMMM yyyy') #时间格式 27 | current_time = datetime.datetime.now().strftime("%I:%M %p") 28 | self.Date_Label.setText(current_date) 29 | self.Time_Label.setText(current_time) 30 | 31 | self.image = None 32 | 33 | @pyqtSlot() 34 | def startVideo(self, camera_name): 35 | """ 36 | :param camera_name: 摄像头或usb摄像头的链接 37 | :return: 38 | """ 39 | if len(camera_name) == 1: 40 | self.capture = cv2.VideoCapture(int(camera_name)) 41 | else: 42 | self.capture = cv2.VideoCapture(camera_name) 43 | self.timer = QTimer(self) # 创建 Timer 44 | path = 'Images' #读取人脸识别图片的路径 45 | if not os.path.exists(path): 46 | os.mkdir(path) 47 | # 路径下人脸编码和人脸名称列表 48 | images = [] 49 | self.class_names = [] 50 | self.encode_list = [] 51 | self.TimeList1 = [] 52 | self.TimeList2 = [] 53 | attendance_list = os.listdir(path) 54 | 55 | for cl in attendance_list: 56 | cur_img = cv2.imread(f'{path}/{cl}') 57 | images.append(cur_img) 58 | self.class_names.append(os.path.splitext(cl)[0]) 59 | for img in images: 60 | img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 61 | boxes = face_recognition.face_locations(img) 62 | encodes_cur_frame = face_recognition.face_encodings(img, boxes)[0] 63 | self.encode_list.append(encodes_cur_frame) 64 | self.timer.timeout.connect(self.update_frame) # 超时连接输出 65 | self.timer.start(10) 66 | 67 | def face_rec_(self, frame, encode_list_known, class_names): 68 | """ 69 | :param frame: 摄像头捕捉 70 | :param encode_list_known: 已录入的人脸编码 71 | :param class_names: 已录入的人脸姓名 72 | :return: 73 | """ 74 | # csv表格保存数据 75 | def mark_attendance(name): 76 | """ 77 | :param name: 人脸识别部分 78 | :return: 79 | """ 80 | if self.ClockInButton.isChecked(): 81 | self.ClockInButton.setEnabled(False) 82 | with open('Attendance.csv', 'a') as f: 83 | if (name != 'unknown'): #签到判断:是否为已经识别人脸 84 | buttonReply = QMessageBox.question(self, '欢迎 ' + name, '开始签到' , 85 | QMessageBox.Yes | QMessageBox.No, QMessageBox.No) 86 | if buttonReply == QMessageBox.Yes: 87 | 88 | date_time_string = datetime.datetime.now().strftime("%y/%m/%d %H:%M:%S") 89 | f.writelines(f'\n{name},{date_time_string},Clock In') 90 | self.ClockInButton.setChecked(False) 91 | 92 | self.NameLabel.setText(name) 93 | self.StatusLabel.setText('签到') 94 | self.HoursLabel.setText('开始签到计时中') 95 | self.MinLabel.setText('') 96 | 97 | self.Time1 = datetime.datetime.now() 98 | self.ClockInButton.setEnabled(True) 99 | else: 100 | print('签到操作失败') 101 | self.ClockInButton.setEnabled(True) 102 | elif self.ClockOutButton.isChecked(): 103 | self.ClockOutButton.setEnabled(False) 104 | with open('Attendance.csv', 'a') as f: 105 | if (name != 'unknown'): 106 | buttonReply = QMessageBox.question(self, '嗨呀 ' + name, '确认签退?', 107 | QMessageBox.Yes | QMessageBox.No, QMessageBox.No) 108 | if buttonReply == QMessageBox.Yes: 109 | date_time_string = datetime.datetime.now().strftime("%y/%m/%d %H:%M:%S") 110 | f.writelines(f'\n{name},{date_time_string},Clock Out') 111 | self.ClockOutButton.setChecked(False) 112 | 113 | self.NameLabel.setText(name) 114 | self.StatusLabel.setText('签退') 115 | self.Time2 = datetime.datetime.now() 116 | 117 | self.ElapseList(name) 118 | self.TimeList2.append(datetime.datetime.now()) 119 | CheckInTime = self.TimeList1[-1] 120 | CheckOutTime = self.TimeList2[-1] 121 | self.ElapseHours = (CheckOutTime - CheckInTime) 122 | self.MinLabel.setText("{:.0f}".format(abs(self.ElapseHours.total_seconds() / 60)%60) + 'm') 123 | self.HoursLabel.setText("{:.0f}".format(abs(self.ElapseHours.total_seconds() / 60**2)) + 'h') 124 | self.ClockOutButton.setEnabled(True) 125 | else: 126 | print('签退操作失败') 127 | self.ClockOutButton.setEnabled(True) 128 | 129 | # 人脸识别部分 130 | faces_cur_frame = face_recognition.face_locations(frame) 131 | encodes_cur_frame = face_recognition.face_encodings(frame, faces_cur_frame) 132 | 133 | for encodeFace, faceLoc in zip(encodes_cur_frame, faces_cur_frame): 134 | match = face_recognition.compare_faces(encode_list_known, encodeFace, tolerance=0.50) 135 | face_dis = face_recognition.face_distance(encode_list_known, encodeFace) 136 | name = "unknown" #未知人脸识别为unknown 137 | best_match_index = np.argmin(face_dis) 138 | if match[best_match_index]: 139 | name = class_names[best_match_index].upper() 140 | y1, x2, y2, x1 = faceLoc 141 | cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2) 142 | cv2.rectangle(frame, (x1, y2 - 20), (x2, y2), (0, 255, 0), cv2.FILLED) 143 | cv2.putText(frame, name, (x1 + 6, y2 - 6), cv2.FONT_HERSHEY_COMPLEX, 0.5, (255, 255, 255), 1) 144 | mark_attendance(name) 145 | 146 | return frame 147 | 148 | def showdialog(self): 149 | msg = QMessageBox() 150 | msg.setIcon(QMessageBox.Information) 151 | 152 | msg.setText("提示") 153 | msg.setInformativeText("消息附加") 154 | msg.setWindowTitle("消息提示") 155 | msg.setDetailedText("内容如下:") 156 | msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) 157 | 158 | 159 | def ElapseList(self,name): 160 | with open('Attendance.csv', "r") as csv_file: 161 | csv_reader = csv.reader(csv_file, delimiter=',') 162 | line_count = 2 163 | 164 | Time1 = datetime.datetime.now() 165 | Time2 = datetime.datetime.now() 166 | for row in csv_reader: 167 | for field in row: 168 | if field in row: 169 | if field == 'Clock In': 170 | if row[0] == name: 171 | Time1 = (datetime.datetime.strptime(row[1], '%y/%m/%d %H:%M:%S')) 172 | self.TimeList1.append(Time1) 173 | if field == 'Clock Out': 174 | if row[0] == name: 175 | Time2 = (datetime.datetime.strptime(row[1], '%y/%m/%d %H:%M:%S')) 176 | self.TimeList2.append(Time2) 177 | 178 | def update_frame(self): 179 | ret, self.image = self.capture.read() 180 | self.displayImage(self.image, self.encode_list, self.class_names, 1) 181 | 182 | def displayImage(self, image, encode_list, class_names, window=1): 183 | """ 184 | :param image: 从摄像头捕捉的图像 185 | :param encode_list: 已识别人脸识别编码 186 | :param class_names: 已识别人脸人员姓名 187 | :param window: 窗体 188 | :return: 189 | """ 190 | image = cv2.resize(image, (640, 480)) #定义识别区域大小 191 | try: 192 | image = self.face_rec_(image, encode_list, class_names) 193 | except Exception as e: 194 | print(e) 195 | qformat = QImage.Format_Indexed8 196 | if len(image.shape) == 3: 197 | if image.shape[2] == 4: 198 | qformat = QImage.Format_RGBA8888 199 | else: 200 | qformat = QImage.Format_RGB888 201 | outImage = QImage(image, image.shape[1], image.shape[0], image.strides[0], qformat) 202 | outImage = outImage.rgbSwapped() 203 | 204 | if window == 1: 205 | self.imgLabel.setPixmap(QPixmap.fromImage(outImage)) 206 | self.imgLabel.setScaledContents(True) 207 | -------------------------------------------------------------------------------- /IOT_FaceRecogition_Attendance/outputwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | OutputDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 951 10 | 591 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | 21 | 1280 22 | 720 23 | 24 | 25 | 26 | 27 | Calibri 28 | 75 29 | true 30 | 31 | 32 | 33 | IOT人脸识别签到系统测试版V0.99 34 | 35 | 36 | 37 | :/icon/icon.png:/icon/icon.png 38 | 39 | 40 | 41 | 42 | 10 43 | 10 44 | 640 45 | 480 46 | 47 | 48 | 49 | 50 | 4 51 | 0 52 | 53 | 54 | 55 | 56 | 640 57 | 480 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 10 68 | 500 69 | 641 70 | 80 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 400 79 | 600 80 | 81 | 82 | 83 | 84 | Roboto Condensed Light 85 | 30 86 | 75 87 | true 88 | 89 | 90 | 91 | 签到 92 | 93 | 94 | true 95 | 96 | 97 | 100 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 400 106 | 600 107 | 108 | 109 | 110 | 111 | Roboto Condensed Light 112 | 30 113 | 75 114 | true 115 | 116 | 117 | 118 | 签退 119 | 120 | 121 | true 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 660 131 | 40 132 | 281 133 | 121 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | Roboto Condensed Light 142 | 15 143 | 75 144 | true 145 | 146 | 147 | 148 | - 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | Roboto Condensed Light 157 | 15 158 | 75 159 | true 160 | 161 | 162 | 163 | - 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | Roboto Condensed Light 172 | 16 173 | 75 174 | true 175 | 176 | 177 | 178 | 日期 : 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | Roboto Condensed Light 187 | 16 188 | 75 189 | true 190 | 191 | 192 | 193 | 时间 : 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 660 203 | 200 204 | 271 205 | 291 206 | 207 | 208 | 209 | 签到详细 210 | 211 | 212 | 213 | 214 | 30 215 | 30 216 | 110 217 | 211 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | Roboto Condensed Light 226 | 12 227 | 50 228 | false 229 | 230 | 231 | 232 | 姓名 : 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | Roboto Condensed Light 241 | 12 242 | 50 243 | false 244 | 245 | 246 | 247 | 状态 : 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | Roboto Condensed Light 256 | 12 257 | 50 258 | false 259 | 260 | 261 | 262 | 时间 : 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 120 272 | 30 273 | 131 274 | 211 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | Roboto Condensed Light 283 | 12 284 | 50 285 | false 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | Roboto Condensed Light 298 | 12 299 | 50 300 | false 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | Roboto Condensed Light 315 | 12 316 | 50 317 | false 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | Roboto Condensed Light 330 | 12 331 | 50 332 | false 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | -------------------------------------------------------------------------------- /IOT_FaceRecogition_Attendance/resource.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | logo.png 4 | 5 | 6 | icon.png 7 | 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | This project is designed for IOT laboratory personnel check-in and attendance, and the system implements the following functions: 4 | **1. Personnel face recognition and complete check-in/check-out 5 | 2. Calculation of attendance time 6 | 3. Save the attendance data in CSV format (Excel) ** 7 | 8 | PS: This system 2D face recognition, saving the tedious face recognition training part, simple and fast 9 | 10 | This project is a beta version, the official version will add more features, continue to update..... 11 | I'll put the beta project address at the end 12 | 13 | ## Project renderings 14 | 15 | **System initialization login interface** 16 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/f48f7936b3ff4a5496e188c13c64dc36.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQklHQk9TU3lpZmk=,size_20,color_FFFFFF,t_70,g_se,x_16) 17 | **Main interface display picture:** 18 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/c2d5b4d272ad4a7eac5ae8107dfb56e9.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQklHQk9TU3lpZmk=,size_20,color_FFFFFF,t_70,g_se,x_16) 19 | **Sign in function display ** 20 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/61685dd4b9184bdb8c33379f0e52833d.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQklHQk9TU3lpZmk=,size_20,color_FFFFFF,t_70,g_se,x_16) 21 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/0a2258078cc84c16b941cc4220a7aca0.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQklHQk9TU3lpZmk=,size_20,color_FFFFFF,t_70,g_se,x_16) 22 | **Sign out function display** 23 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/4cc3fd36c2584623b277994dbe1c9b1e.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQklHQk9TU3lpZmk=,size_20,color_FFFFFF,t_70,g_se,x_16) 24 | **Background check-in data recording** 25 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/f752bbde1e7b4a4bba2090f38d46ae2b.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQklHQk9TU3lpZmk=,size_20,color_FFFFFF,t_70,g_se,x_16) 26 | **Check in/check out** 27 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/eadfab52443c4c29b1829a653a41887f.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQklHQk9TU3lpZmk=,size_20,color_FFFFFF,t_70,g_se,x_16) 28 | 29 | # The environment required for the project 30 | 31 | **OpenCV-Python 4.5.5.64** 32 | **face_recognition 1.30 33 | face_recognition_model 0.3.0 34 | dlib 19.23.1** 35 | 36 | 37 | **PyQt5 5.15.4 38 | pyqt5-plugins 5.15.4.2.2 39 | PyQt5-Qt5 5.15.2 40 | PyQt5-sip 12.10.1 41 | pyqt5-tools 5.15.4.3.2** 42 | 43 | ``` 44 | **PythonVersion 3.9.12** 45 | ``` 46 | ### QT-designer 47 | 48 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/d7e826c9112f4f27b462f3a1b3e3b891.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQklHQk9TU3lpZmk=,size_20,color_FFFFFF,t_70,g_se,x_16) 49 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/e9bef28e2e0241828bcd633769542490.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQklHQk9TU3lpZmk=,size_20,color_FFFFFF,t_70,g_se,x_16) 50 | 51 | 52 | # Code 53 | 54 | ## CoreCode 55 | 56 | **MainWindow.py** 57 | *UI File:* 58 | 59 | ```python 60 | class Ui_Dialog(QDialog): 61 | def __init__(self): 62 | super(Ui_Dialog, self).__init__() 63 | loadUi("mainwindow.ui", self) #加载QTUI文件 64 | 65 | self.runButton.clicked.connect(self.runSlot) 66 | 67 | self._new_window = None 68 | self.Videocapture_ = None 69 | ``` 70 | 71 | *Camera:* 72 | 73 | ```python 74 | def refreshAll(self): 75 | print("当前调用人俩检测摄像头编号(0为笔记本内置摄像头,1为USB外置摄像头):") 76 | self.Videocapture_ = "0" 77 | ``` 78 | 79 | **OutWindow.py** 80 | *request Time* 81 | 82 | ```python 83 | class Ui_OutputDialog(QDialog): 84 | def __init__(self): 85 | super(Ui_OutputDialog, self).__init__() 86 | loadUi("./outputwindow.ui", self) #加载输出窗体UI 87 | 88 | #datetime 时间模块 89 | now = QDate.currentDate() 90 | current_date = now.toString('ddd dd MMMM yyyy') #时间格式 91 | current_time = datetime.datetime.now().strftime("%I:%M %p") 92 | self.Date_Label.setText(current_date) 93 | self.Time_Label.setText(current_time) 94 | 95 | self.image = None 96 | ``` 97 | 98 | *Check in time* 99 | 100 | ```python 101 | def ElapseList(self,name): 102 | with open('Attendance.csv', "r") as csv_file: 103 | csv_reader = csv.reader(csv_file, delimiter=',') 104 | line_count = 2 105 | 106 | Time1 = datetime.datetime.now() 107 | Time2 = datetime.datetime.now() 108 | for row in csv_reader: 109 | for field in row: 110 | if field in row: 111 | if field == 'Clock In': 112 | if row[0] == name: 113 | Time1 = (datetime.datetime.strptime(row[1], '%y/%m/%d %H:%M:%S')) 114 | self.TimeList1.append(Time1) 115 | if field == 'Clock Out': 116 | if row[0] == name: 117 | Time2 = (datetime.datetime.strptime(row[1], '%y/%m/%d %H:%M:%S')) 118 | self.TimeList2.append(Time2) 119 | ``` 120 | 121 | *FaceRecognition* 122 | 123 | ```python 124 | # 人脸识别部分 125 | faces_cur_frame = face_recognition.face_locations(frame) 126 | encodes_cur_frame = face_recognition.face_encodings(frame, faces_cur_frame) 127 | 128 | for encodeFace, faceLoc in zip(encodes_cur_frame, faces_cur_frame): 129 | match = face_recognition.compare_faces(encode_list_known, encodeFace, tolerance=0.50) 130 | face_dis = face_recognition.face_distance(encode_list_known, encodeFace) 131 | name = "unknown" #未知人脸识别为unknown 132 | best_match_index = np.argmin(face_dis) 133 | if match[best_match_index]: 134 | name = class_names[best_match_index].upper() 135 | y1, x2, y2, x1 = faceLoc 136 | cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2) 137 | cv2.rectangle(frame, (x1, y2 - 20), (x2, y2), (0, 255, 0), cv2.FILLED) 138 | cv2.putText(frame, name, (x1 + 6, y2 - 6), cv2.FONT_HERSHEY_COMPLEX, 0.5, (255, 255, 255), 1) 139 | mark_attendance(name) 140 | 141 | return frame 142 | ``` 143 | 144 | *CheckData* 145 | 146 | ```python 147 | # csv表格保存数据 148 | def mark_attendance(name): 149 | """ 150 | :param name: 人脸识别部分 151 | :return: 152 | """ 153 | if self.ClockInButton.isChecked(): 154 | self.ClockInButton.setEnabled(False) 155 | with open('Attendance.csv', 'a') as f: 156 | if (name != 'unknown'): #签到判断:是否为已经识别人脸 157 | buttonReply = QMessageBox.question(self, '欢迎 ' + name, '开始签到' , 158 | QMessageBox.Yes | QMessageBox.No, QMessageBox.No) 159 | if buttonReply == QMessageBox.Yes: 160 | 161 | date_time_string = datetime.datetime.now().strftime("%y/%m/%d %H:%M:%S") 162 | f.writelines(f'\n{name},{date_time_string},Clock In') 163 | self.ClockInButton.setChecked(False) 164 | 165 | self.NameLabel.setText(name) 166 | self.StatusLabel.setText('签到') 167 | self.HoursLabel.setText('开始签到计时中') 168 | self.MinLabel.setText('') 169 | 170 | self.Time1 = datetime.datetime.now() 171 | self.ClockInButton.setEnabled(True) 172 | else: 173 | print('签到操作失败') 174 | self.ClockInButton.setEnabled(True) 175 | elif self.ClockOutButton.isChecked(): 176 | self.ClockOutButton.setEnabled(False) 177 | with open('Attendance.csv', 'a') as f: 178 | if (name != 'unknown'): 179 | buttonReply = QMessageBox.question(self, '嗨呀 ' + name, '确认签退?', 180 | QMessageBox.Yes | QMessageBox.No, QMessageBox.No) 181 | if buttonReply == QMessageBox.Yes: 182 | date_time_string = datetime.datetime.now().strftime("%y/%m/%d %H:%M:%S") 183 | f.writelines(f'\n{name},{date_time_string},Clock Out') 184 | self.ClockOutButton.setChecked(False) 185 | 186 | self.NameLabel.setText(name) 187 | self.StatusLabel.setText('签退') 188 | self.Time2 = datetime.datetime.now() 189 | 190 | self.ElapseList(name) 191 | self.TimeList2.append(datetime.datetime.now()) 192 | CheckInTime = self.TimeList1[-1] 193 | CheckOutTime = self.TimeList2[-1] 194 | self.ElapseHours = (CheckOutTime - CheckInTime) 195 | self.MinLabel.setText("{:.0f}".format(abs(self.ElapseHours.total_seconds() / 60)%60) + 'm') 196 | self.HoursLabel.setText("{:.0f}".format(abs(self.ElapseHours.total_seconds() / 60**2)) + 'h') 197 | self.ClockOutButton.setEnabled(True) 198 | else: 199 | print('签退操作失败') 200 | self.ClockOutButton.setEnabled(True) 201 | ``` 202 | 203 | ### Project directory structure 204 | 205 | ![在这里插入图片描述](https://img-blog.csdnimg.cn/985c4a761fce457cb773e87fde0903ee.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQklHQk9TU3lpZmk=,size_8,color_FFFFFF,t_70,g_se,x_16) 206 | 207 | # At Last 208 | 209 | ***Because there is no face training model in this system, the system misrecognition rate is high and the security is low 210 | The system optimization is poor, the camera captures a low number of frames (8-9), the background occupies a high, and the CPU utilization is high 211 | Data is saved in CSV format, which has low security*** 212 | 213 | --------------------------------------------------------------------------------