├── .idea
├── .gitignore
├── Face-Recognition-Class-Attendance-System.iml
├── aws.xml
├── inspectionProfiles
│ ├── Project_Default.xml
│ └── profiles_settings.xml
├── misc.xml
├── modules.xml
└── vcs.xml
├── README.md
├── __pycache__
└── execute.cpython-38.pyc
├── emo
├── face_test.py
├── intel
│ └── emotions-recognition-retail-0003
│ │ ├── FP16-INT8
│ │ ├── emotions-recognition-retail-0003.bin
│ │ └── emotions-recognition-retail-0003.xml
│ │ ├── FP16
│ │ ├── emotions-recognition-retail-0003.bin
│ │ └── emotions-recognition-retail-0003.xml
│ │ └── FP32
│ │ ├── emotions-recognition-retail-0003.bin
│ │ └── emotions-recognition-retail-0003.xml
└── weights
│ ├── opencv_face_detector.pbtxt
│ └── opencv_face_detector_uint8.pb
├── environment.yaml
├── execute.py
├── images
├── deep_face_recognition_process.png
├── detail_window.png
├── face_alignment.png
├── face_detection.png
├── facenet_architecture.png
├── info_window.png
├── main_window.png
├── mysql_table1.png
├── mysql_table2.png
├── mysql_table3.png
└── mysql_table4.png
├── logo_imgs
├── bkg1.png
├── bkg2.png
├── brain.png
├── fcb_logo.jpg
├── fcb_logo.png
├── info.png
├── info_icon.jpg
└── warn_icon.png
├── model_face_detection
├── deploy.prototxt
├── haarcascade_frontalface_default.xml
├── model_architecture_visualization.py
├── res10_300x300_ssd_iter_140000.caffemodel
├── resnet-ssd-deploy.png
└── resnet-ssd-deploy2.png
├── model_facenet
├── openface_nn4.small2.v1.png
└── openface_nn4.small2.v1.t7
├── mysql_table
└── facerecognition.sql
├── requirements.txt
├── saved_weights
├── embeddings.pickle
├── le.pickle
└── recognizer.pickle
├── ui
├── RandomCheckUI.py
├── RandomCheckUI.ui
├── __pycache__
│ ├── RandomCheckUI.cpython-38.pyc
│ ├── detail.cpython-38.pyc
│ ├── infoUI.cpython-38.pyc
│ ├── main.cpython-36.pyc
│ ├── main.cpython-38.pyc
│ └── mainwindow.cpython-38.pyc
├── detail.py
├── infoUI.py
├── infoUI.ui
├── mainwindow.py
└── mainwindow.ui
└── utils2
├── Detaillog.py
├── GeneratorModel.py
├── GlobalVar.py
├── InfoDialog.py
├── RandomCheck.py
├── __pycache__
├── Detaillog.cpython-38.pyc
├── GeneratorModel.cpython-38.pyc
├── GlobalVar.cpython-38.pyc
├── InfoDialog.cpython-38.pyc
├── InfoUI.cpython-38.pyc
├── MainUI.cpython-38.pyc
└── RandomCheck.cpython-38.pyc
└── microsoft.ttf
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/Face-Recognition-Class-Attendance-System.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/aws.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Student-behavior-system
2 |
3 | 学生行为分析系统
4 |
5 | ---
6 |
7 | > Contributor : Memory555
8 | >
9 | > Reference : https://github.com/datamonday/Face-Recognition-Class-Attendance-System
10 | >
11 | > Github Repo :https://github.com/Memory555/Student-behavior-system
12 | >
13 | > Project Post : 2023.06.14
14 |
15 |
16 | # 1. 项目简介及声明
17 |
18 | **🐱👓本项目为大三智慧学习与教育课程设计,非完全原创代码,参考借鉴Github见上方Reference链接**。
19 |
20 | 🎠本项目使用Python3.8开发。主要包括四部分:
21 | - 前端界面设计:使用Qt Designer(QT5)设计主界面,PyQt5编写界面控件的槽函数。
22 | - 人脸检测算法:使用OpenCV提供的ResNet-SSD预训练模型
23 | - 人脸识别算法:使用OpenFace开源的基于Inception的FaceNet预训练模型。
24 | - 表情识别算法:使用OpenVINO模型库中的emotions-recognition-retail-0003人脸表情模型。
25 | - 信息管理:使用PyMySQL实现学生信息,考勤信息的集中统一化管理。
26 |
27 | ---
28 |
29 | # 2. 环境配置🎡
30 |
31 | ## 2.1 Anaconda 创建虚拟环境
32 |
33 | 打开官方地址并下载对应版本:
34 |
35 | https://www.anaconda.com/products/individual#Downloads
36 |
37 | 如果追求轻量化,使用miniconda也可以,只不过没有navigator。
38 |
39 | 安装完成后,打开 Anaconda Prompt,并按以下步骤输入:
40 |
41 | 1. 创建虚拟环境 `fr` ,设置Python版本为 3.8.0
42 |
43 | ```shell
44 | conda create -n fr python==3.8
45 | ```
46 |
47 | 2. 激活虚拟环境
48 |
49 | ```shell
50 | conda activate fr
51 | ```
52 |
53 | ---
54 |
55 | ## 2.2 安装所需要的包
56 |
57 | 在新开的命令行,激活虚拟环境后,按如下步骤操作。
58 |
59 | 方式一:requirements.txt 安装
60 |
61 | 该文件是我在本地新建的测试通过的环境中所使用的的包,可以直接安装,避免了一个一个包安装的繁琐步骤。打开命令行并切换到该文件所在的根目录,输入如下命令:
62 |
63 | ```shell
64 | pip install -r requirements.txt
65 | ```
66 | 注:本地环境生成requirements.txt的命令:`pip freeze > requirements.txt`
67 |
68 | ---
69 |
70 | 方式二:environment.yaml 安装
71 |
72 | 这是我在本地的conda虚拟环境,实现功能类似 requirements.txt,如果安装了anaconda的话,可以直接安装。需要注意的是该方式是直接创建一个虚拟环境,如果想在已有的环境中进行配置,则只需要按方式一即可。
73 |
74 | ```shell
75 | conda env create -f environment.yaml
76 | ```
77 |
78 | 注:导出本地的conda环境命令:`conda env export > d:/environment.yaml`
79 |
80 | ---
81 |
82 | ## 2.3 安装 dlib
83 | - 官网:http://dlib.net/
84 | - github:https://github.com/davisking/dlib
85 |
86 | 注意:需要先安装Visual Studio C++的Community版本或者专业版和企业版都可以,否则报错!只安装 installer 无效,仍会报错!如果之前没有安装VS内核,只安装了 installer,打开控制面板,右击修改安装,重启之后生效。
87 |
88 | 确认已经安装了VS,打开命令行,激活虚拟环境,直接命令安装即可:
89 |
90 | ```shell
91 | pip install dlib
92 | ```
93 |
94 | 安装比较耗时,大概几分钟.
95 |
96 |
97 | ---
98 |
99 | # 3. 系统前端设计🤖
100 |
101 | 使用 Qt Designer 设计前端界面。
102 |
103 | ## 3.1 主界面
104 |
105 | 
106 |
107 | ---
108 |
109 | ## 3.2 信息采集界面
110 |
111 | 
112 |
113 | ---
114 |
115 | ## 3.3 行为分析详情界面
116 |
117 | 
118 |
119 | ---
120 |
121 | # 4. 系统功能介绍🛵
122 |
123 | ## 4.1 信息采集功能
124 |
125 | 通过信息采集界面实现,针对学生的人脸图片建库。
126 |
127 | 可以手动添加,可以自动采集人脸图像。注意:从自动转为手动方式时,画面会不显示,但不影响采集!
128 |
129 | ## 4.2 人脸识别简介
130 |
131 | 深度学习人脸识别流程可以总结如下(图自论文:I. Masi, Y. Wu, T. Hassner and P. Natarajan, "**Deep Face Recognition: A Survey**," 2018 31st SIBGRAPI Conference on Graphics, Patterns and Images (SIBGRAPI), 2018, pp. 471-478, doi: 10.1109/SIBGRAPI.2018.00067.):
132 |
133 | 
134 |
135 | 总的来说应用人脸识别分为四步:(1)人脸检测,对输入的图片应用人脸检测算法(本项目中使用OpenCV提供的训练好的ResNet-SSD模型)找出人脸的坐标,过程如下图所示:
136 |
137 | 
138 |
139 | (2)应用人脸校正算法,对人脸进行校正,将图像进行保持图片相对平行的基本图像变换,例如旋转和缩放 (仿射变换, affine transformations),使得眼睛和嘴巴尽可能靠近中心,即目的是将非正视角的人脸校正到使两眼处于同一水平位置。如下图所示:
140 |
141 | 
142 |
143 | (3)使用人脸识别算法(本文中使用Google在2015年提出的FaceNet,论文 **FaceNet: A Unified Embedding for Face Recognition and Clustering**)对纯人脸图像进行特征提取,FaceNet是将人脸编码为128维的向量,又称为嵌入(embedding),这个属于在自然语言处理领域非常常用。下图是FaceNet的论文中描述的网络架构:
144 |
145 | 
146 |
147 | (4)如果是训练的话,上一步已经结束了,但是要应用人脸识别算法,还需要在下游任务上实现分类。故本项目中使用支持向量机(Support Vector Machine,SVM)实现对各人脸128维向量的分类任务。 **注意:SVM本质上为二分类器,请保证人脸数据库中至少包含两个人!否则可能导致闪退!**
148 | 注:SVM使用scikit-learn提供的[SVC API](https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html)实现。
149 |
150 | - 一个使用SVM进行人脸识别的官方例程:[Faces recognition example using eigenfaces and SVMs](https://scikit-learn.org/stable/auto_examples/applications/plot_face_recognition.html#sphx-glr-auto-examples-applications-plot-face-recognition-py)
151 |
152 | ---
153 |
154 | ## 4.3 表情识别简介
155 |
156 | 表情识别使用OpenVINO模型库中的emotions-recognition-retail-0003人脸表情模型实现。该模型基于深度学习技术,使用卷积神经网络(CNN)架构进行训练,可以识别出七种不同的表情,包括生气、厌恶、恐惧、开心、平静、伤心和惊讶。
157 | 该模型使用的数据集是FER2013(Faces Emotion Recognition),包含35,887张48x48像素的灰度图像,其中28,709张用于训练,3,589张用于验证,3,589张用于测试。该数据集中的每个图像都被标记为七种不同的情感之一。
158 | emotions-recognition-retail-0003模型的输入是一张人脸图像,输出是一个大小为7的向量,每个元素代表一个表情。模型的精度在FER2013测试集上达到了66.49%的准确率,可以在不同的嵌入式设备上进行加速和部署。
159 | 该模型适用于多个领域的应用,如虚拟现实、智能医疗、安防监控、智能客服等,可以帮助人们更好地理解和识别人类情感。
160 |
161 | 此外,OpenVINO是Inter开发的一套深度学习工具库,用于快速部署应用和解决方案。
162 | 当我们应用Pytorch、Tensorflow和PaddlePaddle训练好模型之后,就面临了模型部署上线问题。OpenVINO是解决这一问题的优秀工具。
163 | 更多内容可查看官方文档介绍:[OpenVINO](https://docs.openvino.ai/cn/2022.1/documentation.html)
164 |
165 | ## 4.4 查询考勤信息
166 |
167 | 通过主界面的未到按键,可以查看当前未到学生情况,会在主界面左侧文本框中显示包含迟到和旷课的学生,点击导出按键可见结果导出。
168 |
169 | ## 4.5 查询未采集学生信息
170 |
171 | 通过主界面的未采集人员按键,实现获知尚未录入人脸信息的学生。
172 |
173 | ## 4.6 补签及请假登记
174 |
175 | 通过主界面的补签和请假按键,输入学号,实现补签和请假登记,并写入数据库。
176 |
177 | ---
178 |
179 | # 5. 数据库存取信息🥗
180 |
181 | ## 5.1 数据库可视化工具 Navicat
182 |
183 | 使用该软件是为了方便管理维护信息,也可使用其他数据管理软件。
184 |
185 | ---
186 |
187 | ## 5.3 MySQL表格及字段说明
188 |
189 | 其主界面如下:
190 |
191 | 学生信息表:
192 | 
193 |
194 | 学生班级表:
195 | 
196 |
197 | 考勤表:
198 | 
199 |
200 | 情绪分析详情表:
201 | 
202 |
203 |
204 |
205 |
206 | ---
207 |
208 | ## 5.4 PyMySQL 使用
209 |
210 | > Github:https://github.com/PyMySQL
211 |
212 | 项目中只使用了简单的写入、查询等几个常用命令,即使没有数据库基础上手也比较容易。例如:
213 |
214 | ```python
215 | # 连接数据库
216 | db = pymysql.connect(host="localhost", user="root", password="mysql105", database="facerecognition")
217 |
218 | # 查询语句,实现通过ID关键字检索个人信息的功能
219 | sql = "SELECT * FROM STUDENTS WHERE ID = {}".format(self.input_ID)
220 | ```
221 |
222 | ---
223 |
224 | # 6. 源码介绍及使用🍨
225 |
226 | ---
227 | ## 6.2 关键文件说明
228 |
229 | - `model_face_detection/res10_300x300_ssd_iter_140000.caffemodel`:OpenCV提供的训练好的人脸检测ResNet-SSD模型权重。
230 | - `model_facenet/openface_nn4.small2.v1.t7`:OpenFace提供的基于Inception的训练好的FaceNet模型权重。
231 | - `emo/intel/emotions-recognition-retail-0003/FP32:`
232 | - `mysql_table/facerecognition.sql`:mysql表格。
233 |
234 | ---
235 |
236 | ## 6.3 需要修改源码部分
237 |
238 | 1. 安装 **msqlservice** 然后修改 `execute.py`文件中的数据库连接代码。比如 `db = pymysql.connect("localhost", "root", "mysql105", "facerecognition")`。这首先需要在 navicat中创建数据库。
239 | 2. 如果不是通过本系统的信息采集功能采集的人脸照片,请将采集的人脸照片放到 `face_dataset/XX` 路径下,其中`XX`是学号(唯一索引),如果是通过系统采集的,则会自动存放在该路径下,不需要修改。
240 | 3. **注意:考虑到班级成员信息存储在数据库中,因此本地的信息采集界面不支持人脸的增删,只支持修改。所以当在本地采集了很多人脸并训练完模型之后,一定要确保采集的人脸ID已经存在于数据库之中,否则可能导致闪退!**
241 |
242 | ---
243 |
244 | ## 6.4 使用步骤
245 |
246 | 1. navicat创建数据库,打开数据库录入学生信息和班级信息;
247 | 2. 修改源码中的数据库连接部分,连接到创建的数据库;
248 | 3. 修改文件`GlobalVar.py` 中的路径;
249 | 4. 采集人脸照片,点击界面中的信息采集,在子窗口操作即可,注意保证本地文件夹的名称和数据库中的ID对应,每个ID的人脸在100--300张较好;
250 | 5. 回到主界面,点击界面中的模型训练,以训练人脸识别模型;
251 | 6. 开始考勤和行为分析:打开相机 --> 开始分析;
252 | 7. 查看每个学生表情情况:分析详情;
253 |
254 | ---
255 |
--------------------------------------------------------------------------------
/__pycache__/execute.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/__pycache__/execute.cpython-38.pyc
--------------------------------------------------------------------------------
/emo/face_test.py:
--------------------------------------------------------------------------------
1 | import cv2 as cv
2 | import numpy as np
3 | from openvino.inference_engine import IECore
4 |
5 | # 人脸检测模型
6 | weight_pb = "E:/soft/smart/Face-Recognition-Class-Attendance-System-master/emo/weights/opencv_face_detector_uint8.pb"
7 | config_text = "E:/soft/smart/Face-Recognition-Class-Attendance-System-master/emo/weights/opencv_face_detector.pbtxt"
8 |
9 | # 加载表情识别模型并设置输入与输出
10 | model_xml = "E:/soft/smart/Face-Recognition-Class-Attendance-System-master/emo/intel/emotions-recognition-retail-0003/FP32/emotions-recognition-retail-0003.xml"
11 | model_bin = "E:/soft/smart/Face-Recognition-Class-Attendance-System-master/emo/intel/emotions-recognition-retail-0003/FP32/emotions-recognition-retail-0003.bin"
12 |
13 | labels = ['neutral', 'happy', 'sad', 'surprise', 'anger']
14 |
15 | ie = IECore()
16 | emotion_net = ie.read_network(model=model_xml, weights=model_bin)
17 |
18 | input_blob = next(iter(emotion_net.input_info))
19 |
20 | exec_net = ie.load_network(network=emotion_net, device_name="CPU", num_requests=2)
21 |
22 | # 读取人脸检测模型
23 | net = cv.dnn.readNetFromTensorflow(weight_pb, config=config_text)
24 |
25 | # 人脸检测&表情识别
26 | def emotion_detect(frame):
27 | h, w, c = frame.shape
28 | blobImage = cv.dnn.blobFromImage(frame, 1.0, (300, 300), (104.0, 177.0, 123.0), False, False)
29 | net.setInput(blobImage)
30 | cvOut = net.forward()
31 |
32 | # 绘制检测矩形
33 | for detection in cvOut[0, 0, :, :]:
34 | score = float(detection[2])
35 | if score > 0.5:
36 | left = detection[3] * w
37 | top = detection[4] * h
38 | right = detection[5] * w
39 | bottom = detection[6] * h
40 |
41 | # roi 和 关键点检测
42 | y1 = np.int32(top) if np.int32(top) > 0 else 0
43 | y2 = np.int32(bottom) if np.int32(bottom) < h else h - 1
44 | x1 = np.int32(left) if np.int32(left) > 0 else 0
45 | x2 = np.int32(right) if np.int32(right) < w else w - 1
46 | roi = frame[y1:y2, x1:x2, :]
47 | image = cv.resize(roi, (64, 64))
48 | image = image.transpose((2, 0, 1)) # Change data layout from HWC to CHW
49 | res = exec_net.infer(inputs={input_blob: [image]})
50 | prob_emotion = res['prob_emotion']
51 | probs = np.reshape(prob_emotion, 5)
52 | txt = labels[np.argmax(probs)]
53 | cv.putText(frame, txt, (np.int32(left), np.int32(top)), cv.FONT_HERSHEY_SIMPLEX, 1.0, (255, 0, 0), 2)
54 | cv.rectangle(frame, (np.int32(left), np.int32(top)),
55 | (np.int32(right), np.int32(bottom)), (0, 0, 255), 2, 8, 0)
56 | print(txt)
57 |
58 |
59 | if __name__ == "__main__":
60 |
61 | # 调用摄像头
62 | capture = cv.VideoCapture(0)
63 | # 读取视频
64 | # path = "./dataset/video/smile.mp4"
65 | # capture = cv.VideoCapture(path)
66 |
67 | while True:
68 | ret, frame = capture.read()
69 | if ret is not True:
70 | break
71 | emotion_detect(frame)
72 | cv.imshow("emotion-detect-demo", frame)
73 | # 按Q 退出 waitKey控制播放速度
74 | if cv.waitKey(1) & 0xFF == ord('q'):
75 | break
76 |
--------------------------------------------------------------------------------
/emo/intel/emotions-recognition-retail-0003/FP16-INT8/emotions-recognition-retail-0003.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/emo/intel/emotions-recognition-retail-0003/FP16-INT8/emotions-recognition-retail-0003.bin
--------------------------------------------------------------------------------
/emo/intel/emotions-recognition-retail-0003/FP16/emotions-recognition-retail-0003.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/emo/intel/emotions-recognition-retail-0003/FP16/emotions-recognition-retail-0003.bin
--------------------------------------------------------------------------------
/emo/intel/emotions-recognition-retail-0003/FP32/emotions-recognition-retail-0003.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/emo/intel/emotions-recognition-retail-0003/FP32/emotions-recognition-retail-0003.bin
--------------------------------------------------------------------------------
/emo/weights/opencv_face_detector_uint8.pb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/emo/weights/opencv_face_detector_uint8.pb
--------------------------------------------------------------------------------
/environment.yaml:
--------------------------------------------------------------------------------
1 | name: fr
2 | channels:
3 | - https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/msys2
4 | - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main
5 | - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
6 | - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
7 | - https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/msys2/
8 | - https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
9 | - defaults
10 | dependencies:
11 | - argon2-cffi=20.1.0=py38h2bbff1b_1
12 | - async_generator=1.10=pyhd3eb1b0_0
13 | - attrs=21.2.0=pyhd3eb1b0_0
14 | - backcall=0.2.0=pyhd3eb1b0_0
15 | - blas=1.0=mkl
16 | - bleach=3.3.0=pyhd3eb1b0_0
17 | - ca-certificates=2021.4.13=haa95532_1
18 | - certifi=2020.12.5=py38haa95532_0
19 | - cffi=1.14.5=py38hcd4344a_0
20 | - colorama=0.4.4=pyhd3eb1b0_0
21 | - cycler=0.10.0=py38_0
22 | - decorator=5.0.9=pyhd3eb1b0_0
23 | - defusedxml=0.7.1=pyhd3eb1b0_0
24 | - entrypoints=0.3=py38_0
25 | - freetype=2.10.4=hd328e21_0
26 | - icc_rt=2019.0.0=h0cc432a_1
27 | - icu=58.2=ha925a31_3
28 | - importlib-metadata=3.10.0=py38haa95532_0
29 | - importlib_metadata=3.10.0=hd3eb1b0_0
30 | - intel-openmp=2021.2.0=haa95532_616
31 | - ipykernel=5.3.4=py38h5ca1d4c_0
32 | - ipython=7.23.1=py38h43734a8_0
33 | - ipython_genutils=0.2.0=pyhd3eb1b0_1
34 | - ipywidgets=7.6.3=pyhd3eb1b0_1
35 | - jedi=0.18.0=py38haa95532_1
36 | - jinja2=3.0.0=pyhd3eb1b0_0
37 | - joblib=1.0.1=pyhd3eb1b0_0
38 | - jpeg=9b=hb83a4c4_2
39 | - jsonschema=3.2.0=py_2
40 | - jupyter=1.0.0=py38_7
41 | - jupyter_client=6.1.12=pyhd3eb1b0_0
42 | - jupyter_console=6.4.0=pyhd3eb1b0_0
43 | - jupyter_core=4.7.1=py38haa95532_0
44 | - jupyterlab_pygments=0.1.2=py_0
45 | - jupyterlab_widgets=1.0.0=pyhd3eb1b0_1
46 | - kiwisolver=1.3.1=py38hd77b12b_0
47 | - libpng=1.6.37=h2a8f88b_0
48 | - libsodium=1.0.18=h62dcd97_0
49 | - libtiff=4.2.0=hd0e1b90_0
50 | - lz4-c=1.9.3=h2bbff1b_0
51 | - m2w64-gcc-libgfortran=5.3.0=6
52 | - m2w64-gcc-libs=5.3.0=7
53 | - m2w64-gcc-libs-core=5.3.0=7
54 | - m2w64-gmp=6.1.0=2
55 | - m2w64-libwinpthread-git=5.0.0.4634.697f757=2
56 | - markupsafe=2.0.1=py38h2bbff1b_0
57 | - matplotlib=3.3.4=py38haa95532_0
58 | - matplotlib-base=3.3.4=py38h49ac443_0
59 | - matplotlib-inline=0.1.2=pyhd8ed1ab_2
60 | - mistune=0.8.4=py38he774522_1000
61 | - mkl=2021.2.0=haa95532_296
62 | - mkl-service=2.3.0=py38h2bbff1b_1
63 | - mkl_fft=1.3.0=py38h277e83a_2
64 | - mkl_random=1.2.1=py38hf11a4ad_2
65 | - msys2-conda-epoch=20160418=1
66 | - nbclient=0.5.3=pyhd3eb1b0_0
67 | - nbconvert=6.0.7=py38_0
68 | - nbformat=5.1.3=pyhd3eb1b0_0
69 | - nest-asyncio=1.5.1=pyhd3eb1b0_0
70 | - notebook=6.4.0=py38haa95532_0
71 | - numpy=1.20.2=py38ha4e8547_0
72 | - numpy-base=1.20.2=py38hc2deb75_0
73 | - olefile=0.46=py_0
74 | - openssl=1.1.1k=h2bbff1b_0
75 | - packaging=20.9=pyhd3eb1b0_0
76 | - pandas=1.2.4=py38hd77b12b_0
77 | - pandoc=2.12=haa95532_0
78 | - pandocfilters=1.4.3=py38haa95532_1
79 | - parso=0.8.2=pyhd3eb1b0_0
80 | - pickleshare=0.7.5=pyhd3eb1b0_1003
81 | - pillow=8.2.0=py38h4fa10fc_0
82 | - pip=21.0.1=py38haa95532_0
83 | - prometheus_client=0.10.1=pyhd3eb1b0_0
84 | - prompt-toolkit=3.0.17=pyh06a4308_0
85 | - prompt_toolkit=3.0.17=hd3eb1b0_0
86 | - pycparser=2.20=py_2
87 | - pygments=2.9.0=pyhd3eb1b0_0
88 | - pyparsing=2.4.7=pyhd3eb1b0_0
89 | - pyqt=5.9.2=py38ha925a31_4
90 | - pyrsistent=0.17.3=py38he774522_0
91 | - python=3.8.0=hff0d562_2
92 | - python-dateutil=2.8.1=pyhd3eb1b0_0
93 | - python_abi=3.8=1_cp38
94 | - pytz=2021.1=pyhd3eb1b0_0
95 | - pywin32=227=py38he774522_1
96 | - pywinpty=0.5.7=py38_0
97 | - pyzmq=20.0.0=py38hd77b12b_1
98 | - qt=5.9.7=vc14h73c81de_0
99 | - qtconsole=5.0.3=pyhd3eb1b0_0
100 | - qtpy=1.9.0=py_0
101 | - scikit-learn=0.24.2=py38hf11a4ad_0
102 | - scipy=1.6.2=py38h66253e8_1
103 | - send2trash=1.5.0=pyhd3eb1b0_1
104 | - setuptools=52.0.0=py38haa95532_0
105 | - sip=4.19.13=py38ha925a31_0
106 | - six=1.15.0=py38haa95532_0
107 | - sqlite=3.35.4=h2bbff1b_0
108 | - terminado=0.9.4=py38haa95532_0
109 | - testpath=0.4.4=pyhd3eb1b0_0
110 | - threadpoolctl=2.1.0=pyh5ca1d4c_0
111 | - tk=8.6.10=he774522_0
112 | - tornado=6.1=py38h2bbff1b_0
113 | - traitlets=5.0.5=pyhd3eb1b0_0
114 | - vc=14.2=h21ff451_1
115 | - vs2015_runtime=14.27.29016=h5e58377_2
116 | - wcwidth=0.2.5=py_0
117 | - webencodings=0.5.1=py38_1
118 | - wheel=0.36.2=pyhd3eb1b0_0
119 | - widgetsnbextension=3.5.1=py38_0
120 | - wincertstore=0.2=py38_0
121 | - winpty=0.4.3=4
122 | - xz=5.2.5=h62dcd97_0
123 | - zeromq=4.3.3=ha925a31_3
124 | - zipp=3.4.1=pyhd3eb1b0_0
125 | - zlib=1.2.11=h62dcd97_4
126 | - zstd=1.4.5=h04227a9_0
127 | - pip:
128 | - blurhash==1.1.4
129 | - boost==0.1
130 | - chardet==4.0.0
131 | - cmake==3.20.2
132 | - dlib==19.22.0
133 | - et-xmlfile==1.1.0
134 | - freetype-py==2.2.0
135 | - greenlet==1.1.0
136 | - idna==2.10
137 | - imutils==0.5.4
138 | - mastodon-py==1.5.1
139 | - opencv-contrib-python==4.5.2.52
140 | - opencv-python==4.5.2.52
141 | - openpyxl==3.0.7
142 | - pymysql==1.0.2
143 | - pyqt5==5.15.4
144 | - pyqt5-qt5==5.15.2
145 | - pyqt5-sip==12.9.0
146 | - python-magic==0.4.22
147 | - requests==2.25.1
148 | - sqlalchemy==1.4.15
149 | - urllib3==1.26.4
150 | - xlrd==2.0.1
151 | prefix: D:\anaconda\envs\fr
152 |
--------------------------------------------------------------------------------
/execute.py:
--------------------------------------------------------------------------------
1 | import os
2 | import pickle
3 | import sys
4 | import threading
5 | import time
6 | from datetime import datetime
7 | from copy import deepcopy
8 | import cv2
9 | import imutils
10 | import numpy as np
11 | import openpyxl
12 | # 导入数据库操作包
13 | import pymysql
14 | # 导入界面处理包
15 | from PyQt5 import QtCore, QtGui, QtWidgets
16 | from PyQt5.QtCore import QTimer, QDateTime, QCoreApplication, QThread
17 | from PyQt5.QtGui import QImage, QIcon, QPixmap
18 | from PyQt5.QtWidgets import QApplication, QWidget, QMessageBox, QInputDialog
19 |
20 | # 使用mainwindow类重构
21 | from ui import mainwindow as MainWindowUI
22 |
23 | # 导入人脸识别检测包
24 | from utils2 import GeneratorModel
25 | # 导入信息采集槽函数类
26 | from utils2.InfoDialog import InfoDialog
27 |
28 | # 导入随机点名类
29 | from utils2.RandomCheck import RCDialog
30 | # 添加数据库连接操作
31 | from utils2.GlobalVar import connect_to_sql
32 | # 导入分析详情槽函数类
33 | from utils2.Detaillog import Detaillog
34 |
35 | from utils2.GlobalVar import FR_LOOP_NUM, statical_facedata_nums
36 |
37 | import sys
38 | import os
39 | from collections import Counter
40 |
41 | # 添加当前路径到环境变量
42 | sys.path.append(os.getcwd())
43 |
44 | from utils2.GlobalVar import num_list
45 |
46 | import numpy as np
47 | from openvino.inference_engine import IECore
48 |
49 | # 全局变量[情绪]
50 | emo_list = []
51 | # 全局变量[起始时间]
52 | start_time = []
53 | # 全局变量[姓名]
54 | student_name_list = []
55 |
56 |
57 | class MainWindow(QtWidgets.QMainWindow):
58 | # 类构造函数
59 | def __init__(self):
60 | # super()构造器方法返回父级的对象。__init__()方法是构造器的一个方法。
61 | super().__init__()
62 | # self.ui = MainUI.Ui_Form()
63 | self.line_text_info3 = []
64 | self.ui = MainWindowUI.Ui_MainWindow()
65 | self.ui.setupUi(self)
66 |
67 | # ####################### 相对路径 ######################
68 | # 初始化label显示的(黑色)背景
69 | self.bkg_pixmap = QPixmap('./logo_imgs/bkg1.png')
70 | # 设置主窗口的logo
71 | self.logo = QIcon('./logo_imgs/fcb_logo.png')
72 | # 设置提示框icon
73 | self.info_icon = QIcon('./logo_imgs/info_icon.jpg')
74 | # OpenCV深度学习人脸检测器的路径
75 | self.detector_path = "./model_face_detection"
76 | # 情绪识别模型的路径
77 | self.temper_path = "./emo/intel/emotions-recognition-retail-0003/FP32"
78 | # OpenCV深度学习面部嵌入模型的路径
79 | self.embedding_model = "./model_facenet/openface_nn4.small2.v1.t7"
80 | # 训练模型以识别面部的路径
81 | self.recognizer_path = "./saved_weights/recognizer.pickle"
82 | # 标签编码器的路径
83 | self.le_path = "./saved_weights/le.pickle"
84 |
85 | # ###################### 窗口初始化 ######################
86 | # 设置窗口名称和图标
87 | self.setWindowTitle('学生行为分析系统 v1.0')
88 | self.setWindowIcon(self.logo)
89 | # 设置单张图片背景
90 | self.ui.label_camera.setPixmap(self.bkg_pixmap)
91 | # label_time显示系统时间
92 | self.timer = QTimer(self)
93 | self.timer.timeout.connect(self.show_time_text)
94 | # 启动时间任务
95 | self.timer.start()
96 |
97 | # ###################### 摄像头初始化 ######################
98 | # 初始化摄像头,默认调用第一个摄像头
99 | # 如果要调用摄像头1,则设置为1,适用于:笔记本外接USB摄像头
100 | self.url = 0
101 | self.cap = cv2.VideoCapture()
102 |
103 | # ###################### 按键的槽函数 ######################
104 | # 设置摄像头按键连接函数
105 | self.ui.bt_open_camera.clicked.connect(self.open_camera)
106 | # 设置开始分析按键的回调函数
107 | self.ui.bt_start_check.clicked.connect(self.auto_control)
108 | # 设置“退出系统”按键事件, 按下之后退出主界面
109 | self.ui.bt_exit.clicked.connect(self.quit_window)
110 | # 设置信息采集按键连接
111 | self.ui.bt_gathering.clicked.connect(self.open_info_dialog)
112 |
113 | # 设置区分打开摄像头还是人脸识别的标识符
114 | self.switch_bt = 0
115 |
116 | # ###################### 数据库相关操作 ######################
117 | # 初始化需要记录的人名
118 | self.record_name = []
119 | # 设置更新人脸数据库的按键连接函数
120 | self.ui.bt_generator.clicked.connect(self.train_model)
121 | # 设置查询班级人数按键的连接函数
122 | # self.ui.bt_check.clicked.connect(self.check_nums)
123 | # 设置请假按键的连接函数
124 | self.ui.bt_leave.clicked.connect(self.leave_button)
125 | # 设置漏签补签按键的连接函数
126 | self.ui.bt_supplement.clicked.connect(self.supplyment_button)
127 | # 设置对输入内容的删除提示
128 | self.ui.lineEdit_leave.setClearButtonEnabled(True)
129 | self.ui.lineEdit_supplement.setClearButtonEnabled(True)
130 | # # 设置查看结果(显示未到和迟到)按键的连接函数
131 | self.ui.bt_listName1.clicked.connect(self.show_late_absence)
132 | # 导出函数
133 | self.ui.bt_output.clicked.connect(self.import_late_absence)
134 | # 核验本地人脸数据集与数据库中的ID是否一致,即验证是否有未录入数据库的情况,以及是否有未采集人脸的情况。
135 | self.ui.bt_check_variation.clicked.connect(self.check_variation_db)
136 | # self.check_time_set = '08:00:00'
137 |
138 |
139 | # 显示系统时间以及相关文字提示函数
140 | def show_time_text(self):
141 | # 设置宽度
142 | self.ui.label_time.setFixedWidth(200)
143 | # 设置显示文本格式
144 | self.ui.label_time.setStyleSheet(
145 | # "QLabel{background:white;}" 此处设置背景色
146 | "QLabel{color:rgb(0, 0, 0); font-size:14px; font-weight:bold; font-family:宋体;}"
147 | "QLabel{font-size:14px; font-weight:bold; font-family:宋体;}")
148 |
149 | current_datetime = QDateTime.currentDateTime().toString()
150 | self.ui.label_time.setText("" + current_datetime)
151 |
152 | # 显示“人脸识别分析系统”文字
153 | self.ui.label_title.setFixedWidth(400)
154 | self.ui.label_title.setStyleSheet("QLabel{font-size:26px; font-weight:bold; font-family:宋体;}")
155 | self.ui.label_title.setText("学生行为分析系统")
156 |
157 | def open_camera(self):
158 | # 判断摄像头是否打开,如果打开则为true,反之为false
159 | if not self.cap.isOpened():
160 | self.ui.label_logo.clear()
161 | # 默认打开Windows系统笔记本自带的摄像头,如果是外接USB,可将0改成1
162 | self.cap.open(self.url)
163 | self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 800)
164 | # self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 600)
165 | self.show_camera()
166 | else:
167 | self.cap.release()
168 | self.ui.label_logo.clear()
169 | self.ui.label_camera.clear()
170 | self.ui.bt_open_camera.setText(u'打开相机')
171 |
172 |
173 | # 进入情绪分析模式,通过switch_bt进行控制的函数
174 | def auto_control(self):
175 | if self.cap.isOpened():
176 | if self.switch_bt == 0:
177 | self.switch_bt = 1
178 | self.ui.bt_start_check.setText(u'退出分析')
179 | self.show_camera()
180 | elif self.switch_bt == 1:
181 | self.switch_bt = 0
182 | self.ui.bt_start_check.setText(u'开始分析')
183 | self.show_camera()
184 | else:
185 | print("[Error] The value of self.switch_bt must be zero or one!")
186 | else:
187 | QMessageBox.information(self, "Tips", "请先打开摄像头!", QMessageBox.Ok)
188 |
189 | def show_camera(self):
190 | # 如果按键按下
191 | global embedded, le, recognizer
192 | if self.switch_bt == 0:
193 | self.ui.label_logo.clear()
194 | self.ui.bt_open_camera.setText(u'关闭相机')
195 | while self.cap.isOpened():
196 | # 以BGR格式读取图像
197 | ret, self.image = self.cap.read()
198 | # 告诉QT处理来处理任何没有被处理的事件,并且将控制权返回给调用者,让代码变的没有那么卡
199 | QApplication.processEvents()
200 | # 将图像转换为RGB格式
201 | show = cv2.cvtColor(self.image, cv2.COLOR_BGR2RGB) # 这里指的是显示原图
202 | # opencv 读取图片的样式,不能通过Qlabel进行显示,需要转换为Qimage QImage(uchar * data, int width,
203 | self.showImage = QImage(show.data, show.shape[1], show.shape[0], QImage.Format_RGB888)
204 | self.ui.label_camera.setPixmap(QPixmap.fromImage(self.showImage))
205 | # 因为最后会存留一张图像在lable上,需要对lable进行清理
206 | self.ui.label_camera.clear()
207 | self.ui.bt_open_camera.setText(u'打开相机')
208 | # 设置单张图片背景
209 | self.ui.label_camera.setPixmap(self.bkg_pixmap)
210 |
211 | elif self.switch_bt == 1:
212 | self.ui.label_logo.clear()
213 | self.ui.bt_start_check.setText(u'退出分析')
214 |
215 | # 人脸检测的置信度
216 | confidence_default = 0.5
217 | # 从磁盘加载序列化面部检测器
218 | proto_path = os.path.sep.join([self.detector_path, "deploy.prototxt"])
219 | model_path = os.path.sep.join([self.detector_path, "res10_300x300_ssd_iter_140000.caffemodel"])
220 | detector = cv2.dnn.readNetFromCaffe(proto_path, model_path)
221 | # 从磁盘加载序列化面嵌入模型
222 | try:
223 | self.ui.textBrowser_log.append("[INFO] 正在加载人脸识别模型")
224 | self.ui.textBrowser_log.append("[INFO] 正在加载情绪识别模型")
225 | # 加载FaceNet人脸识别模型
226 | embedded = cv2.dnn.readNetFromTorch(self.embedding_model)
227 | except FileNotFoundError as e:
228 | self.ui.textBrowser_log.append("面部嵌入模型的路径不正确!", e)
229 |
230 | # 加载实际的人脸识别模型和标签
231 | try:
232 | recognizer = pickle.loads(open(self.recognizer_path, "rb").read())
233 | le = pickle.loads(open(self.le_path, "rb").read())
234 | except FileNotFoundError as e:
235 | self.ui.textBrowser_log.append("人脸识别模型保存路径不正确!", e)
236 |
237 | # 构造人脸id的字典,以便存储检测到每个id的人脸次数,键为人名(ID),值初始化为0,方便统计次数
238 | self.face_name_dict = dict(zip(le.classes_, len(le.classes_) * [0]))
239 | # 初始化循环次数,比如统计10帧中人脸的数量,取最大值进行考勤
240 | loop_num = 0
241 | # 循环来自视频文件流的帧
242 | while self.cap.isOpened():
243 | loop_num += 1
244 | # 从线程视频流中抓取帧
245 | ret, frame = self.cap.read()
246 | QApplication.processEvents()
247 | if ret:
248 | # 调整框架的大小以使其宽度为900像素(同时保持纵横比),然后抓取图像尺寸
249 | frame = imutils.resize(frame, width=900)
250 | (h, w) = frame.shape[:2]
251 | # 从图像构造一个blob, 缩放为 300 x 300 x 3 像素的图像,为了符合ResNet-SSD的输入尺寸
252 | # OpenCV Blog的使用可参考:https://www.pyimagesearch.com/2017/11/06/deep-learning-opencvs-blobfromimage-works/
253 | # 如果与情绪识别统一尺寸64x64,识别框对于小物体很难找到
254 | image_blob = cv2.dnn.blobFromImage(
255 | cv2.resize(frame, (300, 300)), 1.0, (300, 300),
256 | (104.0, 177.0, 123.0), swapRB=False, crop=False)
257 | # 应用OpenCV的基于深度学习的人脸检测器来定位输入图像中的人脸
258 | detector.setInput(image_blob)
259 | # 传入到ResNet-SSD以检测人脸
260 | detections = detector.forward()
261 |
262 | # 初始化一个列表,用于保存识别到的人脸学号
263 | face_names = []
264 | # 初始化一个列表,用于保存识别到的情绪
265 | emo_txt = []
266 |
267 | # 在检测结果中循环检测
268 | # 注意:这里detection为ResNet-SSD网络的输出,与阈值的设置有关,具体可以参考prototxt文件的输出层,输出shape为[1, 1, 200, 7]
269 | # 7 表示的含义分别为 [batch Id, class Id, confidence, left, top, right, bottom]
270 | # 200 表示检测到的目标数量,具体可参考SSD的论文,针对每幅图像,SSD最终会预测8000多个边界框,通过NMS过滤掉IOU小于0.45的框,剩余200个。
271 | for i in np.arange(0, detections.shape[2]):
272 | # 提取与预测相关的置信度(即概率),detections的第3维
273 | confidence = detections[0, 0, i, 2]
274 |
275 | # 用于更新相机开关按键信息
276 | if not self.cap.isOpened():
277 | self.ui.bt_open_camera.setText(u'打开相机')
278 | else:
279 | self.ui.bt_open_camera.setText(u'关闭相机')
280 |
281 |
282 | # 过滤弱检测
283 | if confidence > confidence_default:
284 | # 计算面部边界框的(x,y)坐标, 对应detections的4,5,6,7维(索引为3-7),含义分别代表:
285 | # x_left_bottom, y_left_bottom, x_right_top, y_right_top
286 | box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
287 | (startX, startY, endX, endY) = box.astype("int")
288 |
289 | roi = frame[startY:endY, startX:endX, :]
290 | image = cv2.resize(roi, (64, 64))
291 | image = image.transpose((2, 0, 1)) # Change data layout from HWC to CHW 翻转
292 |
293 | # 加载FaceNet人脸识别模型
294 | model_xml = self.temper_path + "/emotions-recognition-retail-0003.xml"
295 | model_bin = self.temper_path + "/emotions-recognition-retail-0003.bin"
296 |
297 | labels = ['neutral', 'happy', 'sad', 'surprise', 'anger']
298 |
299 | ie = IECore()
300 | emotion_net = ie.read_network(model=model_xml, weights=model_bin)
301 |
302 | input_blob = next(iter(emotion_net.input_info))
303 |
304 | exec_net = ie.load_network(network=emotion_net, device_name="CPU", num_requests=2)
305 |
306 | res = exec_net.infer(inputs={input_blob: [image]})
307 | prob_emotion = res['prob_emotion']
308 | probs = np.reshape(prob_emotion, 5)
309 | txt = labels[np.argmax(probs)] # 取概率最大的情绪
310 |
311 | # 提取面部ROI
312 | # 提取人脸的长和宽,本例中为 397 x 289
313 | face = frame[startY:endY, startX:endX]
314 | (fH, fW) = face.shape[:2]
315 |
316 | # 确保面部宽度和高度足够大,以过滤掉小人脸(较远),防止远处人员签到,以及过滤误检测
317 | if fW < 100 or fH < 100:
318 | continue
319 |
320 | # 为面部ROI构造一个blob,然后通过面部嵌入模型传递blob以获得面部的128-d量化
321 | # shape 为 (1, 3, 96, 96)
322 | face_blob = cv2.dnn.blobFromImage(face, 1.0 / 255,
323 | (96, 96), # 调整到 96 x 96 像素
324 | (0, 0, 0), swapRB=True, crop=False)
325 | # 传入到 FaceNet人脸识别模型中,将 96 x 96 x 3 的人脸图像转换为128维度的向量
326 | embedded.setInput(face_blob)
327 | # 128 维的向量,shape=(1, 128)
328 | vec = embedded.forward()
329 | # 使用SVM对人脸向量进行分类
330 | # prediction 为一向量,其shape的第一个维度为人脸库中ID的数量,返回分类概率的列表
331 | prediction = recognizer.predict_proba(vec)[0]
332 | # 取概率最大的索引
333 | j = np.argmax(prediction)
334 | # 得到预测概率
335 | probability = prediction[j]
336 | # 通过索引j找到人名(ID)转化为one-hot编码前的真实名称,也就是人脸数据集的文件夹名称,亦即数据库中ID字段的值
337 | name = le.classes_[j]
338 |
339 | # 统计各人脸被检测到的次数
340 | self.face_name_dict[name] += 1
341 |
342 | # 绘制面部的边界框以及相关的概率
343 | text = "{}: {:.2f}%".format(name, probability * 100)
344 | # 构造人脸边界框
345 | y = startY - 10 if startY - 10 > 10 else startY + 10
346 | cv2.rectangle(frame, (startX, startY), (endX, endY), (0, 0, 255), 2)
347 | frame = cv2.putText(frame, text, (startX, y), cv2.FONT_HERSHEY_SIMPLEX, 0.45, (0, 0, 255),
348 | 2)
349 | face_names.append(name)
350 | emo_txt.append(txt)
351 |
352 | results_name = ''
353 |
354 | # 执行查询
355 | try:
356 | # 打开数据库连接
357 | db, cursor = connect_to_sql()
358 | except ConnectionError as e:
359 | print("[Error] 数据库连接失败!")
360 | try:
361 | sql = "select name from students where ID = {}".format(name) # 查找姓名
362 | cursor.execute(sql)
363 | results = cursor.fetchall()
364 | finally:
365 | # 提交到数据库执行
366 | db.commit()
367 | cursor.close()
368 | db.close()
369 |
370 | for item in results:
371 | # self.student_ids.append(item[0])
372 | results_name = item[0]
373 |
374 |
375 | # 放入全局列表中
376 | if len(num_list) == 0:
377 | num_list.append(name)
378 | emo_list.append(txt)
379 | student_name_list.append(results_name)
380 | # 获取系统时间,保存到秒
381 | current_time = datetime.now()
382 | start_time.append(current_time)
383 | else: # 通过学号判断是否需要加入全局列表
384 | flag = 0
385 | num = 0
386 | for i in range(len(num_list)):
387 | if name == num_list[i]:
388 | flag = 1 # 全局列表中已经存在
389 | num = i
390 | break
391 | if flag == 0:
392 | num_list.append(name)
393 | emo_list.append(txt)
394 | student_name_list.append(results_name)
395 | current_time = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
396 | start_time.append(current_time)
397 | else:
398 | if txt != emo_list[num]: # 判断情绪是否相同
399 | emo_list[num] = txt
400 | current_time = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
401 | start_time[num] = current_time
402 |
403 | temp = []
404 | for i in range(len(num_list)):
405 | flag = 0
406 | for j in range(len(face_names)):
407 | if num_list[i] == face_names[j]:
408 | flag = 1
409 | if flag == 0:
410 | temp.append(i)
411 |
412 | res = 0
413 | for i in temp:
414 | # 已经不在识别框的学号剔除
415 | del num_list[i-res]
416 | del emo_list[i-res]
417 | del start_time[i-res]
418 | del student_name_list[i-res]
419 | res = res + 1 # 删除后全部下标前移一个
420 | for kk in range(len(num_list)):
421 | # 写入数据库中(建立新表)
422 | try:
423 | # 打开数据库连接
424 | db, cursor = connect_to_sql()
425 | except ConnectionError as e:
426 | print("[Error] 数据库连接失败!")
427 | self.line_text_info3.append((num_list[kk], student_name_list[kk], emo_list[kk], start_time[kk]))
428 | # 写入数据库
429 | try:
430 | # 如果存在数据,先删除再写入。前提是设置唯一索引字段或者主键。
431 | insert_sql3 = "replace into detail(ID, Name, Emo, starttime) values(%s, %s, %s, %s)"
432 | users3 = self.line_text_info3
433 | cursor.executemany(insert_sql3, users3)
434 | finally:
435 | # 提交到数据库执行
436 | db.commit()
437 | cursor.close()
438 | db.close()
439 |
440 | # 统计各情绪数量
441 | emo_count = Counter(emo_txt)
442 | emo_len = len(emo_txt)
443 | step1 = step2 = step3 =step4 = step5 = 0
444 | for k, v in emo_count.items():
445 | if k == 'happy':
446 | step1 = 1
447 | self.ui.label_emo1_1.setText(str(round((v/emo_len)*100,2))+'%')
448 | if k == 'sad':
449 | step2 = 2
450 | self.ui.label_emo2_2.setText(str(round((v/emo_len)*100,2))+'%')
451 | if k == 'surprise':
452 | step3 = 3
453 | self.ui.label_emo3_3.setText(str(round((v/emo_len)*100,2))+'%')
454 | if k == 'neutral':
455 | step4 = 4
456 | self.ui.label_emo6_6.setText(str(round((v/emo_len)*100,2))+'%')
457 | if k == 'anger':
458 | step5 = 5
459 | self.ui.label_emo4_4.setText(str(round((v/emo_len)*100,2))+'%')
460 | # 刷新界面
461 | if step1 == 0:
462 | self.ui.label_emo1_1.setText('0.00%')
463 | if step2 == 0:
464 | self.ui.label_emo2_2.setText('0.00%')
465 | if step3 == 0:
466 | self.ui.label_emo3_3.setText('0.00%')
467 | if step4 == 0:
468 | self.ui.label_emo6_6.setText('0.00%')
469 | if step5 == 0:
470 | self.ui.label_emo4_4.setText('0.00%')
471 |
472 | # 显示输出框架
473 | show_video = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # 这里指的是显示原图
474 | # opencv读取图片的样式,不能通过Qlabel进行显示,需要转换为Qimage。
475 | # QImage(uchar * data, int width, int height, int bytesPerLine, Format format)
476 | self.showImage = QImage(show_video.data, show_video.shape[1], show_video.shape[0],
477 | QImage.Format_RGB888)
478 | self.ui.label_camera.setPixmap(QPixmap.fromImage(self.showImage))
479 |
480 | if loop_num == FR_LOOP_NUM:
481 | # 找到10帧中检测次数最多的人脸
482 | # Python字典按照值的大小降序排列,并返回键值对元组
483 | # 第一个索引[0]表示取排序后的第一个键值对,第二个索引[0]表示取键
484 | most_id_in_dict = \
485 | sorted(self.face_name_dict.items(), key=lambda kv: (kv[1], kv[0]), reverse=True)[0][0]
486 | # 将当前帧检测到次数最多的人脸保存到self.set_name集合中
487 | self.set_name = set()
488 | self.set_name.add(most_id_in_dict)
489 | self.set_names = tuple(self.set_name)
490 |
491 | self.record_names()
492 | self.face_name_dict = dict(zip(le.classes_, len(le.classes_) * [0]))
493 | loop_num = 0
494 | else:
495 | pass
496 | else:
497 | self.cap.release()
498 |
499 | # 因为最后一张画面会显示在GUI中,此处实现清除。
500 | self.ui.label_camera.clear()
501 |
502 | def record_names(self):
503 | # 如果self.set_names是self.record_names 的子集返回ture
504 | if self.set_name.issubset(self.record_name):
505 | pass # record_name1是要写进数据库中的名字信息 set_name是从摄像头中读出人脸的tuple形式
506 | else:
507 | # 获取到self.set_name有而self.record_name无的名字
508 | self.different_name = self.set_name.difference(self.record_name)
509 | # 把self.record_name变成两个集合的并集
510 | self.record_name = self.set_name.union(self.record_name)
511 | # different_name是为了获取到之前没有捕捉到的人脸,并再次将record_name1进行更新
512 |
513 | # 将集合变成tuple,并统计人数
514 | self.write_data = tuple(self.different_name)
515 | names_num = len(self.write_data)
516 |
517 | if names_num > 0:
518 | # 将签到信息写入数据库
519 | self.line_text_info = []
520 | try:
521 | # 打开数据库连接
522 | db, cursor = connect_to_sql()
523 | except ConnectionError as e:
524 | print("[Error] 数据库连接失败!")
525 | else:
526 | # 获取系统时间,保存到秒
527 | current_time = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
528 | results2 = self.use_id_get_info(self.write_data[0])
529 |
530 | # 判断是否迟到,在这里只考虑正常情况,没有设置考勤时间的按钮
531 | self.now = datetime.now()
532 | self.attendance_state = '正常'
533 | self.line_text_info.append((results2[0], results2[1], results2[2],
534 | current_time,
535 | self.attendance_state))
536 |
537 | # 写入数据库
538 | try:
539 | # 如果存在数据,先删除再写入。前提是设置唯一索引字段或者主键。
540 | insert_sql2 = "replace into checkin(Name, ID, Class, Time, Description) values(%s, %s, %s, %s, %s)"
541 | users2 = self.line_text_info
542 | cursor.executemany(insert_sql2, users2)
543 | except ConnectionAbortedError as e:
544 | self.ui.textBrowser_log.append("[INFO] 数据库写入失败!")
545 | else:
546 | self.ui.textBrowser_log.append("[INFO] 数据库写入成功!")
547 | finally:
548 | # 提交到数据库执行
549 | db.commit()
550 | cursor.close()
551 | db.close()
552 |
553 |
554 | # 请假/补签登记
555 | def leave_button(self):
556 | self.leave_students(1)
557 |
558 | def supplyment_button(self):
559 | self.leave_students(2)
560 |
561 | def leave_students(self, button):
562 | global results
563 | self.lineTextInfo = []
564 | # 为防止输入为空卡死,先进行是否输入数据的判断
565 | if self.ui.lineEdit_leave.isModified() or self.ui.lineEdit_supplement.isModified():
566 | # 打开数据库连接
567 | db, cursor = connect_to_sql()
568 | # 获取系统时间,保存到秒
569 | currentTime = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
570 | if button == 1:
571 | self.ui.textBrowser_log.append("[INFO] 正在执行请假登记...")
572 | self.description = "请假"
573 | self.lineText_leave_id = self.ui.lineEdit_leave.text()
574 | results = self.use_id_get_info(self.lineText_leave_id)
575 | elif button == 2:
576 | self.ui.textBrowser_log.append("[INFO] 正在执行漏签补签...")
577 | self.description = "漏签补签"
578 | self.lineText_leave_id = self.ui.lineEdit_supplement.text()
579 | results = self.use_id_get_info(self.lineText_leave_id)
580 | else:
581 | print("[Error] The value of button must be one or two!")
582 |
583 | if len(results) != 0:
584 | try:
585 | self.ui.textBrowser_log.append("[INFO] 正在从数据库获取当前用户信息...")
586 | self.lineTextInfo.append((results[0], results[1], results[2],
587 | currentTime,
588 | self.description))
589 | except ConnectionAbortedError as e:
590 | self.ui.textBrowser_log.append("[INFO] 从数据库获取信息失败,请保证当前用户的信息和考勤记录已录入数据库!", e)
591 | # 写入数据库
592 | try:
593 | # 如果存在数据,先删除再写入。前提是设置唯一索引字段或者主键。
594 | insert_sql = "replace into checkin(Name, ID, Class, Time, Description) values(%s, %s, %s, %s, %s)"
595 | users = self.lineTextInfo
596 | cursor.executemany(insert_sql, users)
597 | except ValueError as e:
598 | self.ui.textBrowser_log.append("[INFO] 写入数据库失败!", e)
599 | else:
600 | self.ui.textBrowser_log.append("[INFO] 写入数据库成功!")
601 | QMessageBox.warning(self, "Warning", "{} {}登记成功,请勿重复操作!".format(self.lineText_leave_id,
602 | self.description), QMessageBox.Ok)
603 | finally:
604 | # 提交到数据库执行
605 | db.commit()
606 | cursor.close()
607 | db.close()
608 |
609 | else:
610 | QMessageBox.critical(self, "Error", f"您输入的ID {self.lineText_leave_id} 不存在!请先录入数据库!")
611 | else:
612 | QMessageBox.critical(self, "Error", "学号不能为空,请输入后重试!", QMessageBox.Ok) # (QMessageBox.Yes | QMessageBox.No)
613 | # 输入框清零
614 | self.ui.lineEdit_leave.clear()
615 | self.ui.lineEdit_supplement.clear()
616 |
617 |
618 | # 核验本地人脸与数据库信息是否一致
619 | def check_variation_db(self):
620 | try:
621 | db, cursor = connect_to_sql()
622 | except ConnectionAbortedError as e:
623 | self.ui.textBrowser_log.append('[INFO] 连接数据库失败,请检查配置信息!')
624 | else:
625 | sql = "select id, name from students"
626 | # 执行查询
627 | cursor.execute(sql)
628 | results = cursor.fetchall()
629 | self.student_ids = []
630 | self.student_names = []
631 | for item in results:
632 | self.student_ids.append(item[0])
633 | self.student_names.append(item[1])
634 | print('[INFO] 当前班级内的成员包括:', self.student_ids, self.student_names)
635 | # 统计本地人脸数据信息
636 | num_dict = statical_facedata_nums()
637 | # ID
638 | self.keys = []
639 | for key in list(num_dict.keys()):
640 | self.keys.append(int(key))
641 | self.check_variation_set_operate()
642 | finally:
643 | db.commit()
644 | cursor.close()
645 | db.close()
646 |
647 | def check_variation_set_operate(self):
648 | # 并集
649 | union_set = set(self.student_ids).union(set(self.keys))
650 | # 交集
651 | inter_set = set(self.student_ids).intersection(set(self.keys))
652 | # 差集
653 | two_diff_set = set(self.student_ids).difference(set(self.keys))
654 | # 本地与数据库不同的ID
655 | local_diff_set = union_set - set(self.student_ids)
656 | # 数据库与本地不同的ID
657 | db_diff_set = union_set - set(self.keys)
658 |
659 | if len(union_set) == 0:
660 | self.ui.textBrowser_log.append('[Error] 本地人脸库名称与数据库均未录入信息,请先录入!')
661 | print('[Error] union_set:', union_set)
662 | elif len(inter_set) == 0 and len(union_set) != 0:
663 | self.ui.textBrowser_log.append('[Error] 本地人脸库名称与数据库完全不一致,请先修改!')
664 | print('[Error] inter_set:', inter_set)
665 | elif len(two_diff_set) == 0 and len(union_set) != 0:
666 | self.ui.textBrowser_log.append('[Success] 核验完成,未发现问题!')
667 | print('[Success] two_diff_set:', two_diff_set)
668 |
669 | elif len(local_diff_set) != 0:
670 | self.ui.textBrowser_log.append('[Warning] 数据库中以下ID的人脸信息还未采集,请抓紧采集!')
671 | self.ui.textBrowser_log.append(str(local_diff_set))
672 | print('[Warning] local_diff_set:', local_diff_set)
673 | elif len(db_diff_set) != 0:
674 | self.ui.textBrowser_log.append('[Warning] 本地人脸以下ID的信息还未录入数据库,请抓紧录入!')
675 | self.ui.textBrowser_log.append(str(db_diff_set))
676 | print('[Warning] db_diff_set:', db_diff_set)
677 |
678 | # 使用ID当索引找到其它信息
679 | def use_id_get_info(self, ID):
680 | global cursor, db
681 | if ID != '':
682 | try:
683 | # 打开数据库连接
684 | db, cursor = connect_to_sql()
685 | # 查询语句,实现通过ID关键字检索个人信息的功能
686 | sql = "select * from students where ID = {}".format(ID)
687 | # 执行查询
688 | cursor.execute(sql)
689 | # 获取所有记录列表
690 | results = cursor.fetchall()
691 | self.check_info = []
692 | for i in results:
693 | self.check_info.append(i[1])
694 | self.check_info.append(i[0])
695 | self.check_info.append(i[2])
696 | return self.check_info
697 | except ConnectionAbortedError as e:
698 | self.ui.textBrowser_log.append("[ERROR] 数据库连接失败!")
699 | finally:
700 | db.commit()
701 | cursor.close()
702 | db.close()
703 |
704 | # 显示未到
705 | def show_late_absence(self):
706 | try:
707 | db, cursor = connect_to_sql()
708 | except ConnectionAbortedError as e:
709 | self.ui.textBrowser_log.append('[INFO] 连接数据库失败,请检查配置信息!')
710 | else:
711 | sql = "select ID, Name, Class from students" # 学生信息
712 |
713 | sql2 = "select * from checkin" # 考勤信息
714 | # 执行查询,全部学生
715 | cursor.execute(sql)
716 | results = cursor.fetchall()
717 | self.student_ids = []
718 | self.student_names = []
719 | self.student_class = []
720 | # self.student_time = []
721 | for item in results:
722 | self.student_ids.append(item[0])
723 | self.student_names.append(item[1])
724 | self.student_class.append(item[2])
725 |
726 | # 执行查询,已经到了的
727 | cursor.execute(sql2)
728 | result2 = cursor.fetchall()
729 | self.student_ids2 = []
730 | self.student_names2 = []
731 | self.student_class2 = []
732 | current_year = datetime.now().year
733 | current_month= datetime.now().month
734 | current_day = datetime.now().day
735 | for item in result2:
736 | if current_year == item[3].year and current_month == item[3].month and current_day == item[3].day:
737 | self.student_ids2.append(item[1])
738 | self.student_names2.append(item[0])
739 | self.student_class2.append(item[2])
740 | finally:
741 | db.commit()
742 | cursor.close()
743 | db.close()
744 | if len(self.student_ids) == 0:
745 | QMessageBox.warning(self, "Yes", "全员到齐", QMessageBox.Ok)
746 | else:
747 | # 设置显示数据层次结构,4行4列(包含行表头)
748 | table_view_module = QtGui.QStandardItemModel(len(self.student_ids) - len(self.student_ids2), 1)
749 | table_view_module.setHorizontalHeaderLabels(['学号', '姓名', '班级'])
750 |
751 | step = 0
752 | for i in range(len(self.student_ids)):
753 | flag = 0
754 | for j in range(len(self.student_ids2)):
755 | if self.student_ids[i] == self.student_ids2[j]:
756 | flag = 1
757 | if flag == 0: # 未到
758 | id = self.student_ids[i]
759 | num = QtGui.QStandardItem(str(id))
760 | name = self.student_names[i]
761 | name = QtGui.QStandardItem(name)
762 | Class = self.student_class[i]
763 | Class = QtGui.QStandardItem(Class)
764 | # 设置每个位置的行名称和文本值
765 | table_view_module.setItem(step, 0, num)
766 | table_view_module.setItem(step, 1, name)
767 | table_view_module.setItem(step, 2, Class)
768 | step = step + 1
769 |
770 | # 指定显示的tableView_escape控件,实例化表格视图
771 | self.ui.tableView_escape.setModel(table_view_module)
772 |
773 |
774 | # 导出未到学生
775 | def import_late_absence(self):
776 | self.address = QtWidgets.QFileDialog.getExistingDirectory(None, "选取文件夹", "C:/") # 起始路径
777 | try:
778 | db, cursor = connect_to_sql()
779 | except ConnectionAbortedError as e:
780 | self.ui.textBrowser_log.append('[INFO] 连接数据库失败,请检查配置信息!')
781 | else:
782 | sql = "select ID, Name, Class from students" # 学生信息
783 |
784 | sql2 = "select * from checkin" # 考勤信息
785 | # 执行查询,全部学生
786 | cursor.execute(sql)
787 | results = cursor.fetchall()
788 | self.student_ids = []
789 | self.student_names = []
790 | self.student_class = []
791 | for item in results:
792 | self.student_ids.append(item[0])
793 | self.student_names.append(item[1])
794 | self.student_class.append(item[2])
795 |
796 | # 执行查询,已经到了的
797 | cursor.execute(sql2)
798 | result2 = cursor.fetchall()
799 | self.student_ids2 = []
800 | self.student_names2 = []
801 | self.student_class2 = []
802 | current_year = datetime.now().year
803 | current_month= datetime.now().month
804 | current_day = datetime.now().day
805 | for item in result2:
806 | if current_year == item[3].year and current_month == item[3].month and current_day == item[3].day:
807 | self.student_ids2.append(item[1])
808 | self.student_names2.append(item[0])
809 | self.student_class2.append(item[2])
810 | finally:
811 | db.commit()
812 | cursor.close()
813 | db.close()
814 | wb = openpyxl.Workbook() # 创建工作簿对象
815 | current_year = str(current_year)
816 | current_month = str(current_month)
817 | current_day = str(current_day)
818 | ws = wb['Sheet'] # 创建子表
819 | ws.append(['学号', '姓名', '班级']) # 添加表头
820 | for i in range(len(self.student_ids)):
821 | flag = 0
822 | for j in range(len(self.student_ids2)):
823 | if self.student_ids[i] == self.student_ids2[j]:
824 | flag = 1
825 | if flag == 0: # 未到
826 | id = self.student_ids[i]
827 | name = self.student_names[i]
828 | Class = self.student_class[i]
829 | data = id, name, Class
830 | ws.append(data) # 每次写入一行
831 | tablename = current_year + '年' + current_month + '月' + current_day + '日缺勤名单'
832 | wb.save(self.address + '\\' + tablename + '.xlsx')
833 |
834 | # 训练人脸识别模型,静态方法
835 | # @staticmethod
836 | def train_model(self):
837 | q_message = QMessageBox.information(self, "Tips", "你确定要重新训练模型吗?", QMessageBox.Yes | QMessageBox.No)
838 | if QMessageBox.Yes == q_message:
839 | GeneratorModel.Generator()
840 | GeneratorModel.TrainModel()
841 | self.ui.textBrowser_log.append('[INFO] 模型训练完成!')
842 | else:
843 | self.ui.textBrowser_log.append('[INFO] 取消模型进程!')
844 |
845 | def open_info_dialog(self):
846 | if self.cap.isOpened():
847 | QMessageBox.warning(self, "Warning", "为防止摄像头冲突,已自动关闭摄像头!", QMessageBox.Ok)
848 | self.cap.release()
849 |
850 |
851 | def quit_window(self):
852 | if self.cap.isOpened():
853 | self.cap.release()
854 | QCoreApplication.quit()
855 |
856 |
857 | if __name__ == '__main__':
858 | app = QApplication(sys.argv)
859 | # 创建并显示窗口
860 | mainWindow = MainWindow()
861 | infoWindow = InfoDialog()
862 | detailWindow = Detaillog()
863 | rcWindow = RCDialog()
864 | mainWindow.ui.bt_gathering.clicked.connect(infoWindow.handle_click)
865 | mainWindow.ui.bt_analyse.clicked.connect(detailWindow.handle_click)
866 | mainWindow.ui.bt_random_check.clicked.connect(rcWindow.handle_click)
867 | mainWindow.show()
868 | sys.exit(app.exec_())
869 |
--------------------------------------------------------------------------------
/images/deep_face_recognition_process.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/images/deep_face_recognition_process.png
--------------------------------------------------------------------------------
/images/detail_window.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/images/detail_window.png
--------------------------------------------------------------------------------
/images/face_alignment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/images/face_alignment.png
--------------------------------------------------------------------------------
/images/face_detection.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/images/face_detection.png
--------------------------------------------------------------------------------
/images/facenet_architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/images/facenet_architecture.png
--------------------------------------------------------------------------------
/images/info_window.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/images/info_window.png
--------------------------------------------------------------------------------
/images/main_window.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/images/main_window.png
--------------------------------------------------------------------------------
/images/mysql_table1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/images/mysql_table1.png
--------------------------------------------------------------------------------
/images/mysql_table2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/images/mysql_table2.png
--------------------------------------------------------------------------------
/images/mysql_table3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/images/mysql_table3.png
--------------------------------------------------------------------------------
/images/mysql_table4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/images/mysql_table4.png
--------------------------------------------------------------------------------
/logo_imgs/bkg1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/logo_imgs/bkg1.png
--------------------------------------------------------------------------------
/logo_imgs/bkg2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/logo_imgs/bkg2.png
--------------------------------------------------------------------------------
/logo_imgs/brain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/logo_imgs/brain.png
--------------------------------------------------------------------------------
/logo_imgs/fcb_logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/logo_imgs/fcb_logo.jpg
--------------------------------------------------------------------------------
/logo_imgs/fcb_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/logo_imgs/fcb_logo.png
--------------------------------------------------------------------------------
/logo_imgs/info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/logo_imgs/info.png
--------------------------------------------------------------------------------
/logo_imgs/info_icon.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/logo_imgs/info_icon.jpg
--------------------------------------------------------------------------------
/logo_imgs/warn_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/logo_imgs/warn_icon.png
--------------------------------------------------------------------------------
/model_face_detection/deploy.prototxt:
--------------------------------------------------------------------------------
1 | input: "data"
2 | input_shape {
3 | dim: 1
4 | dim: 3
5 | dim: 300
6 | dim: 300
7 | }
8 |
9 | layer {
10 | name: "data_bn"
11 | type: "BatchNorm"
12 | bottom: "data"
13 | top: "data_bn"
14 | param {
15 | lr_mult: 0.0
16 | }
17 | param {
18 | lr_mult: 0.0
19 | }
20 | param {
21 | lr_mult: 0.0
22 | }
23 | }
24 | layer {
25 | name: "data_scale"
26 | type: "Scale"
27 | bottom: "data_bn"
28 | top: "data_bn"
29 | param {
30 | lr_mult: 1.0
31 | decay_mult: 1.0
32 | }
33 | param {
34 | lr_mult: 2.0
35 | decay_mult: 1.0
36 | }
37 | scale_param {
38 | bias_term: true
39 | }
40 | }
41 | layer {
42 | name: "conv1_h"
43 | type: "Convolution"
44 | bottom: "data_bn"
45 | top: "conv1_h"
46 | param {
47 | lr_mult: 1.0
48 | decay_mult: 1.0
49 | }
50 | param {
51 | lr_mult: 2.0
52 | decay_mult: 1.0
53 | }
54 | convolution_param {
55 | num_output: 32
56 | pad: 3
57 | kernel_size: 7
58 | stride: 2
59 | weight_filler {
60 | type: "msra"
61 | variance_norm: FAN_OUT
62 | }
63 | bias_filler {
64 | type: "constant"
65 | value: 0.0
66 | }
67 | }
68 | }
69 | layer {
70 | name: "conv1_bn_h"
71 | type: "BatchNorm"
72 | bottom: "conv1_h"
73 | top: "conv1_h"
74 | param {
75 | lr_mult: 0.0
76 | }
77 | param {
78 | lr_mult: 0.0
79 | }
80 | param {
81 | lr_mult: 0.0
82 | }
83 | }
84 | layer {
85 | name: "conv1_scale_h"
86 | type: "Scale"
87 | bottom: "conv1_h"
88 | top: "conv1_h"
89 | param {
90 | lr_mult: 1.0
91 | decay_mult: 1.0
92 | }
93 | param {
94 | lr_mult: 2.0
95 | decay_mult: 1.0
96 | }
97 | scale_param {
98 | bias_term: true
99 | }
100 | }
101 | layer {
102 | name: "conv1_relu"
103 | type: "ReLU"
104 | bottom: "conv1_h"
105 | top: "conv1_h"
106 | }
107 | layer {
108 | name: "conv1_pool"
109 | type: "Pooling"
110 | bottom: "conv1_h"
111 | top: "conv1_pool"
112 | pooling_param {
113 | kernel_size: 3
114 | stride: 2
115 | }
116 | }
117 | layer {
118 | name: "layer_64_1_conv1_h"
119 | type: "Convolution"
120 | bottom: "conv1_pool"
121 | top: "layer_64_1_conv1_h"
122 | param {
123 | lr_mult: 1.0
124 | decay_mult: 1.0
125 | }
126 | convolution_param {
127 | num_output: 32
128 | bias_term: false
129 | pad: 1
130 | kernel_size: 3
131 | stride: 1
132 | weight_filler {
133 | type: "msra"
134 | }
135 | bias_filler {
136 | type: "constant"
137 | value: 0.0
138 | }
139 | }
140 | }
141 | layer {
142 | name: "layer_64_1_bn2_h"
143 | type: "BatchNorm"
144 | bottom: "layer_64_1_conv1_h"
145 | top: "layer_64_1_conv1_h"
146 | param {
147 | lr_mult: 0.0
148 | }
149 | param {
150 | lr_mult: 0.0
151 | }
152 | param {
153 | lr_mult: 0.0
154 | }
155 | }
156 | layer {
157 | name: "layer_64_1_scale2_h"
158 | type: "Scale"
159 | bottom: "layer_64_1_conv1_h"
160 | top: "layer_64_1_conv1_h"
161 | param {
162 | lr_mult: 1.0
163 | decay_mult: 1.0
164 | }
165 | param {
166 | lr_mult: 2.0
167 | decay_mult: 1.0
168 | }
169 | scale_param {
170 | bias_term: true
171 | }
172 | }
173 | layer {
174 | name: "layer_64_1_relu2"
175 | type: "ReLU"
176 | bottom: "layer_64_1_conv1_h"
177 | top: "layer_64_1_conv1_h"
178 | }
179 | layer {
180 | name: "layer_64_1_conv2_h"
181 | type: "Convolution"
182 | bottom: "layer_64_1_conv1_h"
183 | top: "layer_64_1_conv2_h"
184 | param {
185 | lr_mult: 1.0
186 | decay_mult: 1.0
187 | }
188 | convolution_param {
189 | num_output: 32
190 | bias_term: false
191 | pad: 1
192 | kernel_size: 3
193 | stride: 1
194 | weight_filler {
195 | type: "msra"
196 | }
197 | bias_filler {
198 | type: "constant"
199 | value: 0.0
200 | }
201 | }
202 | }
203 | layer {
204 | name: "layer_64_1_sum"
205 | type: "Eltwise"
206 | bottom: "layer_64_1_conv2_h"
207 | bottom: "conv1_pool"
208 | top: "layer_64_1_sum"
209 | }
210 | layer {
211 | name: "layer_128_1_bn1_h"
212 | type: "BatchNorm"
213 | bottom: "layer_64_1_sum"
214 | top: "layer_128_1_bn1_h"
215 | param {
216 | lr_mult: 0.0
217 | }
218 | param {
219 | lr_mult: 0.0
220 | }
221 | param {
222 | lr_mult: 0.0
223 | }
224 | }
225 | layer {
226 | name: "layer_128_1_scale1_h"
227 | type: "Scale"
228 | bottom: "layer_128_1_bn1_h"
229 | top: "layer_128_1_bn1_h"
230 | param {
231 | lr_mult: 1.0
232 | decay_mult: 1.0
233 | }
234 | param {
235 | lr_mult: 2.0
236 | decay_mult: 1.0
237 | }
238 | scale_param {
239 | bias_term: true
240 | }
241 | }
242 | layer {
243 | name: "layer_128_1_relu1"
244 | type: "ReLU"
245 | bottom: "layer_128_1_bn1_h"
246 | top: "layer_128_1_bn1_h"
247 | }
248 | layer {
249 | name: "layer_128_1_conv1_h"
250 | type: "Convolution"
251 | bottom: "layer_128_1_bn1_h"
252 | top: "layer_128_1_conv1_h"
253 | param {
254 | lr_mult: 1.0
255 | decay_mult: 1.0
256 | }
257 | convolution_param {
258 | num_output: 128
259 | bias_term: false
260 | pad: 1
261 | kernel_size: 3
262 | stride: 2
263 | weight_filler {
264 | type: "msra"
265 | }
266 | bias_filler {
267 | type: "constant"
268 | value: 0.0
269 | }
270 | }
271 | }
272 | layer {
273 | name: "layer_128_1_bn2"
274 | type: "BatchNorm"
275 | bottom: "layer_128_1_conv1_h"
276 | top: "layer_128_1_conv1_h"
277 | param {
278 | lr_mult: 0.0
279 | }
280 | param {
281 | lr_mult: 0.0
282 | }
283 | param {
284 | lr_mult: 0.0
285 | }
286 | }
287 | layer {
288 | name: "layer_128_1_scale2"
289 | type: "Scale"
290 | bottom: "layer_128_1_conv1_h"
291 | top: "layer_128_1_conv1_h"
292 | param {
293 | lr_mult: 1.0
294 | decay_mult: 1.0
295 | }
296 | param {
297 | lr_mult: 2.0
298 | decay_mult: 1.0
299 | }
300 | scale_param {
301 | bias_term: true
302 | }
303 | }
304 | layer {
305 | name: "layer_128_1_relu2"
306 | type: "ReLU"
307 | bottom: "layer_128_1_conv1_h"
308 | top: "layer_128_1_conv1_h"
309 | }
310 | layer {
311 | name: "layer_128_1_conv2"
312 | type: "Convolution"
313 | bottom: "layer_128_1_conv1_h"
314 | top: "layer_128_1_conv2"
315 | param {
316 | lr_mult: 1.0
317 | decay_mult: 1.0
318 | }
319 | convolution_param {
320 | num_output: 128
321 | bias_term: false
322 | pad: 1
323 | kernel_size: 3
324 | stride: 1
325 | weight_filler {
326 | type: "msra"
327 | }
328 | bias_filler {
329 | type: "constant"
330 | value: 0.0
331 | }
332 | }
333 | }
334 | layer {
335 | name: "layer_128_1_conv_expand_h"
336 | type: "Convolution"
337 | bottom: "layer_128_1_bn1_h"
338 | top: "layer_128_1_conv_expand_h"
339 | param {
340 | lr_mult: 1.0
341 | decay_mult: 1.0
342 | }
343 | convolution_param {
344 | num_output: 128
345 | bias_term: false
346 | pad: 0
347 | kernel_size: 1
348 | stride: 2
349 | weight_filler {
350 | type: "msra"
351 | }
352 | bias_filler {
353 | type: "constant"
354 | value: 0.0
355 | }
356 | }
357 | }
358 | layer {
359 | name: "layer_128_1_sum"
360 | type: "Eltwise"
361 | bottom: "layer_128_1_conv2"
362 | bottom: "layer_128_1_conv_expand_h"
363 | top: "layer_128_1_sum"
364 | }
365 | layer {
366 | name: "layer_256_1_bn1"
367 | type: "BatchNorm"
368 | bottom: "layer_128_1_sum"
369 | top: "layer_256_1_bn1"
370 | param {
371 | lr_mult: 0.0
372 | }
373 | param {
374 | lr_mult: 0.0
375 | }
376 | param {
377 | lr_mult: 0.0
378 | }
379 | }
380 | layer {
381 | name: "layer_256_1_scale1"
382 | type: "Scale"
383 | bottom: "layer_256_1_bn1"
384 | top: "layer_256_1_bn1"
385 | param {
386 | lr_mult: 1.0
387 | decay_mult: 1.0
388 | }
389 | param {
390 | lr_mult: 2.0
391 | decay_mult: 1.0
392 | }
393 | scale_param {
394 | bias_term: true
395 | }
396 | }
397 | layer {
398 | name: "layer_256_1_relu1"
399 | type: "ReLU"
400 | bottom: "layer_256_1_bn1"
401 | top: "layer_256_1_bn1"
402 | }
403 | layer {
404 | name: "layer_256_1_conv1"
405 | type: "Convolution"
406 | bottom: "layer_256_1_bn1"
407 | top: "layer_256_1_conv1"
408 | param {
409 | lr_mult: 1.0
410 | decay_mult: 1.0
411 | }
412 | convolution_param {
413 | num_output: 256
414 | bias_term: false
415 | pad: 1
416 | kernel_size: 3
417 | stride: 2
418 | weight_filler {
419 | type: "msra"
420 | }
421 | bias_filler {
422 | type: "constant"
423 | value: 0.0
424 | }
425 | }
426 | }
427 | layer {
428 | name: "layer_256_1_bn2"
429 | type: "BatchNorm"
430 | bottom: "layer_256_1_conv1"
431 | top: "layer_256_1_conv1"
432 | param {
433 | lr_mult: 0.0
434 | }
435 | param {
436 | lr_mult: 0.0
437 | }
438 | param {
439 | lr_mult: 0.0
440 | }
441 | }
442 | layer {
443 | name: "layer_256_1_scale2"
444 | type: "Scale"
445 | bottom: "layer_256_1_conv1"
446 | top: "layer_256_1_conv1"
447 | param {
448 | lr_mult: 1.0
449 | decay_mult: 1.0
450 | }
451 | param {
452 | lr_mult: 2.0
453 | decay_mult: 1.0
454 | }
455 | scale_param {
456 | bias_term: true
457 | }
458 | }
459 | layer {
460 | name: "layer_256_1_relu2"
461 | type: "ReLU"
462 | bottom: "layer_256_1_conv1"
463 | top: "layer_256_1_conv1"
464 | }
465 | layer {
466 | name: "layer_256_1_conv2"
467 | type: "Convolution"
468 | bottom: "layer_256_1_conv1"
469 | top: "layer_256_1_conv2"
470 | param {
471 | lr_mult: 1.0
472 | decay_mult: 1.0
473 | }
474 | convolution_param {
475 | num_output: 256
476 | bias_term: false
477 | pad: 1
478 | kernel_size: 3
479 | stride: 1
480 | weight_filler {
481 | type: "msra"
482 | }
483 | bias_filler {
484 | type: "constant"
485 | value: 0.0
486 | }
487 | }
488 | }
489 | layer {
490 | name: "layer_256_1_conv_expand"
491 | type: "Convolution"
492 | bottom: "layer_256_1_bn1"
493 | top: "layer_256_1_conv_expand"
494 | param {
495 | lr_mult: 1.0
496 | decay_mult: 1.0
497 | }
498 | convolution_param {
499 | num_output: 256
500 | bias_term: false
501 | pad: 0
502 | kernel_size: 1
503 | stride: 2
504 | weight_filler {
505 | type: "msra"
506 | }
507 | bias_filler {
508 | type: "constant"
509 | value: 0.0
510 | }
511 | }
512 | }
513 | layer {
514 | name: "layer_256_1_sum"
515 | type: "Eltwise"
516 | bottom: "layer_256_1_conv2"
517 | bottom: "layer_256_1_conv_expand"
518 | top: "layer_256_1_sum"
519 | }
520 | layer {
521 | name: "layer_512_1_bn1"
522 | type: "BatchNorm"
523 | bottom: "layer_256_1_sum"
524 | top: "layer_512_1_bn1"
525 | param {
526 | lr_mult: 0.0
527 | }
528 | param {
529 | lr_mult: 0.0
530 | }
531 | param {
532 | lr_mult: 0.0
533 | }
534 | }
535 | layer {
536 | name: "layer_512_1_scale1"
537 | type: "Scale"
538 | bottom: "layer_512_1_bn1"
539 | top: "layer_512_1_bn1"
540 | param {
541 | lr_mult: 1.0
542 | decay_mult: 1.0
543 | }
544 | param {
545 | lr_mult: 2.0
546 | decay_mult: 1.0
547 | }
548 | scale_param {
549 | bias_term: true
550 | }
551 | }
552 | layer {
553 | name: "layer_512_1_relu1"
554 | type: "ReLU"
555 | bottom: "layer_512_1_bn1"
556 | top: "layer_512_1_bn1"
557 | }
558 | layer {
559 | name: "layer_512_1_conv1_h"
560 | type: "Convolution"
561 | bottom: "layer_512_1_bn1"
562 | top: "layer_512_1_conv1_h"
563 | param {
564 | lr_mult: 1.0
565 | decay_mult: 1.0
566 | }
567 | convolution_param {
568 | num_output: 128
569 | bias_term: false
570 | pad: 1
571 | kernel_size: 3
572 | stride: 1 # 2
573 | weight_filler {
574 | type: "msra"
575 | }
576 | bias_filler {
577 | type: "constant"
578 | value: 0.0
579 | }
580 | }
581 | }
582 | layer {
583 | name: "layer_512_1_bn2_h"
584 | type: "BatchNorm"
585 | bottom: "layer_512_1_conv1_h"
586 | top: "layer_512_1_conv1_h"
587 | param {
588 | lr_mult: 0.0
589 | }
590 | param {
591 | lr_mult: 0.0
592 | }
593 | param {
594 | lr_mult: 0.0
595 | }
596 | }
597 | layer {
598 | name: "layer_512_1_scale2_h"
599 | type: "Scale"
600 | bottom: "layer_512_1_conv1_h"
601 | top: "layer_512_1_conv1_h"
602 | param {
603 | lr_mult: 1.0
604 | decay_mult: 1.0
605 | }
606 | param {
607 | lr_mult: 2.0
608 | decay_mult: 1.0
609 | }
610 | scale_param {
611 | bias_term: true
612 | }
613 | }
614 | layer {
615 | name: "layer_512_1_relu2"
616 | type: "ReLU"
617 | bottom: "layer_512_1_conv1_h"
618 | top: "layer_512_1_conv1_h"
619 | }
620 | layer {
621 | name: "layer_512_1_conv2_h"
622 | type: "Convolution"
623 | bottom: "layer_512_1_conv1_h"
624 | top: "layer_512_1_conv2_h"
625 | param {
626 | lr_mult: 1.0
627 | decay_mult: 1.0
628 | }
629 | convolution_param {
630 | num_output: 256
631 | bias_term: false
632 | pad: 2 # 1
633 | kernel_size: 3
634 | stride: 1
635 | dilation: 2
636 | weight_filler {
637 | type: "msra"
638 | }
639 | bias_filler {
640 | type: "constant"
641 | value: 0.0
642 | }
643 | }
644 | }
645 | layer {
646 | name: "layer_512_1_conv_expand_h"
647 | type: "Convolution"
648 | bottom: "layer_512_1_bn1"
649 | top: "layer_512_1_conv_expand_h"
650 | param {
651 | lr_mult: 1.0
652 | decay_mult: 1.0
653 | }
654 | convolution_param {
655 | num_output: 256
656 | bias_term: false
657 | pad: 0
658 | kernel_size: 1
659 | stride: 1 # 2
660 | weight_filler {
661 | type: "msra"
662 | }
663 | bias_filler {
664 | type: "constant"
665 | value: 0.0
666 | }
667 | }
668 | }
669 | layer {
670 | name: "layer_512_1_sum"
671 | type: "Eltwise"
672 | bottom: "layer_512_1_conv2_h"
673 | bottom: "layer_512_1_conv_expand_h"
674 | top: "layer_512_1_sum"
675 | }
676 | layer {
677 | name: "last_bn_h"
678 | type: "BatchNorm"
679 | bottom: "layer_512_1_sum"
680 | top: "layer_512_1_sum"
681 | param {
682 | lr_mult: 0.0
683 | }
684 | param {
685 | lr_mult: 0.0
686 | }
687 | param {
688 | lr_mult: 0.0
689 | }
690 | }
691 | layer {
692 | name: "last_scale_h"
693 | type: "Scale"
694 | bottom: "layer_512_1_sum"
695 | top: "layer_512_1_sum"
696 | param {
697 | lr_mult: 1.0
698 | decay_mult: 1.0
699 | }
700 | param {
701 | lr_mult: 2.0
702 | decay_mult: 1.0
703 | }
704 | scale_param {
705 | bias_term: true
706 | }
707 | }
708 | layer {
709 | name: "last_relu"
710 | type: "ReLU"
711 | bottom: "layer_512_1_sum"
712 | top: "fc7"
713 | }
714 |
715 | layer {
716 | name: "conv6_1_h"
717 | type: "Convolution"
718 | bottom: "fc7"
719 | top: "conv6_1_h"
720 | param {
721 | lr_mult: 1
722 | decay_mult: 1
723 | }
724 | param {
725 | lr_mult: 2
726 | decay_mult: 0
727 | }
728 | convolution_param {
729 | num_output: 128
730 | pad: 0
731 | kernel_size: 1
732 | stride: 1
733 | weight_filler {
734 | type: "xavier"
735 | }
736 | bias_filler {
737 | type: "constant"
738 | value: 0
739 | }
740 | }
741 | }
742 | layer {
743 | name: "conv6_1_relu"
744 | type: "ReLU"
745 | bottom: "conv6_1_h"
746 | top: "conv6_1_h"
747 | }
748 | layer {
749 | name: "conv6_2_h"
750 | type: "Convolution"
751 | bottom: "conv6_1_h"
752 | top: "conv6_2_h"
753 | param {
754 | lr_mult: 1
755 | decay_mult: 1
756 | }
757 | param {
758 | lr_mult: 2
759 | decay_mult: 0
760 | }
761 | convolution_param {
762 | num_output: 256
763 | pad: 1
764 | kernel_size: 3
765 | stride: 2
766 | weight_filler {
767 | type: "xavier"
768 | }
769 | bias_filler {
770 | type: "constant"
771 | value: 0
772 | }
773 | }
774 | }
775 | layer {
776 | name: "conv6_2_relu"
777 | type: "ReLU"
778 | bottom: "conv6_2_h"
779 | top: "conv6_2_h"
780 | }
781 | layer {
782 | name: "conv7_1_h"
783 | type: "Convolution"
784 | bottom: "conv6_2_h"
785 | top: "conv7_1_h"
786 | param {
787 | lr_mult: 1
788 | decay_mult: 1
789 | }
790 | param {
791 | lr_mult: 2
792 | decay_mult: 0
793 | }
794 | convolution_param {
795 | num_output: 64
796 | pad: 0
797 | kernel_size: 1
798 | stride: 1
799 | weight_filler {
800 | type: "xavier"
801 | }
802 | bias_filler {
803 | type: "constant"
804 | value: 0
805 | }
806 | }
807 | }
808 | layer {
809 | name: "conv7_1_relu"
810 | type: "ReLU"
811 | bottom: "conv7_1_h"
812 | top: "conv7_1_h"
813 | }
814 | layer {
815 | name: "conv7_2_h"
816 | type: "Convolution"
817 | bottom: "conv7_1_h"
818 | top: "conv7_2_h"
819 | param {
820 | lr_mult: 1
821 | decay_mult: 1
822 | }
823 | param {
824 | lr_mult: 2
825 | decay_mult: 0
826 | }
827 | convolution_param {
828 | num_output: 128
829 | pad: 1
830 | kernel_size: 3
831 | stride: 2
832 | weight_filler {
833 | type: "xavier"
834 | }
835 | bias_filler {
836 | type: "constant"
837 | value: 0
838 | }
839 | }
840 | }
841 | layer {
842 | name: "conv7_2_relu"
843 | type: "ReLU"
844 | bottom: "conv7_2_h"
845 | top: "conv7_2_h"
846 | }
847 | layer {
848 | name: "conv8_1_h"
849 | type: "Convolution"
850 | bottom: "conv7_2_h"
851 | top: "conv8_1_h"
852 | param {
853 | lr_mult: 1
854 | decay_mult: 1
855 | }
856 | param {
857 | lr_mult: 2
858 | decay_mult: 0
859 | }
860 | convolution_param {
861 | num_output: 64
862 | pad: 0
863 | kernel_size: 1
864 | stride: 1
865 | weight_filler {
866 | type: "xavier"
867 | }
868 | bias_filler {
869 | type: "constant"
870 | value: 0
871 | }
872 | }
873 | }
874 | layer {
875 | name: "conv8_1_relu"
876 | type: "ReLU"
877 | bottom: "conv8_1_h"
878 | top: "conv8_1_h"
879 | }
880 | layer {
881 | name: "conv8_2_h"
882 | type: "Convolution"
883 | bottom: "conv8_1_h"
884 | top: "conv8_2_h"
885 | param {
886 | lr_mult: 1
887 | decay_mult: 1
888 | }
889 | param {
890 | lr_mult: 2
891 | decay_mult: 0
892 | }
893 | convolution_param {
894 | num_output: 128
895 | pad: 1
896 | kernel_size: 3
897 | stride: 1
898 | weight_filler {
899 | type: "xavier"
900 | }
901 | bias_filler {
902 | type: "constant"
903 | value: 0
904 | }
905 | }
906 | }
907 | layer {
908 | name: "conv8_2_relu"
909 | type: "ReLU"
910 | bottom: "conv8_2_h"
911 | top: "conv8_2_h"
912 | }
913 | layer {
914 | name: "conv9_1_h"
915 | type: "Convolution"
916 | bottom: "conv8_2_h"
917 | top: "conv9_1_h"
918 | param {
919 | lr_mult: 1
920 | decay_mult: 1
921 | }
922 | param {
923 | lr_mult: 2
924 | decay_mult: 0
925 | }
926 | convolution_param {
927 | num_output: 64
928 | pad: 0
929 | kernel_size: 1
930 | stride: 1
931 | weight_filler {
932 | type: "xavier"
933 | }
934 | bias_filler {
935 | type: "constant"
936 | value: 0
937 | }
938 | }
939 | }
940 | layer {
941 | name: "conv9_1_relu"
942 | type: "ReLU"
943 | bottom: "conv9_1_h"
944 | top: "conv9_1_h"
945 | }
946 | layer {
947 | name: "conv9_2_h"
948 | type: "Convolution"
949 | bottom: "conv9_1_h"
950 | top: "conv9_2_h"
951 | param {
952 | lr_mult: 1
953 | decay_mult: 1
954 | }
955 | param {
956 | lr_mult: 2
957 | decay_mult: 0
958 | }
959 | convolution_param {
960 | num_output: 128
961 | pad: 1
962 | kernel_size: 3
963 | stride: 1
964 | weight_filler {
965 | type: "xavier"
966 | }
967 | bias_filler {
968 | type: "constant"
969 | value: 0
970 | }
971 | }
972 | }
973 | layer {
974 | name: "conv9_2_relu"
975 | type: "ReLU"
976 | bottom: "conv9_2_h"
977 | top: "conv9_2_h"
978 | }
979 | layer {
980 | name: "conv4_3_norm"
981 | type: "Normalize"
982 | bottom: "layer_256_1_bn1"
983 | top: "conv4_3_norm"
984 | norm_param {
985 | across_spatial: false
986 | scale_filler {
987 | type: "constant"
988 | value: 20
989 | }
990 | channel_shared: false
991 | }
992 | }
993 | layer {
994 | name: "conv4_3_norm_mbox_loc"
995 | type: "Convolution"
996 | bottom: "conv4_3_norm"
997 | top: "conv4_3_norm_mbox_loc"
998 | param {
999 | lr_mult: 1
1000 | decay_mult: 1
1001 | }
1002 | param {
1003 | lr_mult: 2
1004 | decay_mult: 0
1005 | }
1006 | convolution_param {
1007 | num_output: 16
1008 | pad: 1
1009 | kernel_size: 3
1010 | stride: 1
1011 | weight_filler {
1012 | type: "xavier"
1013 | }
1014 | bias_filler {
1015 | type: "constant"
1016 | value: 0
1017 | }
1018 | }
1019 | }
1020 | layer {
1021 | name: "conv4_3_norm_mbox_loc_perm"
1022 | type: "Permute"
1023 | bottom: "conv4_3_norm_mbox_loc"
1024 | top: "conv4_3_norm_mbox_loc_perm"
1025 | permute_param {
1026 | order: 0
1027 | order: 2
1028 | order: 3
1029 | order: 1
1030 | }
1031 | }
1032 | layer {
1033 | name: "conv4_3_norm_mbox_loc_flat"
1034 | type: "Flatten"
1035 | bottom: "conv4_3_norm_mbox_loc_perm"
1036 | top: "conv4_3_norm_mbox_loc_flat"
1037 | flatten_param {
1038 | axis: 1
1039 | }
1040 | }
1041 | layer {
1042 | name: "conv4_3_norm_mbox_conf"
1043 | type: "Convolution"
1044 | bottom: "conv4_3_norm"
1045 | top: "conv4_3_norm_mbox_conf"
1046 | param {
1047 | lr_mult: 1
1048 | decay_mult: 1
1049 | }
1050 | param {
1051 | lr_mult: 2
1052 | decay_mult: 0
1053 | }
1054 | convolution_param {
1055 | num_output: 8 # 84
1056 | pad: 1
1057 | kernel_size: 3
1058 | stride: 1
1059 | weight_filler {
1060 | type: "xavier"
1061 | }
1062 | bias_filler {
1063 | type: "constant"
1064 | value: 0
1065 | }
1066 | }
1067 | }
1068 | layer {
1069 | name: "conv4_3_norm_mbox_conf_perm"
1070 | type: "Permute"
1071 | bottom: "conv4_3_norm_mbox_conf"
1072 | top: "conv4_3_norm_mbox_conf_perm"
1073 | permute_param {
1074 | order: 0
1075 | order: 2
1076 | order: 3
1077 | order: 1
1078 | }
1079 | }
1080 | layer {
1081 | name: "conv4_3_norm_mbox_conf_flat"
1082 | type: "Flatten"
1083 | bottom: "conv4_3_norm_mbox_conf_perm"
1084 | top: "conv4_3_norm_mbox_conf_flat"
1085 | flatten_param {
1086 | axis: 1
1087 | }
1088 | }
1089 | layer {
1090 | name: "conv4_3_norm_mbox_priorbox"
1091 | type: "PriorBox"
1092 | bottom: "conv4_3_norm"
1093 | bottom: "data"
1094 | top: "conv4_3_norm_mbox_priorbox"
1095 | prior_box_param {
1096 | min_size: 30.0
1097 | max_size: 60.0
1098 | aspect_ratio: 2
1099 | flip: true
1100 | clip: false
1101 | variance: 0.1
1102 | variance: 0.1
1103 | variance: 0.2
1104 | variance: 0.2
1105 | step: 8
1106 | offset: 0.5
1107 | }
1108 | }
1109 | layer {
1110 | name: "fc7_mbox_loc"
1111 | type: "Convolution"
1112 | bottom: "fc7"
1113 | top: "fc7_mbox_loc"
1114 | param {
1115 | lr_mult: 1
1116 | decay_mult: 1
1117 | }
1118 | param {
1119 | lr_mult: 2
1120 | decay_mult: 0
1121 | }
1122 | convolution_param {
1123 | num_output: 24
1124 | pad: 1
1125 | kernel_size: 3
1126 | stride: 1
1127 | weight_filler {
1128 | type: "xavier"
1129 | }
1130 | bias_filler {
1131 | type: "constant"
1132 | value: 0
1133 | }
1134 | }
1135 | }
1136 | layer {
1137 | name: "fc7_mbox_loc_perm"
1138 | type: "Permute"
1139 | bottom: "fc7_mbox_loc"
1140 | top: "fc7_mbox_loc_perm"
1141 | permute_param {
1142 | order: 0
1143 | order: 2
1144 | order: 3
1145 | order: 1
1146 | }
1147 | }
1148 | layer {
1149 | name: "fc7_mbox_loc_flat"
1150 | type: "Flatten"
1151 | bottom: "fc7_mbox_loc_perm"
1152 | top: "fc7_mbox_loc_flat"
1153 | flatten_param {
1154 | axis: 1
1155 | }
1156 | }
1157 | layer {
1158 | name: "fc7_mbox_conf"
1159 | type: "Convolution"
1160 | bottom: "fc7"
1161 | top: "fc7_mbox_conf"
1162 | param {
1163 | lr_mult: 1
1164 | decay_mult: 1
1165 | }
1166 | param {
1167 | lr_mult: 2
1168 | decay_mult: 0
1169 | }
1170 | convolution_param {
1171 | num_output: 12 # 126
1172 | pad: 1
1173 | kernel_size: 3
1174 | stride: 1
1175 | weight_filler {
1176 | type: "xavier"
1177 | }
1178 | bias_filler {
1179 | type: "constant"
1180 | value: 0
1181 | }
1182 | }
1183 | }
1184 | layer {
1185 | name: "fc7_mbox_conf_perm"
1186 | type: "Permute"
1187 | bottom: "fc7_mbox_conf"
1188 | top: "fc7_mbox_conf_perm"
1189 | permute_param {
1190 | order: 0
1191 | order: 2
1192 | order: 3
1193 | order: 1
1194 | }
1195 | }
1196 | layer {
1197 | name: "fc7_mbox_conf_flat"
1198 | type: "Flatten"
1199 | bottom: "fc7_mbox_conf_perm"
1200 | top: "fc7_mbox_conf_flat"
1201 | flatten_param {
1202 | axis: 1
1203 | }
1204 | }
1205 | layer {
1206 | name: "fc7_mbox_priorbox"
1207 | type: "PriorBox"
1208 | bottom: "fc7"
1209 | bottom: "data"
1210 | top: "fc7_mbox_priorbox"
1211 | prior_box_param {
1212 | min_size: 60.0
1213 | max_size: 111.0
1214 | aspect_ratio: 2
1215 | aspect_ratio: 3
1216 | flip: true
1217 | clip: false
1218 | variance: 0.1
1219 | variance: 0.1
1220 | variance: 0.2
1221 | variance: 0.2
1222 | step: 16
1223 | offset: 0.5
1224 | }
1225 | }
1226 | layer {
1227 | name: "conv6_2_mbox_loc"
1228 | type: "Convolution"
1229 | bottom: "conv6_2_h"
1230 | top: "conv6_2_mbox_loc"
1231 | param {
1232 | lr_mult: 1
1233 | decay_mult: 1
1234 | }
1235 | param {
1236 | lr_mult: 2
1237 | decay_mult: 0
1238 | }
1239 | convolution_param {
1240 | num_output: 24
1241 | pad: 1
1242 | kernel_size: 3
1243 | stride: 1
1244 | weight_filler {
1245 | type: "xavier"
1246 | }
1247 | bias_filler {
1248 | type: "constant"
1249 | value: 0
1250 | }
1251 | }
1252 | }
1253 | layer {
1254 | name: "conv6_2_mbox_loc_perm"
1255 | type: "Permute"
1256 | bottom: "conv6_2_mbox_loc"
1257 | top: "conv6_2_mbox_loc_perm"
1258 | permute_param {
1259 | order: 0
1260 | order: 2
1261 | order: 3
1262 | order: 1
1263 | }
1264 | }
1265 | layer {
1266 | name: "conv6_2_mbox_loc_flat"
1267 | type: "Flatten"
1268 | bottom: "conv6_2_mbox_loc_perm"
1269 | top: "conv6_2_mbox_loc_flat"
1270 | flatten_param {
1271 | axis: 1
1272 | }
1273 | }
1274 | layer {
1275 | name: "conv6_2_mbox_conf"
1276 | type: "Convolution"
1277 | bottom: "conv6_2_h"
1278 | top: "conv6_2_mbox_conf"
1279 | param {
1280 | lr_mult: 1
1281 | decay_mult: 1
1282 | }
1283 | param {
1284 | lr_mult: 2
1285 | decay_mult: 0
1286 | }
1287 | convolution_param {
1288 | num_output: 12 # 126
1289 | pad: 1
1290 | kernel_size: 3
1291 | stride: 1
1292 | weight_filler {
1293 | type: "xavier"
1294 | }
1295 | bias_filler {
1296 | type: "constant"
1297 | value: 0
1298 | }
1299 | }
1300 | }
1301 | layer {
1302 | name: "conv6_2_mbox_conf_perm"
1303 | type: "Permute"
1304 | bottom: "conv6_2_mbox_conf"
1305 | top: "conv6_2_mbox_conf_perm"
1306 | permute_param {
1307 | order: 0
1308 | order: 2
1309 | order: 3
1310 | order: 1
1311 | }
1312 | }
1313 | layer {
1314 | name: "conv6_2_mbox_conf_flat"
1315 | type: "Flatten"
1316 | bottom: "conv6_2_mbox_conf_perm"
1317 | top: "conv6_2_mbox_conf_flat"
1318 | flatten_param {
1319 | axis: 1
1320 | }
1321 | }
1322 | layer {
1323 | name: "conv6_2_mbox_priorbox"
1324 | type: "PriorBox"
1325 | bottom: "conv6_2_h"
1326 | bottom: "data"
1327 | top: "conv6_2_mbox_priorbox"
1328 | prior_box_param {
1329 | min_size: 111.0
1330 | max_size: 162.0
1331 | aspect_ratio: 2
1332 | aspect_ratio: 3
1333 | flip: true
1334 | clip: false
1335 | variance: 0.1
1336 | variance: 0.1
1337 | variance: 0.2
1338 | variance: 0.2
1339 | step: 32
1340 | offset: 0.5
1341 | }
1342 | }
1343 | layer {
1344 | name: "conv7_2_mbox_loc"
1345 | type: "Convolution"
1346 | bottom: "conv7_2_h"
1347 | top: "conv7_2_mbox_loc"
1348 | param {
1349 | lr_mult: 1
1350 | decay_mult: 1
1351 | }
1352 | param {
1353 | lr_mult: 2
1354 | decay_mult: 0
1355 | }
1356 | convolution_param {
1357 | num_output: 24
1358 | pad: 1
1359 | kernel_size: 3
1360 | stride: 1
1361 | weight_filler {
1362 | type: "xavier"
1363 | }
1364 | bias_filler {
1365 | type: "constant"
1366 | value: 0
1367 | }
1368 | }
1369 | }
1370 | layer {
1371 | name: "conv7_2_mbox_loc_perm"
1372 | type: "Permute"
1373 | bottom: "conv7_2_mbox_loc"
1374 | top: "conv7_2_mbox_loc_perm"
1375 | permute_param {
1376 | order: 0
1377 | order: 2
1378 | order: 3
1379 | order: 1
1380 | }
1381 | }
1382 | layer {
1383 | name: "conv7_2_mbox_loc_flat"
1384 | type: "Flatten"
1385 | bottom: "conv7_2_mbox_loc_perm"
1386 | top: "conv7_2_mbox_loc_flat"
1387 | flatten_param {
1388 | axis: 1
1389 | }
1390 | }
1391 | layer {
1392 | name: "conv7_2_mbox_conf"
1393 | type: "Convolution"
1394 | bottom: "conv7_2_h"
1395 | top: "conv7_2_mbox_conf"
1396 | param {
1397 | lr_mult: 1
1398 | decay_mult: 1
1399 | }
1400 | param {
1401 | lr_mult: 2
1402 | decay_mult: 0
1403 | }
1404 | convolution_param {
1405 | num_output: 12 # 126
1406 | pad: 1
1407 | kernel_size: 3
1408 | stride: 1
1409 | weight_filler {
1410 | type: "xavier"
1411 | }
1412 | bias_filler {
1413 | type: "constant"
1414 | value: 0
1415 | }
1416 | }
1417 | }
1418 | layer {
1419 | name: "conv7_2_mbox_conf_perm"
1420 | type: "Permute"
1421 | bottom: "conv7_2_mbox_conf"
1422 | top: "conv7_2_mbox_conf_perm"
1423 | permute_param {
1424 | order: 0
1425 | order: 2
1426 | order: 3
1427 | order: 1
1428 | }
1429 | }
1430 | layer {
1431 | name: "conv7_2_mbox_conf_flat"
1432 | type: "Flatten"
1433 | bottom: "conv7_2_mbox_conf_perm"
1434 | top: "conv7_2_mbox_conf_flat"
1435 | flatten_param {
1436 | axis: 1
1437 | }
1438 | }
1439 | layer {
1440 | name: "conv7_2_mbox_priorbox"
1441 | type: "PriorBox"
1442 | bottom: "conv7_2_h"
1443 | bottom: "data"
1444 | top: "conv7_2_mbox_priorbox"
1445 | prior_box_param {
1446 | min_size: 162.0
1447 | max_size: 213.0
1448 | aspect_ratio: 2
1449 | aspect_ratio: 3
1450 | flip: true
1451 | clip: false
1452 | variance: 0.1
1453 | variance: 0.1
1454 | variance: 0.2
1455 | variance: 0.2
1456 | step: 64
1457 | offset: 0.5
1458 | }
1459 | }
1460 | layer {
1461 | name: "conv8_2_mbox_loc"
1462 | type: "Convolution"
1463 | bottom: "conv8_2_h"
1464 | top: "conv8_2_mbox_loc"
1465 | param {
1466 | lr_mult: 1
1467 | decay_mult: 1
1468 | }
1469 | param {
1470 | lr_mult: 2
1471 | decay_mult: 0
1472 | }
1473 | convolution_param {
1474 | num_output: 16
1475 | pad: 1
1476 | kernel_size: 3
1477 | stride: 1
1478 | weight_filler {
1479 | type: "xavier"
1480 | }
1481 | bias_filler {
1482 | type: "constant"
1483 | value: 0
1484 | }
1485 | }
1486 | }
1487 | layer {
1488 | name: "conv8_2_mbox_loc_perm"
1489 | type: "Permute"
1490 | bottom: "conv8_2_mbox_loc"
1491 | top: "conv8_2_mbox_loc_perm"
1492 | permute_param {
1493 | order: 0
1494 | order: 2
1495 | order: 3
1496 | order: 1
1497 | }
1498 | }
1499 | layer {
1500 | name: "conv8_2_mbox_loc_flat"
1501 | type: "Flatten"
1502 | bottom: "conv8_2_mbox_loc_perm"
1503 | top: "conv8_2_mbox_loc_flat"
1504 | flatten_param {
1505 | axis: 1
1506 | }
1507 | }
1508 | layer {
1509 | name: "conv8_2_mbox_conf"
1510 | type: "Convolution"
1511 | bottom: "conv8_2_h"
1512 | top: "conv8_2_mbox_conf"
1513 | param {
1514 | lr_mult: 1
1515 | decay_mult: 1
1516 | }
1517 | param {
1518 | lr_mult: 2
1519 | decay_mult: 0
1520 | }
1521 | convolution_param {
1522 | num_output: 8 # 84
1523 | pad: 1
1524 | kernel_size: 3
1525 | stride: 1
1526 | weight_filler {
1527 | type: "xavier"
1528 | }
1529 | bias_filler {
1530 | type: "constant"
1531 | value: 0
1532 | }
1533 | }
1534 | }
1535 | layer {
1536 | name: "conv8_2_mbox_conf_perm"
1537 | type: "Permute"
1538 | bottom: "conv8_2_mbox_conf"
1539 | top: "conv8_2_mbox_conf_perm"
1540 | permute_param {
1541 | order: 0
1542 | order: 2
1543 | order: 3
1544 | order: 1
1545 | }
1546 | }
1547 | layer {
1548 | name: "conv8_2_mbox_conf_flat"
1549 | type: "Flatten"
1550 | bottom: "conv8_2_mbox_conf_perm"
1551 | top: "conv8_2_mbox_conf_flat"
1552 | flatten_param {
1553 | axis: 1
1554 | }
1555 | }
1556 | layer {
1557 | name: "conv8_2_mbox_priorbox"
1558 | type: "PriorBox"
1559 | bottom: "conv8_2_h"
1560 | bottom: "data"
1561 | top: "conv8_2_mbox_priorbox"
1562 | prior_box_param {
1563 | min_size: 213.0
1564 | max_size: 264.0
1565 | aspect_ratio: 2
1566 | flip: true
1567 | clip: false
1568 | variance: 0.1
1569 | variance: 0.1
1570 | variance: 0.2
1571 | variance: 0.2
1572 | step: 100
1573 | offset: 0.5
1574 | }
1575 | }
1576 | layer {
1577 | name: "conv9_2_mbox_loc"
1578 | type: "Convolution"
1579 | bottom: "conv9_2_h"
1580 | top: "conv9_2_mbox_loc"
1581 | param {
1582 | lr_mult: 1
1583 | decay_mult: 1
1584 | }
1585 | param {
1586 | lr_mult: 2
1587 | decay_mult: 0
1588 | }
1589 | convolution_param {
1590 | num_output: 16
1591 | pad: 1
1592 | kernel_size: 3
1593 | stride: 1
1594 | weight_filler {
1595 | type: "xavier"
1596 | }
1597 | bias_filler {
1598 | type: "constant"
1599 | value: 0
1600 | }
1601 | }
1602 | }
1603 | layer {
1604 | name: "conv9_2_mbox_loc_perm"
1605 | type: "Permute"
1606 | bottom: "conv9_2_mbox_loc"
1607 | top: "conv9_2_mbox_loc_perm"
1608 | permute_param {
1609 | order: 0
1610 | order: 2
1611 | order: 3
1612 | order: 1
1613 | }
1614 | }
1615 | layer {
1616 | name: "conv9_2_mbox_loc_flat"
1617 | type: "Flatten"
1618 | bottom: "conv9_2_mbox_loc_perm"
1619 | top: "conv9_2_mbox_loc_flat"
1620 | flatten_param {
1621 | axis: 1
1622 | }
1623 | }
1624 | layer {
1625 | name: "conv9_2_mbox_conf"
1626 | type: "Convolution"
1627 | bottom: "conv9_2_h"
1628 | top: "conv9_2_mbox_conf"
1629 | param {
1630 | lr_mult: 1
1631 | decay_mult: 1
1632 | }
1633 | param {
1634 | lr_mult: 2
1635 | decay_mult: 0
1636 | }
1637 | convolution_param {
1638 | num_output: 8 # 84
1639 | pad: 1
1640 | kernel_size: 3
1641 | stride: 1
1642 | weight_filler {
1643 | type: "xavier"
1644 | }
1645 | bias_filler {
1646 | type: "constant"
1647 | value: 0
1648 | }
1649 | }
1650 | }
1651 | layer {
1652 | name: "conv9_2_mbox_conf_perm"
1653 | type: "Permute"
1654 | bottom: "conv9_2_mbox_conf"
1655 | top: "conv9_2_mbox_conf_perm"
1656 | permute_param {
1657 | order: 0
1658 | order: 2
1659 | order: 3
1660 | order: 1
1661 | }
1662 | }
1663 | layer {
1664 | name: "conv9_2_mbox_conf_flat"
1665 | type: "Flatten"
1666 | bottom: "conv9_2_mbox_conf_perm"
1667 | top: "conv9_2_mbox_conf_flat"
1668 | flatten_param {
1669 | axis: 1
1670 | }
1671 | }
1672 | layer {
1673 | name: "conv9_2_mbox_priorbox"
1674 | type: "PriorBox"
1675 | bottom: "conv9_2_h"
1676 | bottom: "data"
1677 | top: "conv9_2_mbox_priorbox"
1678 | prior_box_param {
1679 | min_size: 264.0
1680 | max_size: 315.0
1681 | aspect_ratio: 2
1682 | flip: true
1683 | clip: false
1684 | variance: 0.1
1685 | variance: 0.1
1686 | variance: 0.2
1687 | variance: 0.2
1688 | step: 300
1689 | offset: 0.5
1690 | }
1691 | }
1692 | layer {
1693 | name: "mbox_loc"
1694 | type: "Concat"
1695 | bottom: "conv4_3_norm_mbox_loc_flat"
1696 | bottom: "fc7_mbox_loc_flat"
1697 | bottom: "conv6_2_mbox_loc_flat"
1698 | bottom: "conv7_2_mbox_loc_flat"
1699 | bottom: "conv8_2_mbox_loc_flat"
1700 | bottom: "conv9_2_mbox_loc_flat"
1701 | top: "mbox_loc"
1702 | concat_param {
1703 | axis: 1
1704 | }
1705 | }
1706 | layer {
1707 | name: "mbox_conf"
1708 | type: "Concat"
1709 | bottom: "conv4_3_norm_mbox_conf_flat"
1710 | bottom: "fc7_mbox_conf_flat"
1711 | bottom: "conv6_2_mbox_conf_flat"
1712 | bottom: "conv7_2_mbox_conf_flat"
1713 | bottom: "conv8_2_mbox_conf_flat"
1714 | bottom: "conv9_2_mbox_conf_flat"
1715 | top: "mbox_conf"
1716 | concat_param {
1717 | axis: 1
1718 | }
1719 | }
1720 | layer {
1721 | name: "mbox_priorbox"
1722 | type: "Concat"
1723 | bottom: "conv4_3_norm_mbox_priorbox"
1724 | bottom: "fc7_mbox_priorbox"
1725 | bottom: "conv6_2_mbox_priorbox"
1726 | bottom: "conv7_2_mbox_priorbox"
1727 | bottom: "conv8_2_mbox_priorbox"
1728 | bottom: "conv9_2_mbox_priorbox"
1729 | top: "mbox_priorbox"
1730 | concat_param {
1731 | axis: 2
1732 | }
1733 | }
1734 |
1735 | layer {
1736 | name: "mbox_conf_reshape"
1737 | type: "Reshape"
1738 | bottom: "mbox_conf"
1739 | top: "mbox_conf_reshape"
1740 | reshape_param {
1741 | shape {
1742 | dim: 0
1743 | dim: -1
1744 | dim: 2
1745 | }
1746 | }
1747 | }
1748 | layer {
1749 | name: "mbox_conf_softmax"
1750 | type: "Softmax"
1751 | bottom: "mbox_conf_reshape"
1752 | top: "mbox_conf_softmax"
1753 | softmax_param {
1754 | axis: 2
1755 | }
1756 | }
1757 | layer {
1758 | name: "mbox_conf_flatten"
1759 | type: "Flatten"
1760 | bottom: "mbox_conf_softmax"
1761 | top: "mbox_conf_flatten"
1762 | flatten_param {
1763 | axis: 1
1764 | }
1765 | }
1766 |
1767 | layer {
1768 | name: "detection_out"
1769 | type: "DetectionOutput"
1770 | bottom: "mbox_loc"
1771 | bottom: "mbox_conf_flatten"
1772 | bottom: "mbox_priorbox"
1773 | top: "detection_out"
1774 | include {
1775 | phase: TEST
1776 | }
1777 | detection_output_param {
1778 | num_classes: 2
1779 | share_location: true
1780 | background_label_id: 0
1781 | nms_param {
1782 | nms_threshold: 0.45
1783 | top_k: 400
1784 | }
1785 | code_type: CENTER_SIZE
1786 | keep_top_k: 200
1787 | confidence_threshold: 0.01
1788 | }
1789 | }
1790 |
--------------------------------------------------------------------------------
/model_face_detection/model_architecture_visualization.py:
--------------------------------------------------------------------------------
1 |
2 | # 网络架构可视化
3 |
4 | """
5 | 1.
6 | 将prototxt文件内容拷贝到网页中,shift+enter显示网络结构
7 | https://ethereon.github.io/netscope/#/editor
8 |
9 | 2.
10 | https://transcranial.github.io/keras-js/#/inception-v3
11 |
12 | 3.
13 | https://github.com/lutzroeder/Netron
14 | """
--------------------------------------------------------------------------------
/model_face_detection/res10_300x300_ssd_iter_140000.caffemodel:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/model_face_detection/res10_300x300_ssd_iter_140000.caffemodel
--------------------------------------------------------------------------------
/model_face_detection/resnet-ssd-deploy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/model_face_detection/resnet-ssd-deploy.png
--------------------------------------------------------------------------------
/model_face_detection/resnet-ssd-deploy2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/model_face_detection/resnet-ssd-deploy2.png
--------------------------------------------------------------------------------
/model_facenet/openface_nn4.small2.v1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/model_facenet/openface_nn4.small2.v1.png
--------------------------------------------------------------------------------
/model_facenet/openface_nn4.small2.v1.t7:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/model_facenet/openface_nn4.small2.v1.t7
--------------------------------------------------------------------------------
/mysql_table/facerecognition.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Navicat Premium Data Transfer
3 |
4 | Source Server : MySQL
5 | Source Server Type : MySQL
6 | Source Server Version : 80012
7 | Source Host : localhost:3306
8 | Source Schema : facerecognition
9 |
10 | Target Server Type : MySQL
11 | Target Server Version : 80012
12 | File Encoding : 65001
13 |
14 | Date: 27/05/2021 13:55:36
15 | */
16 |
17 | SET NAMES utf8mb4;
18 | SET FOREIGN_KEY_CHECKS = 0;
19 |
20 | -- ----------------------------
21 | -- Table structure for checkin
22 | -- ----------------------------
23 | DROP TABLE IF EXISTS `checkin`;
24 | CREATE TABLE `checkin` (
25 | `Name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
26 | `ID` int(11) NULL DEFAULT NULL,
27 | `Class` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
28 | `Time` datetime NULL DEFAULT NULL,
29 | `Description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
30 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
31 |
32 | -- ----------------------------
33 | -- Records of checkin
34 | -- ----------------------------
35 | INSERT INTO `checkin` VALUES ('Messi', 10, '2020001', '2020-05-25 00:20:27', '迟到');
36 | INSERT INTO `checkin` VALUES ('Messi', 10, '2020001', '2021-05-27 01:20:59', '旷课');
37 | INSERT INTO `checkin` VALUES ('Messi', 10, '2020001', '2021-05-27 03:35:03', '旷课');
38 | INSERT INTO `checkin` VALUES ('Messi', 10, '2020001', '2021-05-27 08:58:47', '旷课');
39 | INSERT INTO `checkin` VALUES ('Messi', 10, '2020001', '2021-05-27 10:19:34', '旷课');
40 |
41 | -- ----------------------------
42 | -- Table structure for studentnums
43 | -- ----------------------------
44 | DROP TABLE IF EXISTS `studentnums`;
45 | CREATE TABLE `studentnums` (
46 | `Class` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
47 | `Num` int(11) NULL DEFAULT NULL
48 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
49 |
50 | -- ----------------------------
51 | -- Records of studentnums
52 | -- ----------------------------
53 | INSERT INTO `studentnums` VALUES ('2020001', 23);
54 | INSERT INTO `studentnums` VALUES ('2020002', 24);
55 |
56 | -- ----------------------------
57 | -- Table structure for students
58 | -- ----------------------------
59 | DROP TABLE IF EXISTS `students`;
60 | CREATE TABLE `students` (
61 | `ID` int(11) NOT NULL,
62 | `Name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
63 | `Class` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
64 | `Sex` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
65 | `Birthday` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
66 | PRIMARY KEY (`ID`) USING BTREE
67 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
68 |
69 | -- ----------------------------
70 | -- Records of students
71 | -- ----------------------------
72 | INSERT INTO `students` VALUES (1, 'TerStegen', '2020001', 'male', '19920430');
73 | INSERT INTO `students` VALUES (2, 'Dest', '2020002', 'male', '20001103');
74 | INSERT INTO `students` VALUES (3, 'Pique', '2020001', 'male', '19870202');
75 | INSERT INTO `students` VALUES (4, 'Araújo', '2020002', 'male', '19990307');
76 | INSERT INTO `students` VALUES (5, 'Busquets', '2020001', 'male', '19880716');
77 | INSERT INTO `students` VALUES (6, 'Wijnaldum', '2020002', 'male', '19901111');
78 | INSERT INTO `students` VALUES (7, 'Griezmann', '2020001', 'male', '19910321');
79 | INSERT INTO `students` VALUES (9, 'Kun', '2020002', 'male', '19880602');
80 | INSERT INTO `students` VALUES (10, 'Messi', '2020001', 'male', '19870624');
81 | INSERT INTO `students` VALUES (11, 'Dembélé', '2020001', 'male', '19970515');
82 | INSERT INTO `students` VALUES (12, 'Depay', '2020002', 'male', '19940213');
83 | INSERT INTO `students` VALUES (13, 'Ignacio', '2020002', 'male', '19990302');
84 | INSERT INTO `students` VALUES (14, 'Coutinho', '2020001', 'male', '19920612');
85 | INSERT INTO `students` VALUES (15, 'Lenglet', '2020002', 'male', '19950617');
86 | INSERT INTO `students` VALUES (16, 'Pedri', '2020001', 'male', '20021125');
87 | INSERT INTO `students` VALUES (17, 'Emerson ', '2020001', 'male', '19990114');
88 | INSERT INTO `students` VALUES (18, 'Alba', '2020001', 'male', '19890321');
89 | INSERT INTO `students` VALUES (21, 'Frenkie', '2020001', 'male', '19970512');
90 | INSERT INTO `students` VALUES (22, 'AnsuFati', '2020002', 'male', '20021031');
91 | INSERT INTO `students` VALUES (23, ' Garcia', '2020002', 'male', '20010109');
92 | INSERT INTO `students` VALUES (27, 'Moriba', '2020002', 'male', '20030119');
93 |
94 | SET FOREIGN_KEY_CHECKS = 1;
95 |
96 | -- Table structure for detail
97 | -- ----------------------------
98 | DROP TABLE IF EXISTS `detail`;
99 | CREATE TABLE `studentnums` (
100 | `ID` int(11) NOT NULL,
101 | `Name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
102 | `Emo` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
103 | `Time` datetime NULL DEFAULT NULL,
104 | ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
105 |
106 | -- ----------------------------
107 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/requirements.txt
--------------------------------------------------------------------------------
/saved_weights/embeddings.pickle:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/saved_weights/embeddings.pickle
--------------------------------------------------------------------------------
/saved_weights/le.pickle:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/saved_weights/le.pickle
--------------------------------------------------------------------------------
/saved_weights/recognizer.pickle:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/saved_weights/recognizer.pickle
--------------------------------------------------------------------------------
/ui/RandomCheckUI.py:
--------------------------------------------------------------------------------
1 | from PyQt5 import QtCore, QtGui, QtWidgets
2 |
3 |
4 | class Ui_Form(object):
5 | def setupUi(self, Form):
6 | Form.setObjectName("Form")
7 | Form.resize(480, 232)
8 | self.pb_success = QtWidgets.QPushButton(Form)
9 | self.pb_success.setGeometry(QtCore.QRect(30, 160, 101, 41))
10 | self.pb_success.setObjectName("pb_success") # 成功回答
11 | self.label = QtWidgets.QLabel(Form) # 姓名
12 | self.label.setGeometry(QtCore.QRect(220, 90, 51, 41))
13 | self.label.setObjectName("label")
14 | self.pb_fail = QtWidgets.QPushButton(Form)
15 | self.pb_fail.setGeometry(QtCore.QRect(200, 160, 101, 41))
16 | self.pb_fail.setObjectName("pb_fail") # 回答失败
17 | self.label_id = QtWidgets.QLabel(Form) # 学号
18 | self.label_id.setGeometry(QtCore.QRect(30, 90, 51, 41))
19 | self.label_id.setObjectName("label_id")
20 | self.pb_other = QtWidgets.QPushButton(Form) # 退出
21 | self.pb_other.setGeometry(QtCore.QRect(370, 160, 81, 41))
22 | self.pb_other.setObjectName("pb_other")
23 | self.lcdNumber_id = QtWidgets.QLCDNumber(Form)
24 | self.lcdNumber_id.setGeometry(QtCore.QRect(100, 90, 101, 41)) # 学号输出框
25 | self.lcdNumber_id.setObjectName("lcdNumber_id")
26 | self.pb_start = QtWidgets.QPushButton(Form) # 开始筛选幸运观众
27 | self.pb_start.setGeometry(QtCore.QRect(180, 20, 271, 41))
28 | self.pb_start.setObjectName("pb_start")
29 | self.pb_connect_db = QtWidgets.QPushButton(Form) # 连接数据库
30 | self.pb_connect_db.setGeometry(QtCore.QRect(30, 20, 131, 41))
31 | self.pb_connect_db.setObjectName("pb_connect_db")
32 | self.textBrowser_name = QtWidgets.QTextBrowser(Form)
33 | self.textBrowser_name.setGeometry(QtCore.QRect(280, 90, 181, 41)) # 姓名输出框
34 | self.textBrowser_name.setObjectName("textBrowser_name")
35 |
36 | self.retranslateUi(Form)
37 | QtCore.QMetaObject.connectSlotsByName(Form)
38 |
39 | def retranslateUi(self, Form):
40 | _translate = QtCore.QCoreApplication.translate
41 | Form.setWindowTitle(_translate("Form", "Form"))
42 | self.pb_success.setText(_translate("Form", "成功回答"))
43 | self.label.setText(_translate("Form", "姓名"))
44 | self.pb_fail.setText(_translate("Form", "答题失败"))
45 | self.label_id.setText(_translate("Form", "学号"))
46 | self.pb_other.setText(_translate("Form", "退出"))
47 | self.pb_start.setText(_translate("Form", "开始筛选幸运观众"))
48 | self.pb_connect_db.setText(_translate("Form", "连接数据库"))
49 |
50 |
51 | if __name__ == "__main__":
52 | import sys
53 | app = QtWidgets.QApplication(sys.argv)
54 | Form = QtWidgets.QWidget()
55 | ui = Ui_Form()
56 | ui.setupUi(Form)
57 | Form.show()
58 | sys.exit(app.exec_())
59 |
--------------------------------------------------------------------------------
/ui/RandomCheckUI.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Form
4 |
5 |
6 |
7 | 0
8 | 0
9 | 480
10 | 232
11 |
12 |
13 |
14 | Form
15 |
16 |
17 |
18 |
19 | 30
20 | 160
21 | 101
22 | 41
23 |
24 |
25 |
26 | 成功回答
27 |
28 |
29 |
30 |
31 |
32 | 270
33 | 90
34 | 31
35 | 41
36 |
37 |
38 |
39 | 姓名
40 |
41 |
42 |
43 |
44 |
45 | 150
46 | 160
47 | 101
48 | 41
49 |
50 |
51 |
52 | 答题失败
53 |
54 |
55 |
56 |
57 |
58 | 40
59 | 90
60 | 31
61 | 41
62 |
63 |
64 |
65 | 学号
66 |
67 |
68 |
69 |
70 |
71 | 370
72 | 160
73 | 81
74 | 41
75 |
76 |
77 |
78 | 其他
79 |
80 |
81 |
82 |
83 |
84 | 280
85 | 90
86 | 171
87 | 31
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 | 80
98 | 90
99 | 171
100 | 41
101 |
102 |
103 |
104 |
105 |
106 |
107 | 150
108 | 20
109 | 301
110 | 41
111 |
112 |
113 |
114 | 开始筛选幸运观众
115 |
116 |
117 |
118 |
119 |
120 | 30
121 | 20
122 | 101
123 | 41
124 |
125 |
126 |
127 | 连接数据库
128 |
129 |
130 |
131 |
132 |
133 | 310
134 | 90
135 | 141
136 | 41
137 |
138 |
139 |
140 |
141 |
142 |
143 | 270
144 | 160
145 | 81
146 | 41
147 |
148 |
149 |
150 | 未到
151 |
152 |
153 |
154 |
155 |
156 |
157 |
--------------------------------------------------------------------------------
/ui/__pycache__/RandomCheckUI.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/ui/__pycache__/RandomCheckUI.cpython-38.pyc
--------------------------------------------------------------------------------
/ui/__pycache__/detail.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/ui/__pycache__/detail.cpython-38.pyc
--------------------------------------------------------------------------------
/ui/__pycache__/infoUI.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/ui/__pycache__/infoUI.cpython-38.pyc
--------------------------------------------------------------------------------
/ui/__pycache__/main.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/ui/__pycache__/main.cpython-36.pyc
--------------------------------------------------------------------------------
/ui/__pycache__/main.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/ui/__pycache__/main.cpython-38.pyc
--------------------------------------------------------------------------------
/ui/__pycache__/mainwindow.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/ui/__pycache__/mainwindow.cpython-38.pyc
--------------------------------------------------------------------------------
/ui/detail.py:
--------------------------------------------------------------------------------
1 | from PyQt5 import QtCore, QtGui, QtWidgets
2 |
3 |
4 | class Ui_Form(object):
5 | def setupUi(self, Form):
6 | Form.setObjectName("Form")
7 | Form.resize(1060, 560)
8 |
9 | self.pb_other = QtWidgets.QPushButton(Form) # 查询详情
10 | self.pb_other.setGeometry(QtCore.QRect(240, 500, 101, 41))
11 | self.pb_other.setObjectName("pb_other")
12 | self.pb_exit = QtWidgets.QPushButton(Form) # 退出
13 | self.pb_exit.setGeometry(QtCore.QRect(640, 500, 101, 41))
14 | self.pb_exit.setObjectName("pb_exit")
15 | self.tableView = QtWidgets.QTableView(Form) # 查询数据库所有结果框
16 | self.tableView.setGeometry(QtCore.QRect(100, 30, 841, 441))
17 | self.tableView.setObjectName("tableView")
18 |
19 | self.retranslateUi(Form)
20 | QtCore.QMetaObject.connectSlotsByName(Form)
21 |
22 | def retranslateUi(self, Form):
23 | _translate = QtCore.QCoreApplication.translate
24 | Form.setWindowTitle(_translate("Form", "Form"))
25 | self.pb_other.setText(_translate("Form", "刷新"))
26 | self.pb_exit.setText(_translate("Form", "退出"))
27 |
28 |
29 | if __name__ == "__main__":
30 | import sys
31 | app = QtWidgets.QApplication(sys.argv)
32 | Form = QtWidgets.QWidget()
33 | ui = Ui_Form()
34 | ui.setupUi(Form)
35 | Form.show()
36 | sys.exit(app.exec_())
37 |
--------------------------------------------------------------------------------
/ui/infoUI.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'InfoUI.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.15.4
6 | #
7 | # WARNING: Any manual changes made to this file will be lost when pyuic5 is
8 | # run again. Do not edit this file unless you know what you are doing.
9 |
10 |
11 | from PyQt5 import QtCore, QtGui, QtWidgets
12 |
13 |
14 | class Ui_Form(object):
15 | def setupUi(self, Form):
16 | Form.setObjectName("Form")
17 | Form.resize(760, 560)
18 | Form.setMinimumSize(QtCore.QSize(760, 560))
19 | Form.setMaximumSize(QtCore.QSize(760, 560))
20 | self.bt_start_collect = QtWidgets.QPushButton(Form) # 开始采集
21 | self.bt_start_collect.setGeometry(QtCore.QRect(10, 460, 131, 91))
22 | self.bt_start_collect.setObjectName("bt_start_collect")
23 | self.label_title = QtWidgets.QLabel(Form) # 人脸识别个人信息采集系统
24 | self.label_title.setGeometry(QtCore.QRect(130, 10, 291, 20))
25 | self.label_title.setObjectName("label_title")
26 | self.label_capture = QtWidgets.QLabel(Form)
27 | self.label_capture.setGeometry(QtCore.QRect(10, 40, 500, 400))
28 | self.label_capture.setMinimumSize(QtCore.QSize(500, 400))
29 | self.label_capture.setMaximumSize(QtCore.QSize(500, 400))
30 | self.label_capture.setText("")
31 | self.label_capture.setObjectName("label_capture")
32 | self.bt_take_photo = QtWidgets.QPushButton(Form) # 拍照
33 | self.bt_take_photo.setGeometry(QtCore.QRect(150, 510, 151, 41))
34 | self.bt_take_photo.setObjectName("bt_take_photo")
35 | self.bt_exit = QtWidgets.QPushButton(Form) # 拍照
36 | self.bt_exit.setGeometry(QtCore.QRect(350, 510, 151, 41))
37 | self.bt_exit.setObjectName("bt_exit")
38 | self.tableView = QtWidgets.QTableView(Form) # 查询数据库所有结果框
39 | self.tableView.setGeometry(QtCore.QRect(530, 30, 221, 441))
40 | self.tableView.setObjectName("tableView")
41 | self.lcdNumber_collection_nums = QtWidgets.QLCDNumber(Form) # 已采集数
42 | self.lcdNumber_collection_nums.setGeometry(QtCore.QRect(430, 470, 71, 31))
43 | self.lcdNumber_collection_nums.setObjectName("lcdNumber_collection_nums")
44 | self.label_collected = QtWidgets.QLabel(Form) # 已采集
45 | self.label_collected.setGeometry(QtCore.QRect(350, 475, 81, 21))
46 | self.label_collected.setObjectName("label_collected_num")
47 | self.label_collected_num = QtWidgets.QLabel(Form) # 采集数目
48 | self.label_collected_num.setGeometry(QtCore.QRect(140, 475, 101, 21))
49 | self.label_collected_num.setObjectName("label_collected_num")
50 | self.spinBox_set_num = QtWidgets.QSpinBox(Form) # 采集数设置
51 | self.spinBox_set_num.setGeometry(QtCore.QRect(250, 471, 81, 31))
52 | self.spinBox_set_num.setObjectName("spinBox_set_num")
53 | self.checkBox_auto_collect = QtWidgets.QCheckBox(Form) # 自动采集
54 | self.checkBox_auto_collect.setGeometry(QtCore.QRect(150, 450, 171, 21))
55 | self.checkBox_auto_collect.setObjectName("checkBox_auto_collect")
56 | self.bt_check_dirs_faces = QtWidgets.QPushButton(Form)
57 | self.bt_check_dirs_faces.setGeometry(QtCore.QRect(530, 490, 221, 61))
58 | self.bt_check_dirs_faces.setObjectName("bt_check_dirs_faces")
59 | self.bt_start_collect.raise_()
60 | self.label_title.raise_()
61 | self.label_capture.raise_()
62 | self.bt_take_photo.raise_()
63 | self.bt_exit.raise_()
64 | self.tableView.raise_()
65 | self.lcdNumber_collection_nums.raise_()
66 | self.label_collected.raise_()
67 | self.label_collected_num.raise_()
68 | self.spinBox_set_num.raise_()
69 | self.checkBox_auto_collect.raise_()
70 | self.bt_check_dirs_faces.raise_()
71 |
72 | self.retranslateUi(Form)
73 | QtCore.QMetaObject.connectSlotsByName(Form)
74 | # Form.setTabOrder控件顺序
75 | Form.setTabOrder(self.bt_start_collect, self.checkBox_auto_collect)
76 | Form.setTabOrder(self.checkBox_auto_collect, self.spinBox_set_num)
77 | Form.setTabOrder(self.spinBox_set_num, self.bt_take_photo)
78 | Form.setTabOrder(self.bt_take_photo, self.bt_exit)
79 | Form.setTabOrder(self.bt_exit, self.tableView)
80 | Form.setTabOrder(self.tableView, self.bt_check_dirs_faces)
81 |
82 | def retranslateUi(self, Form):
83 | _translate = QtCore.QCoreApplication.translate
84 | Form.setWindowTitle(_translate("Form", "Form"))
85 | self.bt_start_collect.setText(_translate("Form", "开始采集"))
86 | self.label_title.setText(_translate("Form", "人脸识别个人信息采集系统"))
87 | self.bt_take_photo.setText(_translate("Form", "拍照"))
88 | self.bt_exit.setText(_translate("Form", "退出"))
89 | self.label_collected.setText(_translate("Form", "已采集"))
90 | self.label_collected_num.setText(_translate("Form", "采集数目"))
91 | self.checkBox_auto_collect.setText(_translate("Form", "自动采集"))
92 | self.bt_check_dirs_faces.setText(_translate("Form", "查询所有已采集数据"))
93 |
94 |
95 | if __name__ == "__main__":
96 | import sys
97 | app = QtWidgets.QApplication(sys.argv)
98 | Form = QtWidgets.QWidget()
99 | ui = Ui_Form()
100 | ui.setupUi(Form)
101 | Form.show()
102 | sys.exit(app.exec_())
103 |
--------------------------------------------------------------------------------
/ui/infoUI.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Form
4 |
5 |
6 |
7 | 0
8 | 0
9 | 760
10 | 560
11 |
12 |
13 |
14 |
15 | 760
16 | 560
17 |
18 |
19 |
20 |
21 | 760
22 | 560
23 |
24 |
25 |
26 | Form
27 |
28 |
29 |
30 |
31 | 530
32 | 70
33 | 71
34 | 21
35 |
36 |
37 |
38 | 请输入姓名:
39 |
40 |
41 |
42 |
43 |
44 | 530
45 | 100
46 | 71
47 | 21
48 |
49 |
50 |
51 | 请输入班级:
52 |
53 |
54 |
55 |
56 |
57 | 530
58 | 40
59 | 71
60 | 21
61 |
62 |
63 |
64 | 请输入学号:
65 |
66 |
67 |
68 |
69 |
70 | 310
71 | 510
72 | 211
73 | 41
74 |
75 |
76 |
77 | 添加或修改信息(DB)
78 |
79 |
80 |
81 |
82 |
83 | 10
84 | 460
85 | 131
86 | 91
87 |
88 |
89 |
90 | 开始采集
91 |
92 |
93 |
94 |
95 |
96 | 170
97 | 10
98 | 251
99 | 16
100 |
101 |
102 |
103 | 人脸识别个人信息采集系统
104 |
105 |
106 |
107 |
108 |
109 | 310
110 | 460
111 | 101
112 | 41
113 |
114 |
115 |
116 | 查询信息(DB)
117 |
118 |
119 |
120 |
121 |
122 | 530
123 | 130
124 | 71
125 | 21
126 |
127 |
128 |
129 | 请输入性别:
130 |
131 |
132 |
133 |
134 |
135 | 530
136 | 160
137 | 71
138 | 21
139 |
140 |
141 |
142 | 请输入生日:
143 |
144 |
145 |
146 |
147 |
148 | 10
149 | 40
150 | 500
151 | 400
152 |
153 |
154 |
155 |
156 | 500
157 | 400
158 |
159 |
160 |
161 |
162 | 500
163 | 400
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 | 150
174 | 510
175 | 151
176 | 41
177 |
178 |
179 |
180 | 拍照
181 |
182 |
183 |
184 |
185 |
186 | 610
187 | 40
188 | 141
189 | 21
190 |
191 |
192 |
193 |
194 |
195 |
196 | 610
197 | 70
198 | 141
199 | 21
200 |
201 |
202 |
203 |
204 |
205 |
206 | 610
207 | 100
208 | 141
209 | 21
210 |
211 |
212 |
213 |
214 |
215 |
216 | 610
217 | 130
218 | 141
219 | 21
220 |
221 |
222 |
223 |
224 |
225 |
226 | 610
227 | 160
228 | 141
229 | 21
230 |
231 |
232 |
233 |
234 |
235 |
236 | 530
237 | 190
238 | 221
239 | 291
240 |
241 |
242 |
243 |
244 |
245 |
246 | 230
247 | 470
248 | 71
249 | 31
250 |
251 |
252 |
253 |
254 |
255 |
256 | 260
257 | 450
258 | 41
259 | 21
260 |
261 |
262 |
263 | 已采集
264 |
265 |
266 |
267 |
268 |
269 | 150
270 | 471
271 | 71
272 | 31
273 |
274 |
275 |
276 |
277 |
278 |
279 | 150
280 | 450
281 | 71
282 | 21
283 |
284 |
285 |
286 | 自动采集
287 |
288 |
289 |
290 |
291 |
292 | 420
293 | 460
294 | 101
295 | 41
296 |
297 |
298 |
299 | 查询人脸数量
300 |
301 |
302 |
303 |
304 |
305 | 530
306 | 490
307 | 221
308 | 61
309 |
310 |
311 |
312 | 查询数据中所有人脸数量
313 |
314 |
315 | label_name
316 | label_class
317 | label_id
318 | bt_start_collect
319 | label_title
320 | bt_check_info
321 | label_sex
322 | label_birth
323 | bt_change_info
324 | label_capture
325 | bt_take_photo
326 | lineEdit_id
327 | lineEdit_name
328 | lineEdit_class
329 | lineEdit_sex
330 | lineEdit_birth
331 | tableView
332 | lcdNumber_collection_nums
333 | label_collected
334 | spinBox_set_num
335 | checkBox_auto_collect
336 | bt_check_id_faces
337 | bt_check_dirs_faces
338 |
339 |
340 | bt_start_collect
341 | checkBox_auto_collect
342 | spinBox_set_num
343 | bt_take_photo
344 | lineEdit_id
345 | lineEdit_name
346 | lineEdit_class
347 | lineEdit_sex
348 | lineEdit_birth
349 | bt_check_info
350 | bt_change_info
351 | bt_check_id_faces
352 | tableView
353 | bt_check_dirs_faces
354 |
355 |
356 |
357 |
358 |
--------------------------------------------------------------------------------
/ui/mainwindow.py:
--------------------------------------------------------------------------------
1 | from PyQt5 import QtCore, QtGui, QtWidgets
2 |
3 |
4 | class Ui_MainWindow(object):
5 | def setupUi(self, MainWindow):
6 | MainWindow.setObjectName("MainWindow")
7 | MainWindow.resize(1086, 907)
8 | self.centralwidget = QtWidgets.QWidget(MainWindow)
9 | self.centralwidget.setObjectName("centralwidget")
10 | self.label_camera = QtWidgets.QLabel(self.centralwidget) # 未打开相机的黑色界面
11 | self.label_camera.setGeometry(QtCore.QRect(30, 80, 800, 600))
12 | self.label_camera.setText("")
13 | self.label_camera.setObjectName("label_camera")
14 | self.label_time = QtWidgets.QLabel(self.centralwidget) # 显示时间
15 | self.label_time.setGeometry(QtCore.QRect(850, 20, 231, 30))
16 | self.label_time.setText("")
17 | self.label_time.setObjectName("label_time")
18 | self.bt_random_check = QtWidgets.QPushButton(self.centralwidget) # 随机抽签
19 | self.bt_random_check.setGeometry(QtCore.QRect(860, 740, 211, 41))
20 | self.bt_random_check.setObjectName("bt_random_check")
21 | self.bt_supplement = QtWidgets.QPushButton(self.centralwidget) # 漏签补签
22 | self.bt_supplement.setGeometry(QtCore.QRect(970, 700, 101, 31))
23 | self.bt_supplement.setObjectName("bt_supplement")
24 | self.line_1 = QtWidgets.QFrame(self.centralwidget)
25 | self.line_1.setGeometry(QtCore.QRect(150, 690, 31, 131))
26 | self.line_1.setFrameShape(QtWidgets.QFrame.VLine)
27 | self.line_1.setFrameShadow(QtWidgets.QFrame.Sunken)
28 | self.line_1.setObjectName("line_1")
29 | self.lineEdit_supplement = QtWidgets.QLineEdit(self.centralwidget) # 漏签补签输入框
30 | self.lineEdit_supplement.setGeometry(QtCore.QRect(860, 700, 101, 31))
31 | self.lineEdit_supplement.setObjectName("lineEdit_supplement")
32 | self.textBrowser_log = QtWidgets.QTextBrowser(self.centralwidget)
33 | self.textBrowser_log.setGeometry(QtCore.QRect(350, 690, 301, 161))
34 | self.textBrowser_log.setObjectName("textBrowser_log")
35 | self.progressBar = QtWidgets.QProgressBar(self.centralwidget)
36 | self.progressBar.setGeometry(QtCore.QRect(30, 833, 301, 16))
37 | self.progressBar.setProperty("value", 24)
38 | self.progressBar.setObjectName("progressBar")
39 | self.bt_start_check = QtWidgets.QPushButton(self.centralwidget) # 开始分析
40 | self.bt_start_check.setGeometry(QtCore.QRect(180, 760, 151, 61))
41 | self.bt_start_check.setObjectName("bt_start_check")
42 | self.bt_generator = QtWidgets.QPushButton(self.centralwidget) # 训练模型
43 | self.bt_generator.setGeometry(QtCore.QRect(180, 690, 151, 61))
44 | self.bt_generator.setObjectName("bt_generator")
45 | self.bt_analyse = QtWidgets.QPushButton(self.centralwidget) # 分析详情
46 | self.bt_analyse.setGeometry(QtCore.QRect(660, 760, 181, 61))
47 | self.bt_analyse.setObjectName("bt_analyse")
48 | self.tableView_escape = QtWidgets.QTableView(self.centralwidget) # 未到记录表
49 | self.tableView_escape.setGeometry(QtCore.QRect(860, 450, 211,201))
50 | self.tableView_escape.setObjectName("tableView_escape")
51 | self.bt_check_variation = QtWidgets.QPushButton(self.centralwidget) # 核验数据库
52 | self.bt_check_variation.setGeometry(QtCore.QRect(20, 760, 131, 61))
53 | self.bt_check_variation.setObjectName("bt_check_variation")
54 | self.bt_open_camera = QtWidgets.QPushButton(self.centralwidget) # 打开相机
55 | self.bt_open_camera.setGeometry(QtCore.QRect(660, 690, 181, 61))
56 | self.bt_open_camera.setObjectName("bt_open_camera")
57 | self.label_title = QtWidgets.QLabel(self.centralwidget) # 标题
58 | self.label_title.setGeometry(QtCore.QRect(360, 20, 400, 40))
59 | self.label_title.setText("")
60 | self.label_title.setObjectName("label_title")
61 | self.label_logo = QtWidgets.QLabel(self.centralwidget)
62 | self.label_logo.setGeometry(QtCore.QRect(30, 70, 800, 600))
63 | # self.label_logo.setMinimumSize(QtCore.QSize(800, 600))
64 | # self.label_logo.setMaximumSize(QtCore.QSize(800, 600))
65 | self.label_logo.setText("")
66 | self.label_logo.setObjectName("label_logo")
67 | self.bt_leave = QtWidgets.QPushButton(self.centralwidget) # 请假登记
68 | self.bt_leave.setGeometry(QtCore.QRect(970, 660, 101, 31))
69 | self.bt_leave.setObjectName("bt_leave")
70 | self.bt_exit = QtWidgets.QPushButton(self.centralwidget) # 退出系统
71 | self.bt_exit.setGeometry(QtCore.QRect(860, 790, 211, 61))
72 | self.bt_exit.setObjectName("bt_exit")
73 | self.line_4 = QtWidgets.QFrame(self.centralwidget)
74 | self.line_4.setGeometry(QtCore.QRect(20, 60, 821, 21))
75 | self.line_4.setFrameShape(QtWidgets.QFrame.HLine)
76 | self.line_4.setFrameShadow(QtWidgets.QFrame.Sunken)
77 | self.line_4.setObjectName("line_4")
78 | self.lineEdit_leave = QtWidgets.QLineEdit(self.centralwidget) # 请假登记输入
79 | self.lineEdit_leave.setGeometry(QtCore.QRect(860, 660, 101, 31))
80 | self.lineEdit_leave.setObjectName("lineEdit_leave")
81 | self.bt_listName1 = QtWidgets.QPushButton(self.centralwidget) # 未到
82 | self.bt_listName1.setGeometry(QtCore.QRect(880, 410, 50, 30))
83 | self.bt_listName1.setObjectName("bt_listName1")
84 |
85 | self.bt_output = QtWidgets.QPushButton(self.centralwidget) # 未到导出
86 | self.bt_output.setGeometry(QtCore.QRect(980, 410, 50, 30))
87 | self.bt_output.setObjectName("bt_output")
88 |
89 | self.label_emo1 = QtWidgets.QLabel(self.centralwidget) # 情绪1
90 | self.label_emo1.setGeometry(QtCore.QRect(880, 80, 50, 30))
91 | self.label_emo1.setObjectName("label_emo1")
92 |
93 | self.label_emo1_1 = QtWidgets.QLabel(self.centralwidget) # 情绪1
94 | self.label_emo1_1.setGeometry(QtCore.QRect(980, 80, 70, 30))
95 | self.label_emo1_1.setObjectName("label_emo1_1")
96 |
97 | self.label_emo2 = QtWidgets.QLabel(self.centralwidget) # 情绪2
98 | self.label_emo2.setGeometry(QtCore.QRect(880, 140, 50, 30))
99 | self.label_emo2.setObjectName("label_emo2")
100 |
101 | self.label_emo2_2 = QtWidgets.QLabel(self.centralwidget) # 情绪2
102 | self.label_emo2_2.setGeometry(QtCore.QRect(980, 140, 70, 30))
103 | self.label_emo2_2.setObjectName("label_emo2_2")
104 |
105 | self.label_emo3 = QtWidgets.QLabel(self.centralwidget) # 情绪3
106 | self.label_emo3.setGeometry(QtCore.QRect(880, 200, 50, 30))
107 | self.label_emo3.setObjectName("label_emo3")
108 |
109 | self.label_emo3_3 = QtWidgets.QLabel(self.centralwidget) # 情绪3
110 | self.label_emo3_3.setGeometry(QtCore.QRect(980, 200, 70, 30))
111 | self.label_emo3_3.setObjectName("label_emo3_3")
112 |
113 | self.label_emo4 = QtWidgets.QLabel(self.centralwidget) # 情绪4
114 | self.label_emo4.setGeometry(QtCore.QRect(880, 260, 50, 30))
115 | self.label_emo4.setObjectName("label_emo4")
116 |
117 | self.label_emo4_4 = QtWidgets.QLabel(self.centralwidget) # 情绪4
118 | self.label_emo4_4.setGeometry(QtCore.QRect(980, 260, 70, 30))
119 | self.label_emo4_4.setObjectName("label_emo4")
120 |
121 | self.label_emo6 = QtWidgets.QLabel(self.centralwidget) # 情绪5
122 | self.label_emo6.setGeometry(QtCore.QRect(880, 320, 50, 30))
123 | self.label_emo6.setObjectName("label_emo6")
124 |
125 | self.label_emo6_6 = QtWidgets.QLabel(self.centralwidget) # 情绪5
126 | self.label_emo6_6.setGeometry(QtCore.QRect(980, 320, 70, 30))
127 | self.label_emo6_6.setObjectName("label_emo6")
128 |
129 | self.bt_gathering = QtWidgets.QPushButton(self.centralwidget) # 信息采集
130 | self.bt_gathering.setGeometry(QtCore.QRect(20, 690, 131, 61))
131 | self.bt_gathering.setObjectName("bt_gathering")
132 |
133 | self.line_2 = QtWidgets.QFrame(self.centralwidget)
134 | self.line_2.setGeometry(QtCore.QRect(840, 70, 20, 781))
135 | self.line_2.setFrameShape(QtWidgets.QFrame.VLine)
136 | self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken)
137 | self.line_2.setObjectName("line_2")
138 |
139 | MainWindow.setCentralWidget(self.centralwidget)
140 | self.menubar = QtWidgets.QMenuBar(MainWindow)
141 | self.menubar.setGeometry(QtCore.QRect(0, 0, 1086, 23))
142 | self.menubar.setObjectName("menubar")
143 | self.menuFile = QtWidgets.QMenu(self.menubar)
144 | self.menuFile.setObjectName("menuFile")
145 | self.menuEdit = QtWidgets.QMenu(self.menubar)
146 | self.menuEdit.setObjectName("menuEdit")
147 | self.menuView = QtWidgets.QMenu(self.menubar)
148 | self.menuView.setObjectName("menuView")
149 | self.menuHelp = QtWidgets.QMenu(self.menubar)
150 | self.menuHelp.setObjectName("menuHelp")
151 | MainWindow.setMenuBar(self.menubar)
152 | self.statusbar = QtWidgets.QStatusBar(MainWindow)
153 | self.statusbar.setObjectName("statusbar")
154 | MainWindow.setStatusBar(self.statusbar)
155 | self.actionAbout = QtWidgets.QAction(MainWindow)
156 | self.actionAbout.setObjectName("actionAbout")
157 | self.actionOpen = QtWidgets.QAction(MainWindow)
158 | self.actionOpen.setObjectName("actionOpen")
159 | self.actionSetting = QtWidgets.QAction(MainWindow)
160 | self.actionSetting.setObjectName("actionSetting")
161 | self.actionExport = QtWidgets.QAction(MainWindow)
162 | self.actionExport.setObjectName("actionExport")
163 | self.menuFile.addAction(self.actionOpen)
164 | self.menuFile.addAction(self.actionSetting)
165 | self.menuFile.addAction(self.actionExport)
166 | self.menuHelp.addAction(self.actionAbout)
167 | self.menubar.addAction(self.menuFile.menuAction())
168 | self.menubar.addAction(self.menuEdit.menuAction())
169 | self.menubar.addAction(self.menuView.menuAction())
170 | self.menubar.addAction(self.menuHelp.menuAction())
171 |
172 | self.retranslateUi(MainWindow)
173 | QtCore.QMetaObject.connectSlotsByName(MainWindow)
174 |
175 | def retranslateUi(self, MainWindow):
176 | _translate = QtCore.QCoreApplication.translate
177 | MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
178 | self.bt_random_check.setText(_translate("MainWindow", "随机抽签"))
179 | self.bt_supplement.setText(_translate("MainWindow", "漏签补签"))
180 | self.bt_start_check.setText(_translate("MainWindow", "开始分析"))
181 | self.bt_generator.setText(_translate("MainWindow", "训练模型"))
182 | self.bt_analyse.setText(_translate("MainWindow", "分析详情"))
183 | self.bt_check_variation.setText(_translate("MainWindow", "未采集人员"))
184 | self.bt_open_camera.setText(_translate("MainWindow", "打开相机"))
185 | self.bt_leave.setText(_translate("MainWindow", "请假登记"))
186 | self.bt_exit.setText(_translate("MainWindow", "退出系统"))
187 | self.label_emo1.setText(_translate("MainWindow", "高兴"))
188 | self.label_emo1_1.setText(_translate("MainWindow", " "))
189 | self.label_emo2.setText(_translate("MainWindow", "伤心"))
190 | self.label_emo2_2.setText(_translate("MainWindow", " "))
191 | self.label_emo3.setText(_translate("MainWindow", "惊讶"))
192 | self.label_emo3_3.setText(_translate("MainWindow", " "))
193 | self.label_emo4.setText(_translate("MainWindow", "生气"))
194 | self.label_emo4_4.setText(_translate("MainWindow", " "))
195 | self.label_emo6.setText(_translate("MainWindow", "中立"))
196 | self.label_emo6_6.setText(_translate("MainWindow", " "))
197 | self.bt_listName1.setText(_translate("MainWindow", "未到"))
198 | self.bt_output.setText(_translate("MainWindow", "导出"))
199 | self.bt_gathering.setText(_translate("MainWindow", "信息采集"))
200 | self.menuFile.setTitle(_translate("MainWindow", "File"))
201 | self.menuEdit.setTitle(_translate("MainWindow", "Edit"))
202 | self.menuView.setTitle(_translate("MainWindow", "View"))
203 | self.menuHelp.setTitle(_translate("MainWindow", "Help"))
204 | self.actionAbout.setText(_translate("MainWindow", "About"))
205 | self.actionAbout.setWhatsThis(_translate("MainWindow", "Author: datamonday"))
206 | self.actionOpen.setText(_translate("MainWindow", "Open"))
207 | self.actionSetting.setText(_translate("MainWindow", "Setting"))
208 | self.actionExport.setText(_translate("MainWindow", "Export"))
209 |
210 |
211 | if __name__ == "__main__":
212 | import sys
213 | app = QtWidgets.QApplication(sys.argv)
214 | MainWindow = QtWidgets.QMainWindow()
215 | ui = Ui_MainWindow()
216 | ui.setupUi(MainWindow)
217 | MainWindow.show()
218 | sys.exit(app.exec_())
219 |
--------------------------------------------------------------------------------
/ui/mainwindow.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | MainWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 1086
10 | 907
11 |
12 |
13 |
14 | MainWindow
15 |
16 |
17 |
18 |
19 |
20 | 30
21 | 80
22 | 700
23 | 600
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | 850
34 | 20
35 | 231
36 | 30
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | 860
47 | 740
48 | 211
49 | 41
50 |
51 |
52 |
53 | 随机点名
54 |
55 |
56 |
57 |
58 |
59 | 970
60 | 300
61 | 101
62 | 31
63 |
64 |
65 |
66 | 漏签补签
67 |
68 |
69 |
70 |
71 |
72 | 860
73 | 360
74 | 211
75 | 141
76 |
77 |
78 |
79 |
80 |
81 |
82 | 860
83 | 100
84 | 61
85 | 16
86 |
87 |
88 |
89 | 考勤地点
90 |
91 |
92 |
93 |
94 |
95 | 150
96 | 690
97 | 31
98 | 131
99 |
100 |
101 |
102 | Qt::Vertical
103 |
104 |
105 |
106 |
107 |
108 | 860
109 | 300
110 | 101
111 | 31
112 |
113 |
114 |
115 |
116 |
117 |
118 | 350
119 | 690
120 | 301
121 | 161
122 |
123 |
124 |
125 |
126 |
127 |
128 | 30
129 | 833
130 | 301
131 | 16
132 |
133 |
134 |
135 | 24
136 |
137 |
138 |
139 |
140 |
141 | 770
142 | 770
143 | 71
144 | 81
145 |
146 |
147 |
148 | 活体检测
149 |
150 |
151 |
152 |
153 |
154 | 660
155 | 770
156 | 101
157 | 81
158 |
159 |
160 |
161 | 开始考勤
162 |
163 |
164 |
165 |
166 |
167 | 180
168 | 690
169 | 151
170 | 21
171 |
172 |
173 | -
174 |
175 | FaceNet (ResNet-SSD)
176 |
177 |
178 | -
179 |
180 | FaceNet (MTCNN)
181 |
182 |
183 | -
184 |
185 | RetinaFace
186 |
187 |
188 | -
189 |
190 | ArcFace
191 |
192 |
193 | -
194 |
195 | CenterFace
196 |
197 |
198 | -
199 |
200 | DBFace
201 |
202 |
203 | -
204 |
205 | FaceBoxes
206 |
207 |
208 | -
209 |
210 | S3FD
211 |
212 |
213 |
214 |
215 |
216 |
217 | 180
218 | 760
219 | 151
220 | 61
221 |
222 |
223 |
224 | 训练模型
225 |
226 |
227 |
228 |
229 |
230 | 860
231 | 530
232 | 211
233 | 141
234 |
235 |
236 |
237 |
238 |
239 |
240 | 180
241 | 720
242 | 151
243 | 31
244 |
245 |
246 |
247 | 加载模型
248 |
249 |
250 |
251 |
252 |
253 | 860
254 | 680
255 | 211
256 | 51
257 |
258 |
259 |
260 | 查看结果
261 |
262 |
263 |
264 |
265 |
266 | 860
267 | 190
268 | 31
269 | 16
270 |
271 |
272 |
273 | 实到
274 |
275 |
276 |
277 |
278 |
279 | 860
280 | 70
281 | 51
282 | 16
283 |
284 |
285 |
286 | 考勤班级
287 |
288 |
289 |
290 |
291 |
292 | 940
293 | 221
294 | 61
295 | 31
296 |
297 |
298 |
299 |
300 |
301 |
302 | 900
303 | 140
304 | 71
305 | 31
306 |
307 |
308 |
309 |
310 |
311 |
312 | 20
313 | 760
314 | 131
315 | 61
316 |
317 |
318 |
319 | 核验人脸数据库信息
320 |
321 |
322 |
323 |
324 |
325 | 860
326 | 510
327 | 41
328 | 16
329 |
330 |
331 |
332 | 迟到
333 |
334 |
335 |
336 |
337 |
338 | 900
339 | 180
340 | 71
341 | 31
342 |
343 |
344 |
345 |
346 |
347 |
348 | 660
349 | 690
350 | 181
351 | 71
352 |
353 |
354 |
355 | 打开相机
356 |
357 |
358 |
359 |
360 |
361 | 360
362 | 20
363 | 400
364 | 40
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 | 30
375 | 70
376 | 800
377 | 600
378 |
379 |
380 |
381 |
382 | 800
383 | 600
384 |
385 |
386 |
387 |
388 | 800
389 | 600
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 | 970
400 | 260
401 | 101
402 | 31
403 |
404 |
405 |
406 | 请假登记
407 |
408 |
409 |
410 |
411 |
412 | 980
413 | 140
414 | 91
415 | 71
416 |
417 |
418 |
419 | 查询
420 |
421 |
422 |
423 |
424 |
425 | 860
426 | 230
427 | 81
428 | 16
429 |
430 |
431 |
432 | 设置考勤时间
433 |
434 |
435 |
436 |
437 |
438 | 860
439 | 790
440 | 211
441 | 61
442 |
443 |
444 |
445 | 退出系统
446 |
447 |
448 |
449 |
450 |
451 | 20
452 | 60
453 | 821
454 | 21
455 |
456 |
457 |
458 | Qt::Horizontal
459 |
460 |
461 |
462 |
463 |
464 | 940
465 | 70
466 | 131
467 | 21
468 |
469 |
470 | -
471 |
472 | 2020001
473 |
474 |
475 | -
476 |
477 | 2020002
478 |
479 |
480 |
481 |
482 |
483 |
484 | 860
485 | 260
486 | 101
487 | 31
488 |
489 |
490 |
491 |
492 |
493 |
494 | 860
495 | 340
496 | 31
497 | 16
498 |
499 |
500 |
501 | 未到
502 |
503 |
504 |
505 |
506 |
507 | 20
508 | 690
509 | 131
510 | 61
511 |
512 |
513 |
514 | 信息采集
515 |
516 |
517 |
518 |
519 |
520 | 860
521 | 150
522 | 31
523 | 16
524 |
525 |
526 |
527 | 应到
528 |
529 |
530 |
531 |
532 |
533 | 840
534 | 70
535 | 20
536 | 781
537 |
538 |
539 |
540 | Qt::Vertical
541 |
542 |
543 |
544 |
545 |
546 | 1011
547 | 220
548 | 61
549 | 31
550 |
551 |
552 |
553 |
554 |
555 |
556 | 940
557 | 100
558 | 131
559 | 21
560 |
561 |
562 | -
563 |
564 | A
565 |
566 |
567 | -
568 |
569 | B
570 |
571 |
572 | -
573 |
574 | C
575 |
576 |
577 | -
578 |
579 | D
580 |
581 |
582 | -
583 |
584 | E
585 |
586 |
587 |
588 |
589 |
627 |
628 |
629 |
630 | About
631 |
632 |
633 | Author: datamonday
634 |
635 |
636 |
637 |
638 | Open
639 |
640 |
641 |
642 |
643 | Setting
644 |
645 |
646 |
647 |
648 | Export
649 |
650 |
651 |
652 |
653 |
654 |
655 |
--------------------------------------------------------------------------------
/utils2/Detaillog.py:
--------------------------------------------------------------------------------
1 | import os
2 | from datetime import datetime
3 | from PyQt5 import QtCore, QtGui, QtWidgets
4 | from PyQt5.QtGui import QImage, QIcon, QPixmap
5 | from PyQt5.QtCore import QCoreApplication, QThread
6 | from PyQt5.QtWidgets import QApplication, QWidget, QMessageBox, QInputDialog
7 | from utils2.GlobalVar import num_list
8 |
9 | # 导入分析详情框界面
10 | from ui import detail
11 |
12 | # 将根目录(execute所在目录)添加到环境变量
13 | from utils2.GlobalVar import add_path_to_sys, connect_to_sql
14 | rootdir = add_path_to_sys()
15 |
16 |
17 | class Detaillog(QWidget):
18 | def __init__(self):
19 | super().__init__()
20 |
21 | self.Dialog = detail.Ui_Form()
22 | self.Dialog.setupUi(self)
23 |
24 | # 实现路径错误提示,方便定位错误
25 | self.current_filename = os.path.basename(__file__)
26 |
27 | try:
28 | # 设置窗口名称和图标
29 | self.setWindowTitle("情绪分析详情界面")
30 | self.setWindowIcon(QIcon(f'{rootdir}/logo_imgs/fcb_logo.jpg'))
31 | except FileNotFoundError as e:
32 | print("[ERROR] UI背景图片路径不正确!(source file: {})".format(self.current_filename), e)
33 |
34 | self.Dialog.pb_other.clicked.connect(self.answer_other)
35 | self.Dialog.pb_exit.clicked.connect(self.pd_exit)
36 |
37 | # 查询详情
38 | def answer_other(self):
39 | try:
40 | db, cursor = connect_to_sql()
41 | except ConnectionAbortedError as e:
42 | self.ui.textBrowser_log.append('[INFO] 连接数据库失败,请检查配置信息!')
43 | else:
44 | sql = "select * from detail"
45 | # 执行查询
46 | cursor.execute(sql)
47 | results = cursor.fetchall()
48 | self.student_ids = []
49 | self.student_names = []
50 | self.student_emo = []
51 | self.student_time = []
52 | for item in results:
53 | self.student_ids.append(item[0])
54 | self.student_names.append(item[1])
55 | self.student_emo.append(item[2])
56 | self.student_time.append(item[3])
57 | finally:
58 | db.commit()
59 | cursor.close()
60 | db.close()
61 | if len(self.student_ids) == 0:
62 | QMessageBox.warning(self, "Error", "暂无情绪分析结果!", QMessageBox.Ok)
63 | else:
64 | # 设置显示数据层次结构,4行4列(包含行表头)
65 | table_view_module = QtGui.QStandardItemModel(len(num_list), 1)
66 | table_view_module.setHorizontalHeaderLabels(['学号', '姓名', '当前表情', '情绪持续时间/s'])
67 |
68 | step = 0
69 | for i in num_list:
70 | id = int(i) # 要显示的学号
71 | k = self.student_ids.index(id)
72 | num = QtGui.QStandardItem(str(id))
73 | name = self.student_names[k]
74 | name = QtGui.QStandardItem(name)
75 | emo = self.student_emo[k]
76 | emo = QtGui.QStandardItem(emo)
77 | current_time = datetime.now()
78 | last_time = (current_time - self.student_time[k]).seconds
79 | last_time = QtGui.QStandardItem(str(last_time))
80 |
81 |
82 | # 设置每个位置的行名称和文本值
83 | table_view_module.setItem(step, 0, num)
84 | table_view_module.setItem(step, 1, name)
85 | table_view_module.setItem(step, 2, emo)
86 | table_view_module.setItem(step, 3, last_time)
87 | step = step + 1
88 |
89 | # 指定显示的tableView控件,实例化表格视图
90 | self.Dialog.tableView.setModel(table_view_module)
91 |
92 | def pd_exit(self):
93 | self.close()
94 |
95 | def handle_click(self):
96 | if not self.isVisible():
97 | self.show()
98 |
99 |
--------------------------------------------------------------------------------
/utils2/GeneratorModel.py:
--------------------------------------------------------------------------------
1 | from imutils import paths
2 | import numpy as np
3 | import imutils
4 | import pickle
5 | import cv2
6 | import os
7 | import sys
8 | from sklearn.preprocessing import LabelEncoder
9 | from sklearn.svm import SVC
10 |
11 | # 将根目录(execute所在目录)添加到环境变量
12 | from utils2.GlobalVar import add_path_to_sys
13 | rootdir = add_path_to_sys()
14 |
15 |
16 | def Generator():
17 | # 人脸数据所在路径
18 | global embedder
19 | face_data = f"{rootdir}/face_dataset"
20 | # 输出面部嵌入的序列化数据库的路径
21 | embeddings = f"{rootdir}/saved_weights/embeddings.pickle"
22 | # OpenCV深度学习人脸检测器的路径
23 | detector_path = f"{rootdir}/model_face_detection/"
24 | # OpenCV深度学习面部嵌入模型的路径;Torch深度学习模型,可产生128-D面部嵌入
25 | # https://cmusatyalab.github.io/openface/models-and-accuracies/
26 | embedding_model = f"{rootdir}/model_facenet/openface_nn4.small2.v1.t7"
27 | # 置信度
28 | default_confidence = 0.5
29 |
30 | # 从磁盘加载序列化面部检测器
31 | print("[INFO] loading face detector...")
32 | proto_path = os.path.sep.join([detector_path, "deploy.prototxt"])
33 | model_path = os.path.sep.join([detector_path, "res10_300x300_ssd_iter_140000.caffemodel"])
34 | detector = cv2.dnn.readNetFromCaffe(proto_path, model_path)
35 |
36 | try:
37 | # 从磁盘加载序列化面嵌入模型
38 | print("[INFO] loading face recognizer...")
39 | embedder = cv2.dnn.readNetFromTorch(embedding_model)
40 | except IOError:
41 | print("[ERROR] Please check filepath!")
42 |
43 | # 人脸图像的路径
44 | print("[INFO] quantifying faces...")
45 | image_paths = list(paths.list_images(face_data))
46 |
47 | # 初始化提取的面部嵌入列表和相应的人名
48 | known_embeddings = []
49 | known_names = []
50 |
51 | # 初始化处理的人脸总数
52 | total = 0
53 |
54 | for (i, imagePath) in enumerate(image_paths):
55 | # 从图像路径中提取人名
56 | print("[INFO] processing image {}/{}".format(i + 1, len(image_paths)))
57 | name = imagePath.split(os.path.sep)[-2]
58 |
59 | # 加载图像,将其大小调整为宽度为600像素(同时保持纵横比),然后抓取图像尺寸
60 | image = cv2.imread(imagePath)
61 | image = imutils.resize(image, width=600)
62 | (h, w) = image.shape[:2]
63 |
64 | # 从图像构造一个blob
65 | image_blob = cv2.dnn.blobFromImage(
66 | cv2.resize(image, (300, 300)), 1.0, (300, 300),
67 | (104.0, 177.0, 123.0), swapRB=False, crop=False)
68 |
69 | # 应用OpenCV的基于深度学习的人脸检测器来定位输入图像中的人脸
70 | detector.setInput(image_blob)
71 | detections = detector.forward()
72 |
73 | # 确保至少找到一张脸
74 | if len(detections) > 0:
75 | # 假设每个图像只有一张脸,找到概率最大的边界框
76 | i = np.argmax(detections[0, 0, :, 2])
77 | confidence = detections[0, 0, i, 2]
78 |
79 | # 确保最大概率的检测也意味着最小概率测试(从而帮助滤除弱检测)
80 | if confidence > default_confidence:
81 | # 计算面部边界框的(x,y)坐标
82 | box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
83 | (startX, startY, endX, endY) = box.astype("int")
84 |
85 | # 提取面部ROI并获取ROI维度
86 | face = image[startY:endY, startX:endX]
87 | (fH, fW) = face.shape[:2]
88 |
89 | # 确保面部宽度和高度足够大
90 | if fW < 20 or fH < 20:
91 | continue
92 |
93 | # 为面部ROI构造一个blob,然后通过面部嵌入模型传递blob以获得面部的128-d量化
94 | face_blob = cv2.dnn.blobFromImage(face, 1.0 / 255,
95 | (96, 96), (0, 0, 0), swapRB=True, crop=False)
96 | embedder.setInput(face_blob)
97 | vec = embedder.forward()
98 |
99 | # 将人物名和相应的脸部嵌入添加到各自的列表中
100 | known_names.append(name)
101 | known_embeddings.append(vec.flatten())
102 | total += 1
103 |
104 | # 将面部嵌入+名称 保存到磁盘
105 | print("[INFO] serializing {} encodings...".format(total))
106 | data = {"embeddings": known_embeddings, "names": known_names}
107 | f = open(embeddings, "wb")
108 | f.write(pickle.dumps(data))
109 | f.close()
110 |
111 |
112 | def TrainModel():
113 | # 面部嵌入的序列化db的路径
114 | embeddings_path = f"{rootdir}/saved_weights/embeddings.pickle"
115 | # 训练识别面部的输出模型的路径
116 | recognizer_path = f"{rootdir}/saved_weights/recognizer.pickle"
117 | # 输出标签编码器的路径
118 | le_path = f"{rootdir}/saved_weights/le.pickle"
119 |
120 | # 加载面嵌入
121 | print("[INFO] loading face embeddings...")
122 | data = pickle.loads(open(embeddings_path, "rb").read())
123 |
124 | # 编码标签
125 | print("[INFO] encoding labels...")
126 | le = LabelEncoder()
127 | labels = le.fit_transform(data["names"])
128 |
129 | # 训练用于接受人脸128-d嵌入的模型,然后产生实际的人脸识别
130 | print("[INFO] training model...")
131 | recognizer = SVC(C=1.0, kernel="linear", probability=True)
132 | recognizer.fit(data["embeddings"], labels)
133 |
134 | # 将实际的人脸识别模型写入磁盘
135 | f = open(recognizer_path, "wb")
136 | f.write(pickle.dumps(recognizer))
137 | f.close()
138 |
139 | # 将标签编码器发送到磁盘
140 | f = open(le_path, "wb")
141 | f.write(pickle.dumps(le))
142 | f.close()
143 |
--------------------------------------------------------------------------------
/utils2/GlobalVar.py:
--------------------------------------------------------------------------------
1 | import os
2 | import re
3 | import sys
4 | import pymysql
5 |
6 | # 全局变量
7 | # 学号
8 | num_list =[]
9 | # 摄像头ID
10 | CAMERA_ID = 0
11 | # 默认采集人脸数量
12 | COLLENCT_FACE_NUM_DEFAULT = 100
13 |
14 | # 多少次循环保存一帧图像
15 | LOOP_FRAME = 20
16 |
17 |
18 | # 初始化循环次数,比如统计20帧中人脸的数量,取最大值进行考勤
19 | FR_LOOP_NUM = 10
20 |
21 | # 将execute文件所在目录添加到根目录
22 | def add_path_to_sys():
23 | rootdir = "E:/soft/smart/Face-Recognition-Class-Attendance-System-master/"
24 | # rootdir = os.getcwd()
25 | sys.path.append(rootdir)
26 |
27 | return rootdir
28 |
29 | # 连接数据库操作
30 | def connect_to_sql():
31 | db = pymysql.connect(host="localhost", user="root", password="123456", database="facedata")
32 | # 使用cursor()方法获取操作游标
33 | cursor = db.cursor()
34 |
35 | return db, cursor
36 |
37 | # 遍历人脸数据文件夹,并统计各人脸的图片数量
38 | def statical_facedata_nums():
39 | # 人脸数据文件夹根目录
40 | files_dir = "E:/soft/smart/Face-Recognition-Class-Attendance-System-master/face_dataset/"
41 | # print(os.listdir(files_dir))
42 |
43 | dirs = os.listdir(files_dir)
44 | # 初始化字典
45 | files_num_dict = dict(zip(dirs, [0] * len(dirs)))
46 |
47 | for dir in dirs:
48 | for file in os.listdir(files_dir + dir):
49 | if file.endswith('.jpg') or file.endswith('.png'):
50 | files_num_dict[dir] += 1
51 |
52 | return files_num_dict
53 |
54 |
55 | if __name__ == '__main__':
56 | files = statical_facedata_nums()
--------------------------------------------------------------------------------
/utils2/InfoDialog.py:
--------------------------------------------------------------------------------
1 | from PyQt5 import QtCore, QtGui, QtWidgets
2 | from PyQt5.QtGui import QImage, QIcon, QPixmap
3 | from PyQt5.QtCore import QCoreApplication, QThread
4 | from PyQt5.QtWidgets import QApplication, QWidget, QMessageBox, QInputDialog
5 | # 导入信息采集框界面
6 | from ui import infoUI
7 |
8 | import threading
9 | import cv2
10 | import imutils
11 | import os
12 | import sys
13 | from datetime import datetime
14 | # 导入全局变量,主要包含摄像头ID,默认采集人脸数量等
15 | from utils2.GlobalVar import CAMERA_ID, COLLENCT_FACE_NUM_DEFAULT, LOOP_FRAME
16 | # 将根目录(execute所在目录)添加到环境变量
17 | from utils2.GlobalVar import add_path_to_sys, statical_facedata_nums
18 | rootdir = add_path_to_sys()
19 |
20 |
21 | class InfoDialog(QWidget):
22 | def __init__(self):
23 | # super()构造器方法返回父级的对象。__init__()方法是构造器的一个方法。
24 | super().__init__()
25 |
26 | self.Dialog = infoUI.Ui_Form()
27 | self.Dialog.setupUi(self)
28 |
29 | # 实现路径错误提示,方便定位错误
30 | self.current_filename = os.path.basename(__file__)
31 |
32 | try:
33 | # 设置窗口名称和图标
34 | self.setWindowTitle('个人信息采集')
35 | self.setWindowIcon(QIcon(f'{rootdir}/logo_imgs/fcb_logo.jpg'))
36 | # 设置单张图片背景
37 | pixmap = QPixmap(f'{rootdir}/logo_imgs/bkg2.png')
38 | self.Dialog.label_capture.setPixmap(pixmap)
39 | except FileNotFoundError as e:
40 | print("[ERROR] UI背景图片路径不正确!(source file: {})".format(self.current_filename), e)
41 |
42 | # 设置信息采集按键连接函数
43 | self.Dialog.bt_start_collect.clicked.connect(self.open_camera)
44 | # 设置拍照按键连接函数
45 | self.Dialog.bt_take_photo.clicked.connect(self.take_photo)
46 | # 查看人脸图片数量案件连接函数
47 | self.Dialog.bt_check_dirs_faces.clicked.connect(self.check_dir_faces_num)
48 | # 退出
49 | self.Dialog.bt_exit.clicked.connect(self.check_exit)
50 |
51 | # 初始化摄像头
52 | self.cap = cv2.VideoCapture()
53 |
54 | # 设置默认采集的照片数量
55 | self.Dialog.spinBox_set_num.setValue(COLLENCT_FACE_NUM_DEFAULT)
56 | # 初始化已经采集的人脸数目
57 | self.have_token_photos = 0
58 |
59 | # 初始化一个变量用来存储上一次采集人脸的ID
60 | self.dialog_text_id_past = None
61 |
62 | self.collect_photos = int(self.Dialog.spinBox_set_num.text())
63 |
64 | def handle_click(self):
65 | if not self.isVisible():
66 | self.show()
67 |
68 | def handle_close(self):
69 | self.close()
70 |
71 | def open_camera(self):
72 | # 判断摄像头是否打开,如果打开则为true,反之为false
73 | if not self.cap.isOpened():
74 | # 通过对话框设置被采集人学号
75 | self.dialog_text_id, ok = QInputDialog.getText(self, '创建个人图像数据库', '请输入学号:')
76 | if ok and self.dialog_text_id != '':
77 |
78 | # 如果两次输入的学号不同,则将上一次的采集图像数量图片等删除
79 | if self.dialog_text_id != self.dialog_text_id_past:
80 | self.have_token_photos = 0
81 | self.Dialog.lcdNumber_collection_nums.display(0)
82 |
83 | self.Dialog.label_capture.clear()
84 | self.cap.open(CAMERA_ID)
85 | self.show_capture()
86 | else:
87 | self.cap.release()
88 | self.Dialog.label_capture.clear()
89 | self.Dialog.bt_start_collect.setText(u'开始采集')
90 |
91 | def show_capture(self):
92 | self.Dialog.bt_start_collect.setText(u'停止采集')
93 | self.Dialog.label_capture.clear()
94 | print("[INFO] starting video stream...")
95 | loop_num = 0
96 |
97 | # 循环来自视频文件流的帧
98 | while self.cap.isOpened():
99 | # 获取设定的最大采集张数
100 | self.collect_photos = int(self.Dialog.spinBox_set_num.text())
101 | # 循环自增
102 | loop_num += 1
103 |
104 | ret, frame = self.cap.read()
105 | QApplication.processEvents()
106 | frame = imutils.resize(frame, width=500)
107 | show_video = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # 这里指的是显示原图
108 | # opencv读取图片的样式,不能通过Qlabel进行显示,需要转换为Qimage。
109 | # QImage(uchar * data, int width, int height, int bytesPerLine, Format format)
110 | self.showImage = QImage(show_video.data,
111 | show_video.shape[1],
112 | show_video.shape[0],
113 | QImage.Format_RGB888)
114 | self.Dialog.label_capture.setPixmap(QPixmap.fromImage(self.showImage))
115 | # 是否为自动采集
116 | is_auto_collect = self.Dialog.checkBox_auto_collect.isChecked()
117 |
118 | if is_auto_collect:
119 | # 如果达到设定的最大采集数量则退出
120 | if self.have_token_photos != self.collect_photos:
121 | # 大量I/O,为保证每次都写入磁盘,20次循环写入一次
122 | if loop_num == LOOP_FRAME:
123 | self.have_token_photos += 1
124 | self.save_image()
125 |
126 | loop_num = 0
127 | if self.have_token_photos == self.collect_photos:
128 | QMessageBox.warning(self, "Warning", "已达到最大采集张数:{}!请增加采集数量或停止采集!".format(self.have_token_photos), QMessageBox.Ok)
129 | self.cap.release()
130 | self.Dialog.bt_start_collect.setText('开始采集')
131 | break
132 | else:
133 | QMessageBox.information(self, "Tips", "已退出自动采集模式,请手动采集!")
134 | break
135 |
136 | # 记录上次需要采集的照片数量
137 | self.dialog_text_id_past = self.dialog_text_id
138 |
139 | # 因为最后一张画面会显示在GUI中,此处实现清除。
140 | self.Dialog.label_capture.clear()
141 |
142 | def save_image(self, method='qt5'):
143 | self.filename = '{}/face_dataset/{}/'.format(rootdir, self.dialog_text_id)
144 | self.mk_folder(self.filename)
145 | if method == 'qt5':
146 | photo_save_path = os.path.join(os.path.dirname(os.path.abspath('__file__')), '{}'.format(self.filename))
147 | save_filename = datetime.now().strftime("%Y%m%d%H%M%S") + ".png"
148 | self.showImage.save(photo_save_path + save_filename)
149 |
150 | self.Dialog.lcdNumber_collection_nums.display(self.have_token_photos)
151 |
152 | # 创建文件夹
153 | def mk_folder(self, path):
154 | # 去除首位空格
155 | path = path.strip()
156 | # 去除尾部 \ 符号
157 | path = path.rstrip("\\")
158 | # 判断路径是否存在, 存在=True; 不存在=False
159 | is_dir_exists = os.path.exists(path)
160 | # 判断结果
161 | if not is_dir_exists:
162 | # 如果不存在则创建目录
163 | os.makedirs(path)
164 | return True
165 |
166 | def take_photo(self):
167 | if self.cap.isOpened():
168 | self.collect_photos = int(self.Dialog.spinBox_set_num.text())
169 | if self.have_token_photos != self.collect_photos:
170 | self.have_token_photos += 1
171 | try:
172 | self.save_image()
173 | except FileNotFoundError as e:
174 | print("[ERROR] 路径不正确!(source file: {})".format(self.current_filename), e)
175 |
176 | else:
177 | QMessageBox.information(self, "Information", self.tr("已达到设置的最大采集张数!"), QMessageBox.Ok)
178 |
179 | else:
180 | QMessageBox.information(self, "Information", self.tr("请先打开摄像头!"), QMessageBox.Ok)
181 |
182 |
183 | # 检查本地人脸数据信息,包括文件夹名(ID)及图片数量
184 | def check_dir_faces_num(self):
185 | num_dict = statical_facedata_nums()
186 | keys = list(num_dict.keys())
187 | # values = list(num_dict.values())
188 | # print(values)
189 | # 如果没有人脸文件夹,则提示用户采集数据
190 | if len(keys) == 0:
191 | QMessageBox.warning(self, "Error", "face_dataset文件夹下没有人脸数据,请马上录入!", QMessageBox.Ok)
192 | else:
193 | # 设置显示数据层次结构,行1列(包含行表头)
194 | table_view_module = QtGui.QStandardItemModel(len(keys), 1)
195 | table_view_module.setHorizontalHeaderLabels(['ID'])
196 |
197 | for row, key in enumerate(keys):
198 | # print(key, values[row])
199 | id = QtGui.QStandardItem(key)
200 | # num = QtGui.QStandardItem(str(values[row]))
201 |
202 | # 设置每个位置的行名称和文本值
203 | table_view_module.setItem(row, 0, id)
204 | # table_view_module.setItem(row, 1, num)
205 |
206 | # 指定显示的tableView控件,实例化表格视图
207 | self.Dialog.tableView.setModel(table_view_module)
208 |
209 |
210 | def check_exit(self):
211 | if self.cap.isOpened():
212 | self.cap.release()
213 | self.close()
214 |
--------------------------------------------------------------------------------
/utils2/RandomCheck.py:
--------------------------------------------------------------------------------
1 | import random
2 | from copy import deepcopy
3 |
4 |
5 | def random_check(choices):
6 | # 停止标志
7 | exit_flag = False
8 | # 防止原地修改
9 | choices = deepcopy(choices)
10 | while len(choices) != 0:
11 | random_choice = random.choice(choices)
12 | print(random_choice)
13 | choices.remove(random_choice)
14 |
15 | if exit_flag:
16 | break
17 |
18 |
19 | if __name__ == '__main__':
20 | choice_list = ['1', '2', '3', '4', '5', '7', '9', '11', '12', '13', '16', '18', '21', '22', '23']
21 | random_check(choice_list)
22 |
23 | import os
24 | from datetime import datetime
25 | from PyQt5 import QtCore, QtGui, QtWidgets
26 | from PyQt5.QtGui import QImage, QIcon, QPixmap
27 | from PyQt5.QtCore import QCoreApplication, QThread
28 | from PyQt5.QtWidgets import QApplication, QWidget, QMessageBox, QInputDialog
29 |
30 |
31 | # 导入信息采集框界面
32 | from ui import RandomCheckUI
33 |
34 | # 将根目录(execute所在目录)添加到环境变量
35 | from utils2.GlobalVar import add_path_to_sys, connect_to_sql
36 | rootdir = add_path_to_sys()
37 |
38 |
39 | class RCDialog(QWidget):
40 | def __init__(self):
41 | super().__init__()
42 |
43 | self.Dialog = RandomCheckUI.Ui_Form()
44 | self.Dialog.setupUi(self)
45 |
46 | # 实现路径错误提示,方便定位错误
47 | self.current_filename = os.path.basename(__file__)
48 |
49 | try:
50 | # 设置窗口名称和图标
51 | self.setWindowTitle("随机点名答题系统")
52 | self.setWindowIcon(QIcon(f'{rootdir}/logo_imgs/fcb_logo.jpg'))
53 | except FileNotFoundError as e:
54 | print("[ERROR] UI背景图片路径不正确!(source file: {})".format(self.current_filename), e)
55 | # else:
56 | # print("[INFO] 设置icon成功!")
57 |
58 | self.Dialog.pb_connect_db.clicked.connect(self.get_id_name_from_db)
59 |
60 | self.Dialog.pb_start.clicked.connect(self.start_random_check)
61 |
62 | self.Dialog.pb_success.clicked.connect(self.answer_success)
63 |
64 | self.Dialog.pb_fail.clicked.connect(self.answer_fail)
65 |
66 |
67 | self.Dialog.pb_other.clicked.connect(self.answer_other)
68 |
69 | self.get_id_name_from_db()
70 |
71 | # 核验本地人脸与数据库信息是否一致
72 | def get_id_name_from_db(self):
73 | try:
74 | db, cursor = connect_to_sql()
75 | except ConnectionAbortedError as e:
76 | self.ui.textBrowser_log.append('[INFO] 连接数据库失败,请检查配置信息!')
77 | else:
78 | sql = "select id, name from students"
79 | # 执行查询
80 | cursor.execute(sql)
81 | results = cursor.fetchall()
82 | self.student_ids = []
83 | self.student_names = []
84 | for item in results:
85 | self.student_ids.append(item[0])
86 | self.student_names.append(item[1])
87 | # 初始化点名列表
88 | self.random_check_names = deepcopy(self.student_names)
89 | self.random_check_ids = deepcopy(self.student_ids)
90 |
91 | # 随机点名
92 | def start_random_check(self):
93 | try:
94 | if len(self.random_check_ids) == 0 or len(self.random_check_names) == 0:
95 | box_choose = QMessageBox.information(self, "Notice", "已经遍历完毕,是否重新开始点名?", QMessageBox.Yes | QMessageBox.No)
96 | if box_choose == QMessageBox.Yes:
97 | self.random_check_names = deepcopy(self.student_names)
98 | self.random_check_ids = deepcopy(self.student_ids)
99 | else:
100 | pass
101 | else:
102 | self.rc_id = random.choice(self.random_check_ids)
103 | self.rc_name = self.random_check_names[self.random_check_ids.index(self.rc_id)]
104 | self.random_check_ids.remove(self.rc_id)
105 | self.random_check_names.remove(self.rc_name)
106 |
107 | self.Dialog.lcdNumber_id.display(self.rc_id)
108 | self.Dialog.textBrowser_name.append(self.rc_name)
109 |
110 | # 获取系统时间,保存到秒
111 | self.current_time = str(datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
112 |
113 | except Exception as e:
114 | QMessageBox.critical(self, "Error", "[Error] 随机点名列表未定义!请先连接数据库!", QMessageBox.Ok)
115 | print("[Exception]: ", e)
116 |
117 | # 成功回答
118 | def answer_success(self):
119 | print(self.rc_id, self.rc_name, self.current_time, "成功回答")
120 |
121 | # 回答失败
122 | def answer_fail(self):
123 | print(self.rc_id, self.rc_name, self.current_time, "回答失败")
124 |
125 |
126 | # 退出
127 | def answer_other(self):
128 | self.close()
129 |
130 | def handle_click(self):
131 | if not self.isVisible():
132 | self.show()
133 |
--------------------------------------------------------------------------------
/utils2/__pycache__/Detaillog.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/utils2/__pycache__/Detaillog.cpython-38.pyc
--------------------------------------------------------------------------------
/utils2/__pycache__/GeneratorModel.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/utils2/__pycache__/GeneratorModel.cpython-38.pyc
--------------------------------------------------------------------------------
/utils2/__pycache__/GlobalVar.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/utils2/__pycache__/GlobalVar.cpython-38.pyc
--------------------------------------------------------------------------------
/utils2/__pycache__/InfoDialog.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/utils2/__pycache__/InfoDialog.cpython-38.pyc
--------------------------------------------------------------------------------
/utils2/__pycache__/InfoUI.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/utils2/__pycache__/InfoUI.cpython-38.pyc
--------------------------------------------------------------------------------
/utils2/__pycache__/MainUI.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/utils2/__pycache__/MainUI.cpython-38.pyc
--------------------------------------------------------------------------------
/utils2/__pycache__/RandomCheck.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/utils2/__pycache__/RandomCheck.cpython-38.pyc
--------------------------------------------------------------------------------
/utils2/microsoft.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Memory555/Student-behavior-system/198313230e7c7ba4d5f762afa67b2b6df8a2700f/utils2/microsoft.ttf
--------------------------------------------------------------------------------