├── align ├── __init__.py ├── text.txt ├── det1.npy ├── det2.npy └── det3.npy ├── src ├── __init__.py ├── take_photo.py ├── get_face.py ├── SetUpMainWindow.py ├── face_recognition.py ├── Sqlite_UI.py └── facenet.py ├── tools ├── __init__.py └── sqlite_func.py ├── 20170512-110547 └── test.txt ├── DB ├── DB_File.txt ├── StudentFaceDB.db └── StudentCheckWorkDB.db ├── markdown_imgs ├── 1.png ├── 2.png └── 3.png ├── ui_src ├── __pycache__ │ ├── help.cpython-36.pyc │ ├── delwin_ui.cpython-36.pyc │ ├── addStudent.cpython-36.pyc │ ├── checkTable.cpython-36.pyc │ ├── addClassTable.cpython-36.pyc │ ├── delCheckTable.cpython-36.pyc │ └── deleteClassTable.cpython-36.pyc ├── Add_Data.ui ├── Add_Table.ui ├── Add_Data.py ├── Add_Table.py ├── prompt.ui ├── prompt.py ├── help.py ├── help.ui ├── delwin_ui.ui ├── delwin_ui.py ├── checkTable.ui ├── deleteClassTable.ui ├── delCheckTable.ui ├── checkTable.py ├── deleteClassTable.py ├── delCheckTable.py ├── addClassTable.ui ├── addClassTable.py ├── sqlite_main_window.ui ├── sqlite_main_window.py ├── MainUI.ui ├── MainUI.py ├── addStudent.ui └── addStudent.py ├── .gitignore └── README.md /align/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tools/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /align/text.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /20170512-110547/test.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /DB/DB_File.txt: -------------------------------------------------------------------------------- 1 | StudentFaceDB.db:人脸数据库 2 | StudentCheckWorkDB.db:考勤数据库 -------------------------------------------------------------------------------- /align/det1.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akira4O4/PyQt5_Face_Recognition/HEAD/align/det1.npy -------------------------------------------------------------------------------- /align/det2.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akira4O4/PyQt5_Face_Recognition/HEAD/align/det2.npy -------------------------------------------------------------------------------- /align/det3.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akira4O4/PyQt5_Face_Recognition/HEAD/align/det3.npy -------------------------------------------------------------------------------- /DB/StudentFaceDB.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akira4O4/PyQt5_Face_Recognition/HEAD/DB/StudentFaceDB.db -------------------------------------------------------------------------------- /markdown_imgs/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akira4O4/PyQt5_Face_Recognition/HEAD/markdown_imgs/1.png -------------------------------------------------------------------------------- /markdown_imgs/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akira4O4/PyQt5_Face_Recognition/HEAD/markdown_imgs/2.png -------------------------------------------------------------------------------- /markdown_imgs/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akira4O4/PyQt5_Face_Recognition/HEAD/markdown_imgs/3.png -------------------------------------------------------------------------------- /DB/StudentCheckWorkDB.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akira4O4/PyQt5_Face_Recognition/HEAD/DB/StudentCheckWorkDB.db -------------------------------------------------------------------------------- /ui_src/__pycache__/help.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akira4O4/PyQt5_Face_Recognition/HEAD/ui_src/__pycache__/help.cpython-36.pyc -------------------------------------------------------------------------------- /ui_src/__pycache__/delwin_ui.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akira4O4/PyQt5_Face_Recognition/HEAD/ui_src/__pycache__/delwin_ui.cpython-36.pyc -------------------------------------------------------------------------------- /ui_src/__pycache__/addStudent.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akira4O4/PyQt5_Face_Recognition/HEAD/ui_src/__pycache__/addStudent.cpython-36.pyc -------------------------------------------------------------------------------- /ui_src/__pycache__/checkTable.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akira4O4/PyQt5_Face_Recognition/HEAD/ui_src/__pycache__/checkTable.cpython-36.pyc -------------------------------------------------------------------------------- /ui_src/__pycache__/addClassTable.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akira4O4/PyQt5_Face_Recognition/HEAD/ui_src/__pycache__/addClassTable.cpython-36.pyc -------------------------------------------------------------------------------- /ui_src/__pycache__/delCheckTable.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akira4O4/PyQt5_Face_Recognition/HEAD/ui_src/__pycache__/delCheckTable.cpython-36.pyc -------------------------------------------------------------------------------- /ui_src/__pycache__/deleteClassTable.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akira4O4/PyQt5_Face_Recognition/HEAD/ui_src/__pycache__/deleteClassTable.cpython-36.pyc -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | 3 | 20170512-110547/ 4 | 5 | align/__pycache__/ 6 | 7 | src/__pycache__/ 8 | 9 | ui_src/__pycache__/ 10 | 11 | tools/__pycache__/ 12 | 13 | test/ 14 | 15 | 16 | ui_src/__pycache__/MainUI.cpython-36.pyc 17 | 18 | src_img/ 19 | emb_img/ 20 | 21 | src/file_op.py 22 | src/sqlite3_op.py 23 | -------------------------------------------------------------------------------- /ui_src/Add_Data.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Dialog_Add_Data 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | Add_Data 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /ui_src/Add_Table.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Dialog_Add_Table 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | Add Table 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /ui_src/Add_Data.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'Add_Data.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.9.2 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_Dialog_Add_Data(object): 12 | def setupUi(self, Dialog_Add_Data): 13 | Dialog_Add_Data.setObjectName("Dialog_Add_Data") 14 | Dialog_Add_Data.resize(400, 300) 15 | 16 | self.retranslateUi(Dialog_Add_Data) 17 | QtCore.QMetaObject.connectSlotsByName(Dialog_Add_Data) 18 | 19 | def retranslateUi(self, Dialog_Add_Data): 20 | _translate = QtCore.QCoreApplication.translate 21 | Dialog_Add_Data.setWindowTitle(_translate("Dialog_Add_Data", "Add_Data")) 22 | 23 | -------------------------------------------------------------------------------- /ui_src/Add_Table.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'Add_Table.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.9.2 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_Dialog_Add_Table(object): 12 | def setupUi(self, Dialog_Add_Table): 13 | Dialog_Add_Table.setObjectName("Dialog_Add_Table") 14 | Dialog_Add_Table.resize(400, 300) 15 | 16 | self.retranslateUi(Dialog_Add_Table) 17 | QtCore.QMetaObject.connectSlotsByName(Dialog_Add_Table) 18 | 19 | def retranslateUi(self, Dialog_Add_Table): 20 | _translate = QtCore.QCoreApplication.translate 21 | Dialog_Add_Table.setWindowTitle(_translate("Dialog_Add_Table", "Add Table")) 22 | 23 | -------------------------------------------------------------------------------- /ui_src/prompt.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Form 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | true 19 | 20 | 21 | 22 | 120 23 | 100 24 | 211 25 | 71 26 | 27 | 28 | 29 | 30 | 20 31 | 32 | 33 | 34 | 正在训练... 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /ui_src/prompt.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'prompt.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.9.2 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_For_prompt(object): 12 | def setupUi(self, Form): 13 | Form.setObjectName("prompt") 14 | Form.resize(400, 300) 15 | self.label = QtWidgets.QLabel(Form) 16 | self.label.setEnabled(True) 17 | self.label.setGeometry(QtCore.QRect(120, 100, 211, 71)) 18 | font = QtGui.QFont() 19 | font.setPointSize(20) 20 | self.label.setFont(font) 21 | self.label.setObjectName("label") 22 | 23 | self.retranslateUi(Form) 24 | QtCore.QMetaObject.connectSlotsByName(Form) 25 | 26 | def retranslateUi(self, Form): 27 | _translate = QtCore.QCoreApplication.translate 28 | Form.setWindowTitle(_translate("Form", "提示")) 29 | self.label.setText(_translate("Form", "正在训练...")) 30 | 31 | -------------------------------------------------------------------------------- /src/take_photo.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | 3 | 4 | class Camera: 5 | global cap 6 | cap = cv2.VideoCapture(0) 7 | num = 1 # 照片计数器 8 | 9 | def __init__(self): 10 | pass 11 | 12 | def openCamera(self): 13 | cap.open() 14 | ret, frame = cap.read() 15 | frame = cv2.flip(frame, 1) 16 | frame = cv2.resize(frame, (640, 480)) 17 | frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) 18 | lable = cv2.putText(frame, '-->Camera OK', (10, 30), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (0, 255, 0), 19 | thickness=1, lineType=1) 20 | return frame 21 | 22 | def takePhoto(self): 23 | ret, frame = cap.read() 24 | frame = cv2.flip(frame, 1) 25 | frame = cv2.resize(self.frame, (640, 480)) 26 | frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) 27 | lable = cv2.putText(frame, '-->Press the space to take a photo', (10, 30), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, 28 | (0, 255, 0), 29 | thickness=1, lineType=1) 30 | 31 | 32 | if __name__ == "__main__": 33 | # cap=Camera() 34 | # cap.openCamera() 35 | selectFName = 'ff' 36 | fPaht = '../faces/' + selectFName 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # 基于卷积神经网络的学生人脸识别考勤系统 3 | ## 上传前已经通过测试,希望各位认真查阅README,README中写了许多细节,不熟悉TensorFlow和python的请提前学习。欢迎给小星星。 4 | 5 | **gitee:https://gitee.com/omegalee/PyQt5_Face_Recognition** 6 | 7 | ## 测试环境: 8 | >**1.Windows 10 Ubuntu 20.04** 9 | >**2.TensorFlow1.15 GPU版本(没有GPU也可以,CPU版本会慢一些)** 10 | >**3.PyQt5** 11 | >**4.Sqlite3** 12 | 13 | ## 使用的模型: 14 | ### MTCNN->人脸检测 15 | ### FaceNet->人脸识别 16 | 17 | ## 程序目录如下: 18 | >**20170512-11-547下为FaceNet数据 这个数据太大无法上传,请到百度云下载** 19 | >**链接:https://** 20 | >**pan.baidu.** 21 | >**com/s/1nMwbahnZ0ZgeIOO6UrATdw(请去掉空格)** 22 | >**提取码:w3it ** 23 | >**align文件夹下为MTCNN模型数据** 24 | >**src文件夹下为所有主程序文件 SetUpMainWindow.py为启动文件** 25 | >**DB文件夹下为sqlite3数据库(文件夹里面是空的,运行主程序会自动创建,也可以手动创建,但是名字必须和DB_File里面写的一样)** 26 | >**ui_src文件夹下为ui设计文件和转码py文件** 27 | >**emb_img和src_img文件夹在程序运行时会自动创建(或者可以直接手动创建,两个都是空文件夹)** 28 | 29 | 30 | ## 目录结构 31 | ![目录结构1](https://github.com/omega-Lee/PyQt5_Face_Recognition/blob/master/markdown_imgs/3.png) 32 | 33 | 34 | ## DB目录讲解 35 | >**StudentCheckWorkDB.db 为学生考勤数据表** 36 | >**StudentFaceDB.db 为学生人脸数据** 37 | 38 | 39 | ## 操作步骤 40 | 0、SetUpMainWindow.py是主界面启动文件 41 | 1、在数据库管理中添加用户,主要不要修改主键内容,修改主键内容会导致更新错误 42 | 2、在主界面点击刷新,更新数据表 43 | 3、选择学号ID 44 | 4、打开摄像头->录入人脸 45 | 5、点击生成模型(人脸模型生成过程线程会被阻塞,但是训练完成就没事了) 46 | 5、开始检测 47 | 48 | ## 软件界面细节 49 | 50 | ![1](https://github.com/omega-Lee/PyQt5_Face_Recognition/blob/master/markdown_imgs/1.png) 51 | 52 | ![2](https://github.com/omega-Lee/PyQt5_Face_Recognition/blob/master/markdown_imgs/2.png) 53 | 54 | -------------------------------------------------------------------------------- /ui_src/help.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'help.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.9.2 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_help(object): 12 | def setupUi(self, help): 13 | help.setObjectName("help") 14 | help.resize(792, 240) 15 | self.horizontalLayout = QtWidgets.QHBoxLayout(help) 16 | self.horizontalLayout.setObjectName("horizontalLayout") 17 | self.textEdit = QtWidgets.QTextEdit(help) 18 | self.textEdit.setEnabled(False) 19 | self.textEdit.setObjectName("textEdit") 20 | self.horizontalLayout.addWidget(self.textEdit) 21 | 22 | self.retranslateUi(help) 23 | QtCore.QMetaObject.connectSlotsByName(help) 24 | 25 | def retranslateUi(self, help): 26 | _translate = QtCore.QCoreApplication.translate 27 | help.setWindowTitle(_translate("help", "帮助")) 28 | self.textEdit.setHtml(_translate("help", "\n" 29 | "\n" 32 | "

一:运行环境TensorFlow-gpu,win10,python3.7

\n" 33 | "


\n" 34 | "

二、使用方法:

\n" 35 | "

1、单击打开摄像头按钮,检测摄像头是否正常。

\n" 36 | "

2、单击添加标签按钮,添加一个新用户标签。

\n" 37 | "

3、在打开摄像头的情况下,单击录入人脸按钮,尽可能的确保正脸面对摄像头。

\n" 38 | "

4、单击提取特征按钮,在训练过程中,程序将保持忙碌状态直到提取结束。

\n" 39 | "

5、单击开始检测按钮,程序开启时间根据机器性能而定,在检测过程中,按下esc退出识别。

\n" 40 | "

6、单击删除按钮,输入需要删除的标签,完成删除操作。

")) 41 | 42 | -------------------------------------------------------------------------------- /ui_src/help.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | help 4 | 5 | 6 | 7 | 0 8 | 0 9 | 792 10 | 240 11 | 12 | 13 | 14 | 帮助 15 | 16 | 17 | 18 | 19 | 20 | false 21 | 22 | 23 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> 24 | <html><head><meta name="qrichtext" content="1" /><style type="text/css"> 25 | p, li { white-space: pre-wrap; } 26 | </style></head><body style=" font-family:'SimSun'; font-size:9pt; font-weight:400; font-style:normal;"> 27 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:12pt; font-weight:600;">一:运行环境</span>:<span style=" font-weight:600;">TensorFlow-gpu,win10,python3.7</span></p> 28 | <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> 29 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:11pt; font-weight:600;">二、使用方法:</span></p> 30 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:11pt;">1、单击打开摄像头按钮,检测摄像头是否正常。</span></p> 31 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:11pt;">2、单击添加标签按钮,添加一个新用户标签。</span></p> 32 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:11pt;">3、在打开摄像头的情况下,单击录入人脸按钮,尽可能的确保正脸面对摄像头。</span></p> 33 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:11pt;">4、单击提取特征按钮,在训练过程中,程序将保持忙碌状态直到提取结束。</span></p> 34 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:11pt;">5、单击开始检测按钮,程序开启时间根据机器性能而定,在检测过程中,按下esc退出识别。</span></p> 35 | <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:11pt;">6、单击删除按钮,输入需要删除的标签,完成删除操作。</span></p></body></html> 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /ui_src/delwin_ui.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Form_Del 4 | 5 | 6 | 7 | 0 8 | 0 9 | 401 10 | 252 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 50 20 | 50 21 | 299 22 | 138 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 16 31 | 32 | 33 | 34 | Qt::LeftToRight 35 | 36 | 37 | 选择需要删除的班级学号 38 | 39 | 40 | Qt::AlignCenter 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 16 55 | 56 | 57 | 58 | 选择班级 59 | 60 | 61 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 16 77 | 78 | 79 | 80 | 选择学号 81 | 82 | 83 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 200 99 | 60 100 | 101 | 102 | 103 | 104 | 16 105 | 50 106 | false 107 | 108 | 109 | 110 | 查询 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 200 123 | 60 124 | 125 | 126 | 127 | 128 | 16 129 | 50 130 | false 131 | 132 | 133 | 134 | 确定 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 200 143 | 60 144 | 145 | 146 | 147 | 148 | 16 149 | 50 150 | false 151 | 152 | 153 | 154 | 取消 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /ui_src/delwin_ui.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'delwin_ui.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.9.2 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_Form_Del(object): 12 | def setupUi(self, Form_Del): 13 | Form_Del.setObjectName("Form_Del") 14 | Form_Del.resize(401, 252) 15 | self.widget = QtWidgets.QWidget(Form_Del) 16 | self.widget.setGeometry(QtCore.QRect(50, 50, 299, 138)) 17 | self.widget.setObjectName("widget") 18 | self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.widget) 19 | self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) 20 | self.verticalLayout_2.setObjectName("verticalLayout_2") 21 | self.lab_delTest = QtWidgets.QLabel(self.widget) 22 | font = QtGui.QFont() 23 | font.setPointSize(16) 24 | self.lab_delTest.setFont(font) 25 | self.lab_delTest.setLayoutDirection(QtCore.Qt.LeftToRight) 26 | self.lab_delTest.setAlignment(QtCore.Qt.AlignCenter) 27 | self.lab_delTest.setObjectName("lab_delTest") 28 | self.verticalLayout_2.addWidget(self.lab_delTest) 29 | self.horizontalLayout_4 = QtWidgets.QHBoxLayout() 30 | self.horizontalLayout_4.setObjectName("horizontalLayout_4") 31 | self.verticalLayout = QtWidgets.QVBoxLayout() 32 | self.verticalLayout.setObjectName("verticalLayout") 33 | self.horizontalLayout_2 = QtWidgets.QHBoxLayout() 34 | self.horizontalLayout_2.setObjectName("horizontalLayout_2") 35 | self.lab_selecCalss = QtWidgets.QLabel(self.widget) 36 | font = QtGui.QFont() 37 | font.setPointSize(16) 38 | self.lab_selecCalss.setFont(font) 39 | self.lab_selecCalss.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) 40 | self.lab_selecCalss.setObjectName("lab_selecCalss") 41 | self.horizontalLayout_2.addWidget(self.lab_selecCalss) 42 | self.comboBox_selectClass = QtWidgets.QComboBox(self.widget) 43 | self.comboBox_selectClass.setObjectName("comboBox_selectClass") 44 | self.horizontalLayout_2.addWidget(self.comboBox_selectClass) 45 | self.verticalLayout.addLayout(self.horizontalLayout_2) 46 | self.horizontalLayout_3 = QtWidgets.QHBoxLayout() 47 | self.horizontalLayout_3.setObjectName("horizontalLayout_3") 48 | self.lab_selecLable = QtWidgets.QLabel(self.widget) 49 | font = QtGui.QFont() 50 | font.setPointSize(16) 51 | self.lab_selecLable.setFont(font) 52 | self.lab_selecLable.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) 53 | self.lab_selecLable.setObjectName("lab_selecLable") 54 | self.horizontalLayout_3.addWidget(self.lab_selecLable) 55 | self.comboBox_selectId = QtWidgets.QComboBox(self.widget) 56 | self.comboBox_selectId.setObjectName("comboBox_selectId") 57 | self.horizontalLayout_3.addWidget(self.comboBox_selectId) 58 | self.verticalLayout.addLayout(self.horizontalLayout_3) 59 | self.horizontalLayout_4.addLayout(self.verticalLayout) 60 | self.btn_Refresh = QtWidgets.QPushButton(self.widget) 61 | self.btn_Refresh.setMaximumSize(QtCore.QSize(200, 60)) 62 | font = QtGui.QFont() 63 | font.setPointSize(16) 64 | font.setBold(False) 65 | font.setWeight(50) 66 | self.btn_Refresh.setFont(font) 67 | self.btn_Refresh.setObjectName("btn_Refresh") 68 | self.horizontalLayout_4.addWidget(self.btn_Refresh) 69 | self.verticalLayout_2.addLayout(self.horizontalLayout_4) 70 | self.horizontalLayout = QtWidgets.QHBoxLayout() 71 | self.horizontalLayout.setObjectName("horizontalLayout") 72 | self.btn_Enter = QtWidgets.QPushButton(self.widget) 73 | self.btn_Enter.setMaximumSize(QtCore.QSize(200, 60)) 74 | font = QtGui.QFont() 75 | font.setPointSize(16) 76 | font.setBold(False) 77 | font.setWeight(50) 78 | self.btn_Enter.setFont(font) 79 | self.btn_Enter.setObjectName("btn_Enter") 80 | self.horizontalLayout.addWidget(self.btn_Enter) 81 | self.btn_Cancel = QtWidgets.QPushButton(self.widget) 82 | self.btn_Cancel.setMaximumSize(QtCore.QSize(200, 60)) 83 | font = QtGui.QFont() 84 | font.setPointSize(16) 85 | font.setBold(False) 86 | font.setWeight(50) 87 | self.btn_Cancel.setFont(font) 88 | self.btn_Cancel.setObjectName("btn_Cancel") 89 | self.horizontalLayout.addWidget(self.btn_Cancel) 90 | self.verticalLayout_2.addLayout(self.horizontalLayout) 91 | 92 | self.retranslateUi(Form_Del) 93 | QtCore.QMetaObject.connectSlotsByName(Form_Del) 94 | 95 | def retranslateUi(self, Form_Del): 96 | _translate = QtCore.QCoreApplication.translate 97 | Form_Del.setWindowTitle(_translate("Form_Del", "Form")) 98 | self.lab_delTest.setText(_translate("Form_Del", "选择需要删除的班级学号")) 99 | self.lab_selecCalss.setText(_translate("Form_Del", "选择班级")) 100 | self.lab_selecLable.setText(_translate("Form_Del", "选择学号")) 101 | self.btn_Refresh.setText(_translate("Form_Del", "查询")) 102 | self.btn_Enter.setText(_translate("Form_Del", "确定")) 103 | self.btn_Cancel.setText(_translate("Form_Del", "取消")) 104 | 105 | -------------------------------------------------------------------------------- /ui_src/checkTable.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Form_checkTable 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 30 20 | 60 21 | 344 22 | 164 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 0 33 | 0 34 | 35 | 36 | 37 | 38 | 16 39 | 40 | 41 | 42 | Qt::LeftToRight 43 | 44 | 45 | 添加考勤表 46 | 47 | 48 | Qt::AlignCenter 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 0 61 | 0 62 | 63 | 64 | 65 | 66 | 16 67 | 68 | 69 | 70 | Qt::LeftToRight 71 | 72 | 73 | 考勤表名称: 74 | 75 | 76 | Qt::AlignCenter 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | true 88 | 89 | 90 | 91 | 0 92 | 0 93 | 94 | 95 | 96 | 97 | 16 98 | 99 | 100 | 101 | Qt::LeftToRight 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 0 118 | 0 119 | 120 | 121 | 122 | 123 | 200 124 | 60 125 | 126 | 127 | 128 | 129 | 16 130 | 50 131 | false 132 | 133 | 134 | 135 | Qt::LeftToRight 136 | 137 | 138 | 确定 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 0 147 | 0 148 | 149 | 150 | 151 | 152 | 200 153 | 60 154 | 155 | 156 | 157 | 158 | 16 159 | 50 160 | false 161 | 162 | 163 | 164 | Qt::LeftToRight 165 | 166 | 167 | 取消 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /src/get_face.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import os 4 | from scipy import misc 5 | from skimage import transform 6 | import copy 7 | import facenet 8 | import align.detect_face 9 | import argparse 10 | import sys 11 | # import sqlite3_op 12 | from tools.sqlite_func import Sqlite_Func 13 | import cv2 14 | import imageio 15 | 16 | 17 | # MTCNN人脸检测 18 | def align_data(image_path, imgae_size, gpu_memory_faction): 19 | minsize = 20 20 | threshhold = [0.6, 0.7, 0.7] 21 | factor = 0.709 22 | 23 | with tf.Graph().as_default(): 24 | # per_process_gpu_memory_fraction指定了每个GPU进程中使用显存的上限,但它只能均匀地作用于所有GPU,无法对不同GPU设置不同的上限。 25 | gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=gpu_memory_faction, allow_growth=True) 26 | sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options, log_device_placement=False)) 27 | # 加载mtcnn 28 | with sess.as_default(): 29 | pnet, onet, rnet = align.detect_face.create_mtcnn(sess, None) 30 | 31 | temp_image_path = copy.copy(image_path) # 浅拷贝文件目录 32 | image_list = [] # 图片列表 33 | for path in temp_image_path: 34 | 35 | print('读取:', path) 36 | # os.path.expanduser:展开目录 37 | img = imageio.imread(os.path.expanduser(path)) # 这样读出来的图片格式为numpy类型,后面就不需要再转换了 38 | # img_size = np.asarray(img.shape)[0:2] # 获取数据尺寸类型为ndarray 39 | 40 | bounding_boxes, _ = align.detect_face.detect_face(img, minsize, pnet, onet, rnet, threshhold, factor) 41 | if len(bounding_boxes) < 1: 42 | image_path.remove(path) 43 | print("无法检测到脸部,删除", path) 44 | continue 45 | 46 | det = np.squeeze(bounding_boxes[0, 0:4]) # 从数组的形状中删除单维度条目,即把shape中为1的维度去掉,数据降维 47 | 48 | # 切片操作需要整数类型 49 | bb = np.zeros(4, dtype=np.int32) 50 | bb[0] = det[0] 51 | bb[1] = det[1] 52 | bb[2] = det[2] 53 | bb[3] = det[3] 54 | cropped = img[bb[1]:bb[3], bb[0]:bb[2], :] # 对角坐标 55 | cropped = cv2.resize(cropped, (imgae_size, imgae_size), interpolation=cv2.INTER_AREA) # 默认双三线性插值 56 | 57 | prewhitened = facenet.prewhiten(cropped) # 白化,取出冗余数据 58 | image_list.append(prewhitened) 59 | 60 | images = np.stack(image_list) 61 | 62 | return images 63 | 64 | 65 | # 文件夹人脸检测 66 | def detection(): 67 | src_img = '../src_img/' # 原图片 68 | emb_img = '../emb_img' # 人脸目录 69 | 70 | # 如果不存在这个目录就新建一个 71 | if os.path.exists(emb_img) is False: 72 | os.mkdir(emb_img) 73 | if os.path.exists(src_img) is False: 74 | os.mkdir(src_img) 75 | 76 | img_path_set = [] 77 | # 查看src_img下所有文件 78 | for f in os.listdir(src_img): 79 | # 拼接图片目录 80 | one_img = os.path.join(src_img, f) 81 | img_path_set.append(one_img) 82 | 83 | print(img_path_set) 84 | if len(img_path_set) != 0: 85 | # 提取人脸 86 | images_align = align_data(img_path_set, 160, 1.0) 87 | 88 | # 保存切割好的图片 89 | count = 0 90 | for f in os.listdir(src_img): 91 | # param:path,img 92 | imageio.imwrite(os.path.join(emb_img, f), images_align[count]) 93 | count = count + 1 94 | 95 | # 删除已经被剪裁的图片 96 | os.remove(os.path.join(src_img, f)) 97 | 98 | # 计算特征值 99 | computing_emb() 100 | return True 101 | 102 | 103 | # Facenet计算embadding并存入数据库 104 | def computing_emb(): 105 | with tf.Graph().as_default(): 106 | with tf.Session() as sess: 107 | 108 | # opsql = sqlite3_op.Operate_Sql() 109 | sqlite = Sqlite_Func() 110 | 111 | model = '../20170512-110547/' 112 | emb_img = '../emb_img' 113 | # 加载facenet模型 114 | facenet.load_model(model) 115 | images_placeholder = tf.get_default_graph().get_tensor_by_name("input:0") 116 | embeddings = tf.get_default_graph().get_tensor_by_name("embeddings:0") 117 | phase_train_placeholder = tf.get_default_graph().get_tensor_by_name("phase_train:0") 118 | image = [] 119 | nrof_images = 0 120 | global compare_emb, compare_num, all_obj_name 121 | 122 | all_obj_name = [] 123 | for i in os.listdir(emb_img): 124 | all_obj_name.append(i) 125 | img = imageio.imread(os.path.join(emb_img, i)) 126 | prewhitened = facenet.prewhiten(img) # 预白化去除冗余信息 127 | image.append(prewhitened) 128 | nrof_images = nrof_images + 1 129 | 130 | images = np.stack(image) # 沿着新轴连接数组的序列。 131 | # 计算对比图片embadding,embdadding是一个128维的张量 132 | compare_emb = sess.run(embeddings, feed_dict={images_placeholder: images, phase_train_placeholder: False}) 133 | compare_num = len(compare_emb) 134 | print('compare_emb len:', len(compare_emb[0])) 135 | print("pre_embadding计算完成") 136 | 137 | for i in os.listdir(emb_img): 138 | #拆分表名和id号 139 | index = 0 140 | info = i.split("#") 141 | print("info:{}".format(info)) 142 | table_name=info[0] 143 | id = info[1].split(".") 144 | ID=id[0] 145 | 146 | # opsql.insert_emb(info[0], id[0], compare_emb[index]) 147 | sqlite.update_face_emb(sqlite.DB_STUDENTFACE_PATH, table_name, ID, compare_emb[index]) 148 | index += 1 149 | 150 | # 移除已经计算过的image 151 | for f in os.listdir(emb_img): 152 | pass 153 | os.remove(os.path.join(emb_img, f)) 154 | 155 | 156 | def parse_arguments(argv): 157 | parser = argparse.ArgumentParser() 158 | parser.add_argument('--img_size', type=int, default=160) 159 | return parser.parse_args(argv) 160 | 161 | 162 | def main(args): 163 | detection() 164 | 165 | 166 | if __name__ == "__main__": 167 | # main(parse_arguments(sys.argv[1:])) 168 | detection() 169 | -------------------------------------------------------------------------------- /ui_src/deleteClassTable.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Form 4 | 5 | 6 | 7 | 0 8 | 0 9 | 498 10 | 250 11 | 12 | 13 | 14 | 删除班级表 15 | 16 | 17 | 18 | 19 | 30 20 | 30 21 | 436 22 | 166 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 0 33 | 0 34 | 35 | 36 | 37 | 38 | 16 39 | 40 | 41 | 42 | Qt::LeftToRight 43 | 44 | 45 | 删除人脸数据表 46 | 47 | 48 | Qt::AlignCenter 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 0 61 | 0 62 | 63 | 64 | 65 | 66 | 16 67 | 68 | 69 | 70 | Qt::LeftToRight 71 | 72 | 73 | 人脸数据表名: 74 | 75 | 76 | Qt::AlignCenter 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 0 99 | 0 100 | 101 | 102 | 103 | 104 | 200 105 | 60 106 | 107 | 108 | 109 | 110 | 16 111 | 50 112 | false 113 | 114 | 115 | 116 | Qt::LeftToRight 117 | 118 | 119 | 确定 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 0 128 | 0 129 | 130 | 131 | 132 | 133 | 200 134 | 60 135 | 136 | 137 | 138 | 139 | 16 140 | 50 141 | false 142 | 143 | 144 | 145 | Qt::LeftToRight 146 | 147 | 148 | 刷新 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 0 157 | 0 158 | 159 | 160 | 161 | 162 | 200 163 | 60 164 | 165 | 166 | 167 | 168 | 16 169 | 50 170 | false 171 | 172 | 173 | 174 | Qt::LeftToRight 175 | 176 | 177 | 取消 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | -------------------------------------------------------------------------------- /ui_src/delCheckTable.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Form_delCheckTable 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 30 20 | 60 21 | 344 22 | 164 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 0 33 | 0 34 | 35 | 36 | 37 | 38 | 16 39 | 40 | 41 | 42 | Qt::LeftToRight 43 | 44 | 45 | 删除考勤表 46 | 47 | 48 | Qt::AlignCenter 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 0 61 | 0 62 | 63 | 64 | 65 | 66 | 16 67 | 68 | 69 | 70 | Qt::LeftToRight 71 | 72 | 73 | 考勤表名称: 74 | 75 | 76 | Qt::AlignCenter 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 0 100 | 0 101 | 102 | 103 | 104 | 105 | 200 106 | 60 107 | 108 | 109 | 110 | 111 | 16 112 | 50 113 | false 114 | 115 | 116 | 117 | Qt::LeftToRight 118 | 119 | 120 | 确定 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 0 129 | 0 130 | 131 | 132 | 133 | 134 | 200 135 | 60 136 | 137 | 138 | 139 | 140 | 16 141 | 50 142 | false 143 | 144 | 145 | 146 | Qt::LeftToRight 147 | 148 | 149 | 刷新 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 0 158 | 0 159 | 160 | 161 | 162 | 163 | 200 164 | 60 165 | 166 | 167 | 168 | 169 | 16 170 | 50 171 | false 172 | 173 | 174 | 175 | Qt::LeftToRight 176 | 177 | 178 | 取消 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | -------------------------------------------------------------------------------- /ui_src/checkTable.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'checkTable.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.9.2 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_Form_checkTable(object): 12 | def setupUi(self, Form_checkTable): 13 | Form_checkTable.setObjectName("Form_checkTable") 14 | Form_checkTable.resize(400, 300) 15 | self.layoutWidget = QtWidgets.QWidget(Form_checkTable) 16 | self.layoutWidget.setGeometry(QtCore.QRect(30, 60, 344, 164)) 17 | self.layoutWidget.setObjectName("layoutWidget") 18 | self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.layoutWidget) 19 | self.verticalLayout_4.setContentsMargins(0, 0, 0, 0) 20 | self.verticalLayout_4.setObjectName("verticalLayout_4") 21 | self.verticalLayout_3 = QtWidgets.QVBoxLayout() 22 | self.verticalLayout_3.setObjectName("verticalLayout_3") 23 | self.lab_addTest_8 = QtWidgets.QLabel(self.layoutWidget) 24 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) 25 | sizePolicy.setHorizontalStretch(0) 26 | sizePolicy.setVerticalStretch(0) 27 | sizePolicy.setHeightForWidth(self.lab_addTest_8.sizePolicy().hasHeightForWidth()) 28 | self.lab_addTest_8.setSizePolicy(sizePolicy) 29 | font = QtGui.QFont() 30 | font.setPointSize(16) 31 | self.lab_addTest_8.setFont(font) 32 | self.lab_addTest_8.setLayoutDirection(QtCore.Qt.LeftToRight) 33 | self.lab_addTest_8.setAlignment(QtCore.Qt.AlignCenter) 34 | self.lab_addTest_8.setObjectName("lab_addTest_8") 35 | self.verticalLayout_3.addWidget(self.lab_addTest_8) 36 | self.horizontalLayout = QtWidgets.QHBoxLayout() 37 | self.horizontalLayout.setObjectName("horizontalLayout") 38 | self.verticalLayout = QtWidgets.QVBoxLayout() 39 | self.verticalLayout.setObjectName("verticalLayout") 40 | self.lab_addTest_6 = QtWidgets.QLabel(self.layoutWidget) 41 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) 42 | sizePolicy.setHorizontalStretch(0) 43 | sizePolicy.setVerticalStretch(0) 44 | sizePolicy.setHeightForWidth(self.lab_addTest_6.sizePolicy().hasHeightForWidth()) 45 | self.lab_addTest_6.setSizePolicy(sizePolicy) 46 | font = QtGui.QFont() 47 | font.setPointSize(16) 48 | self.lab_addTest_6.setFont(font) 49 | self.lab_addTest_6.setLayoutDirection(QtCore.Qt.LeftToRight) 50 | self.lab_addTest_6.setAlignment(QtCore.Qt.AlignCenter) 51 | self.lab_addTest_6.setObjectName("lab_addTest_6") 52 | self.verticalLayout.addWidget(self.lab_addTest_6) 53 | self.horizontalLayout.addLayout(self.verticalLayout) 54 | self.verticalLayout_2 = QtWidgets.QVBoxLayout() 55 | self.verticalLayout_2.setObjectName("verticalLayout_2") 56 | self.line_addCheckTable = QtWidgets.QLineEdit(self.layoutWidget) 57 | self.line_addCheckTable.setEnabled(True) 58 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) 59 | sizePolicy.setHorizontalStretch(0) 60 | sizePolicy.setVerticalStretch(0) 61 | sizePolicy.setHeightForWidth(self.line_addCheckTable.sizePolicy().hasHeightForWidth()) 62 | self.line_addCheckTable.setSizePolicy(sizePolicy) 63 | font = QtGui.QFont() 64 | font.setPointSize(16) 65 | self.line_addCheckTable.setFont(font) 66 | self.line_addCheckTable.setLayoutDirection(QtCore.Qt.LeftToRight) 67 | self.line_addCheckTable.setObjectName("line_addCheckTable") 68 | self.verticalLayout_2.addWidget(self.line_addCheckTable) 69 | self.horizontalLayout.addLayout(self.verticalLayout_2) 70 | self.verticalLayout_3.addLayout(self.horizontalLayout) 71 | self.verticalLayout_4.addLayout(self.verticalLayout_3) 72 | self.horizontalLayout_2 = QtWidgets.QHBoxLayout() 73 | self.horizontalLayout_2.setObjectName("horizontalLayout_2") 74 | self.btn_confirm = QtWidgets.QPushButton(self.layoutWidget) 75 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) 76 | sizePolicy.setHorizontalStretch(0) 77 | sizePolicy.setVerticalStretch(0) 78 | sizePolicy.setHeightForWidth(self.btn_confirm.sizePolicy().hasHeightForWidth()) 79 | self.btn_confirm.setSizePolicy(sizePolicy) 80 | self.btn_confirm.setMaximumSize(QtCore.QSize(200, 60)) 81 | font = QtGui.QFont() 82 | font.setPointSize(16) 83 | font.setBold(False) 84 | font.setWeight(50) 85 | self.btn_confirm.setFont(font) 86 | self.btn_confirm.setLayoutDirection(QtCore.Qt.LeftToRight) 87 | self.btn_confirm.setObjectName("btn_confirm") 88 | self.horizontalLayout_2.addWidget(self.btn_confirm) 89 | self.btn_cancel = QtWidgets.QPushButton(self.layoutWidget) 90 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) 91 | sizePolicy.setHorizontalStretch(0) 92 | sizePolicy.setVerticalStretch(0) 93 | sizePolicy.setHeightForWidth(self.btn_cancel.sizePolicy().hasHeightForWidth()) 94 | self.btn_cancel.setSizePolicy(sizePolicy) 95 | self.btn_cancel.setMaximumSize(QtCore.QSize(200, 60)) 96 | font = QtGui.QFont() 97 | font.setPointSize(16) 98 | font.setBold(False) 99 | font.setWeight(50) 100 | self.btn_cancel.setFont(font) 101 | self.btn_cancel.setLayoutDirection(QtCore.Qt.LeftToRight) 102 | self.btn_cancel.setObjectName("btn_cancel") 103 | self.horizontalLayout_2.addWidget(self.btn_cancel) 104 | self.verticalLayout_4.addLayout(self.horizontalLayout_2) 105 | 106 | self.retranslateUi(Form_checkTable) 107 | QtCore.QMetaObject.connectSlotsByName(Form_checkTable) 108 | 109 | def retranslateUi(self, Form_checkTable): 110 | _translate = QtCore.QCoreApplication.translate 111 | Form_checkTable.setWindowTitle(_translate("Form_checkTable", "Form")) 112 | self.lab_addTest_8.setText(_translate("Form_checkTable", "添加考勤表")) 113 | self.lab_addTest_6.setText(_translate("Form_checkTable", "考勤表名称:")) 114 | self.btn_confirm.setText(_translate("Form_checkTable", "确定")) 115 | self.btn_cancel.setText(_translate("Form_checkTable", "取消")) 116 | 117 | -------------------------------------------------------------------------------- /ui_src/deleteClassTable.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'deleteClassTable.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.9.2 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_DelClassTable(object): 12 | def setupUi(self, Form): 13 | Form.setObjectName("Form") 14 | Form.resize(498, 250) 15 | self.layoutWidget = QtWidgets.QWidget(Form) 16 | self.layoutWidget.setGeometry(QtCore.QRect(30, 30, 436, 166)) 17 | self.layoutWidget.setObjectName("layoutWidget") 18 | self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.layoutWidget) 19 | self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) 20 | self.verticalLayout_3.setObjectName("verticalLayout_3") 21 | self.verticalLayout_2 = QtWidgets.QVBoxLayout() 22 | self.verticalLayout_2.setObjectName("verticalLayout_2") 23 | self.lab_addTest_8 = QtWidgets.QLabel(self.layoutWidget) 24 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) 25 | sizePolicy.setHorizontalStretch(0) 26 | sizePolicy.setVerticalStretch(0) 27 | sizePolicy.setHeightForWidth(self.lab_addTest_8.sizePolicy().hasHeightForWidth()) 28 | self.lab_addTest_8.setSizePolicy(sizePolicy) 29 | font = QtGui.QFont() 30 | font.setPointSize(16) 31 | self.lab_addTest_8.setFont(font) 32 | self.lab_addTest_8.setLayoutDirection(QtCore.Qt.LeftToRight) 33 | self.lab_addTest_8.setAlignment(QtCore.Qt.AlignCenter) 34 | self.lab_addTest_8.setObjectName("lab_addTest_8") 35 | self.verticalLayout_2.addWidget(self.lab_addTest_8) 36 | self.verticalLayout = QtWidgets.QVBoxLayout() 37 | self.verticalLayout.setObjectName("verticalLayout") 38 | self.horizontalLayout = QtWidgets.QHBoxLayout() 39 | self.horizontalLayout.setObjectName("horizontalLayout") 40 | self.lab_addTest_6 = QtWidgets.QLabel(self.layoutWidget) 41 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) 42 | sizePolicy.setHorizontalStretch(0) 43 | sizePolicy.setVerticalStretch(0) 44 | sizePolicy.setHeightForWidth(self.lab_addTest_6.sizePolicy().hasHeightForWidth()) 45 | self.lab_addTest_6.setSizePolicy(sizePolicy) 46 | font = QtGui.QFont() 47 | font.setPointSize(16) 48 | self.lab_addTest_6.setFont(font) 49 | self.lab_addTest_6.setLayoutDirection(QtCore.Qt.LeftToRight) 50 | self.lab_addTest_6.setAlignment(QtCore.Qt.AlignCenter) 51 | self.lab_addTest_6.setObjectName("lab_addTest_6") 52 | self.horizontalLayout.addWidget(self.lab_addTest_6) 53 | self.comboBox_del_facedata_table = QtWidgets.QComboBox(self.layoutWidget) 54 | self.comboBox_del_facedata_table.setObjectName("comboBox_del_facedata_table") 55 | self.horizontalLayout.addWidget(self.comboBox_del_facedata_table) 56 | self.verticalLayout.addLayout(self.horizontalLayout) 57 | self.horizontalLayout_3 = QtWidgets.QHBoxLayout() 58 | self.horizontalLayout_3.setObjectName("horizontalLayout_3") 59 | self.verticalLayout.addLayout(self.horizontalLayout_3) 60 | self.verticalLayout_2.addLayout(self.verticalLayout) 61 | self.verticalLayout_3.addLayout(self.verticalLayout_2) 62 | self.horizontalLayout_2 = QtWidgets.QHBoxLayout() 63 | self.horizontalLayout_2.setObjectName("horizontalLayout_2") 64 | self.btn_confirm = QtWidgets.QPushButton(self.layoutWidget) 65 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) 66 | sizePolicy.setHorizontalStretch(0) 67 | sizePolicy.setVerticalStretch(0) 68 | sizePolicy.setHeightForWidth(self.btn_confirm.sizePolicy().hasHeightForWidth()) 69 | self.btn_confirm.setSizePolicy(sizePolicy) 70 | self.btn_confirm.setMaximumSize(QtCore.QSize(200, 60)) 71 | font = QtGui.QFont() 72 | font.setPointSize(16) 73 | font.setBold(False) 74 | font.setWeight(50) 75 | self.btn_confirm.setFont(font) 76 | self.btn_confirm.setLayoutDirection(QtCore.Qt.LeftToRight) 77 | self.btn_confirm.setObjectName("btn_confirm") 78 | self.horizontalLayout_2.addWidget(self.btn_confirm) 79 | self.btn_refresh = QtWidgets.QPushButton(self.layoutWidget) 80 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) 81 | sizePolicy.setHorizontalStretch(0) 82 | sizePolicy.setVerticalStretch(0) 83 | sizePolicy.setHeightForWidth(self.btn_refresh.sizePolicy().hasHeightForWidth()) 84 | self.btn_refresh.setSizePolicy(sizePolicy) 85 | self.btn_refresh.setMaximumSize(QtCore.QSize(200, 60)) 86 | font = QtGui.QFont() 87 | font.setPointSize(16) 88 | font.setBold(False) 89 | font.setWeight(50) 90 | self.btn_refresh.setFont(font) 91 | self.btn_refresh.setLayoutDirection(QtCore.Qt.LeftToRight) 92 | self.btn_refresh.setObjectName("btn_refresh") 93 | self.horizontalLayout_2.addWidget(self.btn_refresh) 94 | self.btn_cancel = QtWidgets.QPushButton(self.layoutWidget) 95 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) 96 | sizePolicy.setHorizontalStretch(0) 97 | sizePolicy.setVerticalStretch(0) 98 | sizePolicy.setHeightForWidth(self.btn_cancel.sizePolicy().hasHeightForWidth()) 99 | self.btn_cancel.setSizePolicy(sizePolicy) 100 | self.btn_cancel.setMaximumSize(QtCore.QSize(200, 60)) 101 | font = QtGui.QFont() 102 | font.setPointSize(16) 103 | font.setBold(False) 104 | font.setWeight(50) 105 | self.btn_cancel.setFont(font) 106 | self.btn_cancel.setLayoutDirection(QtCore.Qt.LeftToRight) 107 | self.btn_cancel.setObjectName("btn_cancel") 108 | self.horizontalLayout_2.addWidget(self.btn_cancel) 109 | self.verticalLayout_3.addLayout(self.horizontalLayout_2) 110 | 111 | self.retranslateUi(Form) 112 | QtCore.QMetaObject.connectSlotsByName(Form) 113 | 114 | def retranslateUi(self, Form): 115 | _translate = QtCore.QCoreApplication.translate 116 | Form.setWindowTitle(_translate("Form", "删除班级表")) 117 | self.lab_addTest_8.setText(_translate("Form", "删除人脸数据表")) 118 | self.lab_addTest_6.setText(_translate("Form", "人脸数据表名:")) 119 | self.btn_confirm.setText(_translate("Form", "确定")) 120 | self.btn_refresh.setText(_translate("Form", "刷新")) 121 | self.btn_cancel.setText(_translate("Form", "取消")) 122 | 123 | -------------------------------------------------------------------------------- /ui_src/delCheckTable.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'delCheckTable.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.9.2 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_Form_delCheckTable(object): 12 | def setupUi(self, Form_delCheckTable): 13 | Form_delCheckTable.setObjectName("Form_delCheckTable") 14 | Form_delCheckTable.resize(400, 300) 15 | self.layoutWidget = QtWidgets.QWidget(Form_delCheckTable) 16 | self.layoutWidget.setGeometry(QtCore.QRect(30, 60, 344, 164)) 17 | self.layoutWidget.setObjectName("layoutWidget") 18 | self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.layoutWidget) 19 | self.verticalLayout_4.setContentsMargins(0, 0, 0, 0) 20 | self.verticalLayout_4.setObjectName("verticalLayout_4") 21 | self.verticalLayout_3 = QtWidgets.QVBoxLayout() 22 | self.verticalLayout_3.setObjectName("verticalLayout_3") 23 | self.lab_addTest_8 = QtWidgets.QLabel(self.layoutWidget) 24 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) 25 | sizePolicy.setHorizontalStretch(0) 26 | sizePolicy.setVerticalStretch(0) 27 | sizePolicy.setHeightForWidth(self.lab_addTest_8.sizePolicy().hasHeightForWidth()) 28 | self.lab_addTest_8.setSizePolicy(sizePolicy) 29 | font = QtGui.QFont() 30 | font.setPointSize(16) 31 | self.lab_addTest_8.setFont(font) 32 | self.lab_addTest_8.setLayoutDirection(QtCore.Qt.LeftToRight) 33 | self.lab_addTest_8.setAlignment(QtCore.Qt.AlignCenter) 34 | self.lab_addTest_8.setObjectName("lab_addTest_8") 35 | self.verticalLayout_3.addWidget(self.lab_addTest_8) 36 | self.horizontalLayout = QtWidgets.QHBoxLayout() 37 | self.horizontalLayout.setObjectName("horizontalLayout") 38 | self.verticalLayout = QtWidgets.QVBoxLayout() 39 | self.verticalLayout.setObjectName("verticalLayout") 40 | self.lab_addTest_6 = QtWidgets.QLabel(self.layoutWidget) 41 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) 42 | sizePolicy.setHorizontalStretch(0) 43 | sizePolicy.setVerticalStretch(0) 44 | sizePolicy.setHeightForWidth(self.lab_addTest_6.sizePolicy().hasHeightForWidth()) 45 | self.lab_addTest_6.setSizePolicy(sizePolicy) 46 | font = QtGui.QFont() 47 | font.setPointSize(16) 48 | self.lab_addTest_6.setFont(font) 49 | self.lab_addTest_6.setLayoutDirection(QtCore.Qt.LeftToRight) 50 | self.lab_addTest_6.setAlignment(QtCore.Qt.AlignCenter) 51 | self.lab_addTest_6.setObjectName("lab_addTest_6") 52 | self.verticalLayout.addWidget(self.lab_addTest_6) 53 | self.horizontalLayout.addLayout(self.verticalLayout) 54 | self.verticalLayout_2 = QtWidgets.QVBoxLayout() 55 | self.verticalLayout_2.setObjectName("verticalLayout_2") 56 | self.comboBox_delCheckTable = QtWidgets.QComboBox(self.layoutWidget) 57 | self.comboBox_delCheckTable.setObjectName("comboBox_delCheckTable") 58 | self.verticalLayout_2.addWidget(self.comboBox_delCheckTable) 59 | self.horizontalLayout.addLayout(self.verticalLayout_2) 60 | self.verticalLayout_3.addLayout(self.horizontalLayout) 61 | self.verticalLayout_4.addLayout(self.verticalLayout_3) 62 | self.horizontalLayout_2 = QtWidgets.QHBoxLayout() 63 | self.horizontalLayout_2.setObjectName("horizontalLayout_2") 64 | self.btn_confirm = QtWidgets.QPushButton(self.layoutWidget) 65 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) 66 | sizePolicy.setHorizontalStretch(0) 67 | sizePolicy.setVerticalStretch(0) 68 | sizePolicy.setHeightForWidth(self.btn_confirm.sizePolicy().hasHeightForWidth()) 69 | self.btn_confirm.setSizePolicy(sizePolicy) 70 | self.btn_confirm.setMaximumSize(QtCore.QSize(200, 60)) 71 | font = QtGui.QFont() 72 | font.setPointSize(16) 73 | font.setBold(False) 74 | font.setWeight(50) 75 | self.btn_confirm.setFont(font) 76 | self.btn_confirm.setLayoutDirection(QtCore.Qt.LeftToRight) 77 | self.btn_confirm.setObjectName("btn_confirm") 78 | self.horizontalLayout_2.addWidget(self.btn_confirm) 79 | self.btn_refresh = QtWidgets.QPushButton(self.layoutWidget) 80 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) 81 | sizePolicy.setHorizontalStretch(0) 82 | sizePolicy.setVerticalStretch(0) 83 | sizePolicy.setHeightForWidth(self.btn_refresh.sizePolicy().hasHeightForWidth()) 84 | self.btn_refresh.setSizePolicy(sizePolicy) 85 | self.btn_refresh.setMaximumSize(QtCore.QSize(200, 60)) 86 | font = QtGui.QFont() 87 | font.setPointSize(16) 88 | font.setBold(False) 89 | font.setWeight(50) 90 | self.btn_refresh.setFont(font) 91 | self.btn_refresh.setLayoutDirection(QtCore.Qt.LeftToRight) 92 | self.btn_refresh.setObjectName("btn_refresh") 93 | self.horizontalLayout_2.addWidget(self.btn_refresh) 94 | self.btn_cancel = QtWidgets.QPushButton(self.layoutWidget) 95 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) 96 | sizePolicy.setHorizontalStretch(0) 97 | sizePolicy.setVerticalStretch(0) 98 | sizePolicy.setHeightForWidth(self.btn_cancel.sizePolicy().hasHeightForWidth()) 99 | self.btn_cancel.setSizePolicy(sizePolicy) 100 | self.btn_cancel.setMaximumSize(QtCore.QSize(200, 60)) 101 | font = QtGui.QFont() 102 | font.setPointSize(16) 103 | font.setBold(False) 104 | font.setWeight(50) 105 | self.btn_cancel.setFont(font) 106 | self.btn_cancel.setLayoutDirection(QtCore.Qt.LeftToRight) 107 | self.btn_cancel.setObjectName("btn_cancel") 108 | self.horizontalLayout_2.addWidget(self.btn_cancel) 109 | self.verticalLayout_4.addLayout(self.horizontalLayout_2) 110 | 111 | self.retranslateUi(Form_delCheckTable) 112 | QtCore.QMetaObject.connectSlotsByName(Form_delCheckTable) 113 | 114 | def retranslateUi(self, Form_delCheckTable): 115 | _translate = QtCore.QCoreApplication.translate 116 | Form_delCheckTable.setWindowTitle(_translate("Form_delCheckTable", "Form")) 117 | self.lab_addTest_8.setText(_translate("Form_delCheckTable", "删除考勤表")) 118 | self.lab_addTest_6.setText(_translate("Form_delCheckTable", "考勤表名称:")) 119 | self.btn_confirm.setText(_translate("Form_delCheckTable", "确定")) 120 | self.btn_refresh.setText(_translate("Form_delCheckTable", "刷新")) 121 | self.btn_cancel.setText(_translate("Form_delCheckTable", "取消")) 122 | 123 | -------------------------------------------------------------------------------- /ui_src/addClassTable.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Form 4 | 5 | 6 | 7 | 0 8 | 0 9 | 496 10 | 255 11 | 12 | 13 | 14 | 添加班级表 15 | 16 | 17 | 18 | 19 | 70 20 | 50 21 | 344 22 | 164 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 0 33 | 0 34 | 35 | 36 | 37 | 38 | 16 39 | 40 | 41 | 42 | Qt::LeftToRight 43 | 44 | 45 | 添加人脸数据表 46 | 47 | 48 | Qt::AlignCenter 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 0 61 | 0 62 | 63 | 64 | 65 | 66 | 16 67 | 68 | 69 | 70 | Qt::LeftToRight 71 | 72 | 73 | 院系 74 | 75 | 76 | Qt::AlignCenter 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 0 85 | 0 86 | 87 | 88 | 89 | 90 | 16 91 | 92 | 93 | 94 | Qt::LeftToRight 95 | 96 | 97 | 班级 98 | 99 | 100 | Qt::AlignCenter 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | true 112 | 113 | 114 | 115 | 0 116 | 0 117 | 118 | 119 | 120 | 121 | 16 122 | 123 | 124 | 125 | Qt::LeftToRight 126 | 127 | 128 | 129 | 130 | 131 | 132 | true 133 | 134 | 135 | 136 | 0 137 | 0 138 | 139 | 140 | 141 | 142 | 16 143 | 144 | 145 | 146 | Qt::LeftToRight 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 0 163 | 0 164 | 165 | 166 | 167 | 168 | 200 169 | 60 170 | 171 | 172 | 173 | 174 | 16 175 | 50 176 | false 177 | 178 | 179 | 180 | Qt::LeftToRight 181 | 182 | 183 | 确定 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 0 192 | 0 193 | 194 | 195 | 196 | 197 | 200 198 | 60 199 | 200 | 201 | 202 | 203 | 16 204 | 50 205 | false 206 | 207 | 208 | 209 | Qt::LeftToRight 210 | 211 | 212 | 取消 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | -------------------------------------------------------------------------------- /tools/sqlite_func.py: -------------------------------------------------------------------------------- 1 | import sqlite3 as db 2 | 3 | test_db_path = "/home/lee/pyCode/PyQt5_Face_Recognition/DB/StudentFaceDB.db" 4 | 5 | 6 | class Sqlite_Func: 7 | def __init__(self): 8 | 9 | # 数据库数据库地址 10 | self.DB_STUDENTFACE_PATH = '../DB/StudentFaceDB.db' 11 | self.DB_STUDENTCHECKWORK_PATH = '../DB/StudentCheckWorkDB.db' 12 | 13 | # 数据库类型 14 | self.DB_TYPE_FACE = "studentfacedb.db".upper() 15 | self.DB_TYPE_CHECKWORK = "studentcheckworkdb.db".upper() 16 | 17 | self.dict_cmd = {} 18 | 19 | self.init_cmd() 20 | 21 | def init_cmd(self): 22 | 23 | # 创建人脸数据表 24 | self.dict_cmd[self.DB_TYPE_FACE] = "CREATE TABLE {}(" \ 25 | "lable text not null," \ 26 | "name text not null," \ 27 | "sex text not null," \ 28 | "id text primary key not null," \ 29 | "profession text not null," \ 30 | "features text not null);" 31 | # 创建学生考勤表 32 | self.dict_cmd[self.DB_TYPE_CHECKWORK] = "CREATE TABLE {}(" \ 33 | "id text primary key not null," \ 34 | "name text not null," \ 35 | "flag text not null);" 36 | 37 | # 执行语句 38 | def executeCMD(self, db_path, cmd): 39 | if cmd == "": 40 | assert "func executeCMD error" 41 | conn = db.connect(db_path) # 该 API 打开一个到 SQLite 数据库文件 database 的链接,如果数据库成功打开,则返回一个连接对象 42 | if conn == None: 43 | return None 44 | cursor = conn.cursor() # 该例程创建一个 cursor,将在 Python 数据库编程中用到。 45 | conn.row_factory = db.Row # 可访问列信息 46 | print("cmd:",cmd) 47 | cursor.execute(cmd) # 该例程执行一个 SQL 语句 48 | rows = cursor.fetchall() # 该例程获取查询结果集中所有(剩余)的行,返回一个列表。当没有可用的行时,则返回一个空的列表。 49 | conn.commit() 50 | conn.close() 51 | return rows 52 | 53 | # 返回当前当前数据库所有表 54 | def check_table(self, db_path): 55 | print("返回当前当前数据库:{}所有表".format(db_path)) 56 | self._table = "select name from sqlite_master where type='table' order by name" 57 | ret = self.executeCMD(db_path, self._table) 58 | self.table_list = [] 59 | for i in ret: 60 | self.table_list.append(i[0]) 61 | return self.table_list 62 | 63 | # 查看表结构 64 | def check_field(self, db_path, t): 65 | self.field_list = [] 66 | self._schema = lambda t: "PRAGMA table_info({})".format(t) 67 | ret = self.executeCMD(db_path, self._schema(t)) 68 | for i in ret: 69 | self.field_list.append(i[1]) 70 | return self.field_list 71 | 72 | # 构建普通查询语句 73 | def auto_select(self, table, fields="*"): 74 | 75 | cmd = "select * from {};".format(table) 76 | 77 | if fields != "*": 78 | f = ', '.join(list(map(lambda x: x, fields))) 79 | cmd = "select {} from {};".format(f, table) 80 | return cmd 81 | 82 | # 插入emb 83 | def update_face_emb(self, db_path, table, id, data): 84 | print(data) 85 | emb_str = '' 86 | for i in range(len(data)): 87 | emb_str += str(data[i]) + ' ' 88 | print(emb_str) 89 | cmd = 'UPDATE {table_name} SET features = "{emb}" WHERE id = {id};'.format(table_name=table, 90 | emb=emb_str, id=id) 91 | self.executeCMD(db_path, cmd) 92 | 93 | # 更新考勤 94 | def update_checkwork(self, db_path, table, id): 95 | cmd = 'UPDATE {table_name} SET flag = "{f}" WHERE id = {id};'.format(table_name=table, 96 | f="1", id=id) 97 | self.executeCMD(db_path, cmd) 98 | print("update checkwork done") 99 | 100 | # 更新 101 | def update(self, db_path, table, field, data, primary_key_index): 102 | print("upate new date...") 103 | 104 | for info in data: 105 | # 检查id是否被修改 106 | cmd = "select * from {} where {}='{}'".format(table,field[primary_key_index], info[primary_key_index]) 107 | print("cmd->",cmd) 108 | ret = self.executeCMD(db_path, cmd) 109 | if ret == []: 110 | # 主键被修改 111 | return -3 112 | 113 | print("new data->", data) 114 | for info in data: 115 | for i in range(len(info)): 116 | if info == "": 117 | print("数据为空") 118 | return -1 119 | 120 | # 删除修改的数据项 121 | # DELETE FROM table_name WHERE primary key=val; 122 | print("删除旧数据") 123 | for i in range(len(data)): 124 | cmd = "delete from {} where {}='{}';".format(str(table), field[primary_key_index], 125 | data[i][primary_key_index]) 126 | print("execute cmd={}".format(cmd)) 127 | ret = self.executeCMD(db_path, cmd) 128 | if ret == []: 129 | print("delete success") 130 | 131 | # 插入新数据 132 | # INSERT INTO TABLE_NAME VALUES (value1,value2,value3,...valueN); 133 | print("插入新数据") 134 | for info in data: 135 | print("new data:", info) 136 | ret = self.insert(db_path, table, info) 137 | print("ret:", ret) 138 | return ret 139 | 140 | # 查找一个表中的主键位置 141 | # para:db路径,表名 142 | # return primary_key_index,primary_key 143 | def find_primary_key(self, db_path, table): 144 | cmd = "pragma table_info ({});".format(str(table)) 145 | ret = self.executeCMD(db_path, cmd) 146 | print(ret) 147 | num = len(ret[0]) - 1 148 | for i in range(len(ret)): 149 | if ret[i][num] == 1: 150 | print("{}:{}是主键".format(i, ret[i][1])) 151 | return i, ret[i][1] 152 | 153 | # 删除 154 | # param:表,主键,参数 155 | def delete(self, db_path, table_name, primary_key, primary_key_index, data): 156 | # DELETE FROM table_name WHERE [condition]; 157 | cmd = "DELETE FROM {} WHERE {}='{}';".format(table_name, primary_key, data[primary_key_index]) 158 | print("del cmd:", cmd) 159 | self.executeCMD(db_path, cmd) 160 | 161 | def insert(self, db_path, table, data): 162 | # INSERT INTO TABLE_NAME VALUES (value1,value2,value3,...valueN); 163 | for i in data: 164 | if i == "": 165 | print("数据为空") 166 | return -1 167 | cmd = ', '.join(list(map(lambda x: "'" + x + "'", data))) 168 | cmd = "INSERT INTO {} VALUES ({});".format(table, cmd) 169 | print("execute cmd={}\n".format(cmd)) 170 | try: 171 | ret = self.executeCMD(db_path, cmd) 172 | except: 173 | return -2 174 | return 0 175 | 176 | def delete_table(self, db_path, table_name): 177 | cmd = "DROP TABLE {};".format(table_name) 178 | print(cmd) 179 | self.executeCMD(db_path, cmd) 180 | 181 | # param->table_type: 182 | def create_table(self, db_path, table_name, db_type): 183 | 184 | print("create_table") 185 | cmd = self.dict_cmd[db_type].format(table_name) 186 | print(cmd) 187 | 188 | # 检查表名是否重复 189 | table_list = self.check_table(db_path) 190 | for i in table_list: 191 | if i == table_name: 192 | print("表名重复") 193 | return 194 | 195 | # 检查类型是否正确 196 | self.executeCMD(db_path, cmd) 197 | 198 | 199 | # 200 | 201 | if __name__ == "__main__": 202 | t = Sqlite_Func() 203 | print(t.dict_cmd) 204 | -------------------------------------------------------------------------------- /ui_src/addClassTable.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'addClassTable.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.9.2 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_AddClassTable(object): 12 | def setupUi(self, Form): 13 | Form.setObjectName("Form") 14 | Form.resize(496, 255) 15 | self.layoutWidget = QtWidgets.QWidget(Form) 16 | self.layoutWidget.setGeometry(QtCore.QRect(70, 50, 344, 164)) 17 | self.layoutWidget.setObjectName("layoutWidget") 18 | self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.layoutWidget) 19 | self.verticalLayout_4.setContentsMargins(0, 0, 0, 0) 20 | self.verticalLayout_4.setObjectName("verticalLayout_4") 21 | self.verticalLayout_3 = QtWidgets.QVBoxLayout() 22 | self.verticalLayout_3.setObjectName("verticalLayout_3") 23 | self.lab_addTest_8 = QtWidgets.QLabel(self.layoutWidget) 24 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) 25 | sizePolicy.setHorizontalStretch(0) 26 | sizePolicy.setVerticalStretch(0) 27 | sizePolicy.setHeightForWidth(self.lab_addTest_8.sizePolicy().hasHeightForWidth()) 28 | self.lab_addTest_8.setSizePolicy(sizePolicy) 29 | font = QtGui.QFont() 30 | font.setPointSize(16) 31 | self.lab_addTest_8.setFont(font) 32 | self.lab_addTest_8.setLayoutDirection(QtCore.Qt.LeftToRight) 33 | self.lab_addTest_8.setAlignment(QtCore.Qt.AlignCenter) 34 | self.lab_addTest_8.setObjectName("lab_addTest_8") 35 | self.verticalLayout_3.addWidget(self.lab_addTest_8) 36 | self.horizontalLayout = QtWidgets.QHBoxLayout() 37 | self.horizontalLayout.setObjectName("horizontalLayout") 38 | self.verticalLayout = QtWidgets.QVBoxLayout() 39 | self.verticalLayout.setObjectName("verticalLayout") 40 | self.lab_addTest_6 = QtWidgets.QLabel(self.layoutWidget) 41 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) 42 | sizePolicy.setHorizontalStretch(0) 43 | sizePolicy.setVerticalStretch(0) 44 | sizePolicy.setHeightForWidth(self.lab_addTest_6.sizePolicy().hasHeightForWidth()) 45 | self.lab_addTest_6.setSizePolicy(sizePolicy) 46 | font = QtGui.QFont() 47 | font.setPointSize(16) 48 | self.lab_addTest_6.setFont(font) 49 | self.lab_addTest_6.setLayoutDirection(QtCore.Qt.LeftToRight) 50 | self.lab_addTest_6.setAlignment(QtCore.Qt.AlignCenter) 51 | self.lab_addTest_6.setObjectName("lab_addTest_6") 52 | self.verticalLayout.addWidget(self.lab_addTest_6) 53 | self.lab_addTest_7 = QtWidgets.QLabel(self.layoutWidget) 54 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) 55 | sizePolicy.setHorizontalStretch(0) 56 | sizePolicy.setVerticalStretch(0) 57 | sizePolicy.setHeightForWidth(self.lab_addTest_7.sizePolicy().hasHeightForWidth()) 58 | self.lab_addTest_7.setSizePolicy(sizePolicy) 59 | font = QtGui.QFont() 60 | font.setPointSize(16) 61 | self.lab_addTest_7.setFont(font) 62 | self.lab_addTest_7.setLayoutDirection(QtCore.Qt.LeftToRight) 63 | self.lab_addTest_7.setAlignment(QtCore.Qt.AlignCenter) 64 | self.lab_addTest_7.setObjectName("lab_addTest_7") 65 | self.verticalLayout.addWidget(self.lab_addTest_7) 66 | self.horizontalLayout.addLayout(self.verticalLayout) 67 | self.verticalLayout_2 = QtWidgets.QVBoxLayout() 68 | self.verticalLayout_2.setObjectName("verticalLayout_2") 69 | self.line_profession = QtWidgets.QLineEdit(self.layoutWidget) 70 | self.line_profession.setEnabled(True) 71 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) 72 | sizePolicy.setHorizontalStretch(0) 73 | sizePolicy.setVerticalStretch(0) 74 | sizePolicy.setHeightForWidth(self.line_profession.sizePolicy().hasHeightForWidth()) 75 | self.line_profession.setSizePolicy(sizePolicy) 76 | font = QtGui.QFont() 77 | font.setPointSize(16) 78 | self.line_profession.setFont(font) 79 | self.line_profession.setLayoutDirection(QtCore.Qt.LeftToRight) 80 | self.line_profession.setObjectName("line_profession") 81 | self.verticalLayout_2.addWidget(self.line_profession) 82 | self.line_class = QtWidgets.QLineEdit(self.layoutWidget) 83 | self.line_class.setEnabled(True) 84 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) 85 | sizePolicy.setHorizontalStretch(0) 86 | sizePolicy.setVerticalStretch(0) 87 | sizePolicy.setHeightForWidth(self.line_class.sizePolicy().hasHeightForWidth()) 88 | self.line_class.setSizePolicy(sizePolicy) 89 | font = QtGui.QFont() 90 | font.setPointSize(16) 91 | self.line_class.setFont(font) 92 | self.line_class.setLayoutDirection(QtCore.Qt.LeftToRight) 93 | self.line_class.setObjectName("line_class") 94 | self.verticalLayout_2.addWidget(self.line_class) 95 | self.horizontalLayout.addLayout(self.verticalLayout_2) 96 | self.verticalLayout_3.addLayout(self.horizontalLayout) 97 | self.verticalLayout_4.addLayout(self.verticalLayout_3) 98 | self.horizontalLayout_2 = QtWidgets.QHBoxLayout() 99 | self.horizontalLayout_2.setObjectName("horizontalLayout_2") 100 | self.btn_confirm = QtWidgets.QPushButton(self.layoutWidget) 101 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) 102 | sizePolicy.setHorizontalStretch(0) 103 | sizePolicy.setVerticalStretch(0) 104 | sizePolicy.setHeightForWidth(self.btn_confirm.sizePolicy().hasHeightForWidth()) 105 | self.btn_confirm.setSizePolicy(sizePolicy) 106 | self.btn_confirm.setMaximumSize(QtCore.QSize(200, 60)) 107 | font = QtGui.QFont() 108 | font.setPointSize(16) 109 | font.setBold(False) 110 | font.setWeight(50) 111 | self.btn_confirm.setFont(font) 112 | self.btn_confirm.setLayoutDirection(QtCore.Qt.LeftToRight) 113 | self.btn_confirm.setObjectName("btn_confirm") 114 | self.horizontalLayout_2.addWidget(self.btn_confirm) 115 | self.btn_cancel = QtWidgets.QPushButton(self.layoutWidget) 116 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) 117 | sizePolicy.setHorizontalStretch(0) 118 | sizePolicy.setVerticalStretch(0) 119 | sizePolicy.setHeightForWidth(self.btn_cancel.sizePolicy().hasHeightForWidth()) 120 | self.btn_cancel.setSizePolicy(sizePolicy) 121 | self.btn_cancel.setMaximumSize(QtCore.QSize(200, 60)) 122 | font = QtGui.QFont() 123 | font.setPointSize(16) 124 | font.setBold(False) 125 | font.setWeight(50) 126 | self.btn_cancel.setFont(font) 127 | self.btn_cancel.setLayoutDirection(QtCore.Qt.LeftToRight) 128 | self.btn_cancel.setObjectName("btn_cancel") 129 | self.horizontalLayout_2.addWidget(self.btn_cancel) 130 | self.verticalLayout_4.addLayout(self.horizontalLayout_2) 131 | 132 | self.retranslateUi(Form) 133 | QtCore.QMetaObject.connectSlotsByName(Form) 134 | 135 | def retranslateUi(self, Form): 136 | _translate = QtCore.QCoreApplication.translate 137 | Form.setWindowTitle(_translate("Form", "添加班级表")) 138 | self.lab_addTest_8.setText(_translate("Form", "添加人脸数据表")) 139 | self.lab_addTest_6.setText(_translate("Form", "院系")) 140 | self.lab_addTest_7.setText(_translate("Form", "班级")) 141 | self.btn_confirm.setText(_translate("Form", "确定")) 142 | self.btn_cancel.setText(_translate("Form", "取消")) 143 | 144 | -------------------------------------------------------------------------------- /ui_src/sqlite_main_window.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | SqliteMainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 922 10 | 688 11 | 12 | 13 | 14 | Sqlite Main Window 15 | 16 | 17 | 18 | 19 | 20 | 21 | 选择一个表和若干字段 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 16 33 | 34 | 35 | 36 | 37 | 38 | 39 | Qt::AlignCenter 40 | 41 | 42 | 43 | 44 | 45 | 46 | true 47 | 48 | 49 | 50 | 51 | 0 52 | 0 53 | 182 54 | 497 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 16 71 | 72 | 73 | 74 | 字段 75 | 76 | 77 | Qt::AlignCenter 78 | 79 | 80 | 81 | 82 | 83 | 84 | true 85 | 86 | 87 | 88 | 89 | 0 90 | 0 91 | 180 92 | 412 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 12 113 | 114 | 115 | 116 | 全不选 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 12 125 | 126 | 127 | 128 | 全选 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 创建新表 155 | 156 | 157 | 158 | 159 | 160 | 161 | 删除表 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 添加数据 173 | 174 | 175 | 176 | 177 | 178 | 179 | 删除数据 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 更新数据 191 | 192 | 193 | 194 | 195 | 196 | 197 | 查询数据 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 16 210 | 211 | 212 | 213 | 命令 214 | 215 | 216 | Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 0 229 | 0 230 | 922 231 | 23 232 | 233 | 234 | 235 | 236 | File 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | Open File 246 | 247 | 248 | 249 | 250 | 251 | 252 | -------------------------------------------------------------------------------- /src/SetUpMainWindow.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import sys 3 | import time 4 | import os 5 | 6 | from PyQt5.QtWidgets import * 7 | from PyQt5 import QtCore, QtGui, QtWidgets 8 | from PyQt5.QtWidgets import QMainWindow, QApplication 9 | 10 | import get_face 11 | import face_recognition 12 | # from file_op import File_Operate 13 | # from sqlite3_op import Operate_Sql 14 | from tools.sqlite_func import Sqlite_Func 15 | 16 | from ui_src.MainUI import Ui_Face_Recognition_window 17 | from Sqlite_UI import Sqlite_UI 18 | 19 | 20 | # 主窗口类 21 | class MainWindow(QMainWindow, Ui_Face_Recognition_window): 22 | # 构造函数 23 | def __init__(self, parent=None): 24 | super(MainWindow, self).__init__(parent) 25 | self.setupUi(self) 26 | 27 | self.sf = Sqlite_Func() 28 | 29 | # self.opsql = Operate_Sql() 30 | 31 | self.timer_camera_test = QtCore.QTimer() # qt计数器 32 | self.timer_camera_face = QtCore.QTimer() # qt计数器 33 | 34 | self.openSqlite = Sqlite_UI() # 数据库对象 35 | self.slot_init() 36 | 37 | self.combobox_face_init() # 初始化下拉列表:人脸数据表 38 | self.combobox_checkWork_init() # 初始化下拉列表:考勤数据表 39 | 40 | self.photoNum = 0 # 照片计数 41 | self.CAM_NUM = 0 42 | self.pNum = 0 # 照片计数器 43 | self.photo_transmission = 0 # 图片传输变量 44 | self.frame_out = 0 45 | 46 | # 启动Facenet模块 47 | self.face = face_recognition.face() 48 | self.init_db() 49 | 50 | def init_db(self): 51 | if os.path.exists("../DB/StudentFaceDB.db") is False: 52 | os.mkdir("../DB/StudentFaceDB.db") 53 | if os.path.exists("../DB/StudentCheckWorkDB.db.db") is False: 54 | os.mkdir("../DB/StudentCheckWorkDB.db.db") 55 | 56 | # 槽初始化 57 | def slot_init(self): 58 | 59 | self.timer_camera_test.timeout.connect(self.show_frame) 60 | 61 | self.btn_openCamera.clicked.connect(self.opencamera) 62 | self.btn_takePhoto.clicked.connect(self.take_photo) 63 | 64 | self.btn_refresh.clicked.connect(self.refresh) 65 | 66 | self.btn_train.clicked.connect(self.train) 67 | self.btn_recogniton.clicked.connect(self.open_recognition_camera) 68 | self.btn_sqlite.clicked.connect(self.open_sqlite) 69 | 70 | def open_sqlite(self): 71 | self.openSqlite.show() 72 | 73 | def opencamera(self): 74 | if self.timer_camera_test.isActive() == False: 75 | self.cap = cv2.VideoCapture(0) 76 | flag = self.cap.open(self.CAM_NUM) 77 | if flag is None: 78 | msg = QtWidgets.QMessageBox.warning(self, u"Warning", u"摄像头无法打开!", 79 | buttons=QtWidgets.QMessageBox.Ok, 80 | defaultButton=QtWidgets.QMessageBox.Ok) 81 | self.btn_openCamera.setText("关闭摄像头") 82 | self.timer_camera_test.start(25) 83 | else: 84 | self.btn_openCamera.setText(u"打开摄像头") 85 | self.timer_camera_test.stop() 86 | self.lab_frame.setText(u"无图像输入") 87 | self.cap.release() 88 | 89 | def show_frame(self): 90 | ret, frame = self.cap.read() 91 | if frame is None: 92 | return 93 | frame = cv2.flip(frame, 1) 94 | frame = cv2.resize(frame, (640, 480)) 95 | self.photo_transmission = frame 96 | frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) 97 | lable = cv2.putText(frame, '-->Camera OK', (10, 30), cv2.FONT_HERSHEY_COMPLEX_SMALL, 1, (0, 255, 0), 98 | thickness=1, lineType=1) 99 | showFrame = QtGui.QImage(frame.data, frame.shape[1], frame.shape[0], QtGui.QImage.Format_RGB888) 100 | self.lab_frame.setPixmap(QtGui.QPixmap.fromImage(showFrame)) 101 | 102 | # 拍照 103 | def take_photo(self): 104 | ''' 105 | 1、从数据库中读取所有文件名 106 | 2、从文件名中选择文件目录作为照片存储地址 107 | 3、调用拍照程序对当前画面进行拍照 108 | 4、更新拍照数量 109 | ''' 110 | 111 | # 如果摄像头没有打开 112 | if self.btn_openCamera.text() != '关闭摄像头': 113 | msg = QtWidgets.QMessageBox.warning(self, u"Warning", u"请打开摄像头!", 114 | buttons=QtWidgets.QMessageBox.Ok, 115 | defaultButton=QtWidgets.QMessageBox.Ok) 116 | else: 117 | face = self.comboBox_face.currentText() 118 | id = self.comboBox_id.currentText() 119 | if id == '' or id is None: 120 | msg = QtWidgets.QMessageBox.warning(self, u"Warning", u"请选择学号!", 121 | buttons=QtWidgets.QMessageBox.Ok, 122 | defaultButton=QtWidgets.QMessageBox.Ok) 123 | else: 124 | name = '{CLASS}#{id}'.format(CLASS=face, id=id) 125 | name = '../src_img/{name}.jpg'.format(name=name) 126 | print(name) 127 | cv2.imwrite(name, self.photo_transmission) 128 | 129 | # 考勤表初始化 130 | def combobox_checkWork_init(self, checktable=None): 131 | self.comboBox_checkWork.clear() 132 | 133 | ret = self.sf.check_table(self.sf.DB_STUDENTCHECKWORK_PATH) 134 | print("DB:{}\ntables:{}\ntable_nmu:{}".format(self.sf.DB_STUDENTCHECKWORK_PATH, ret, len(ret))) 135 | 136 | readlines = len(ret) 137 | lineindex = 0 138 | 139 | while lineindex < readlines: 140 | self.comboBox_checkWork.addItem(ret[lineindex]) 141 | lineindex += 1 142 | if checktable != '' or checktable is None: 143 | self.comboBox_checkWork.setCurrentText(checktable) 144 | print('combobox_checkWork_init done\n') 145 | 146 | # 获取人脸数据表 147 | def combobox_face_init(self, checked_table=None): 148 | self.comboBox_face.clear() 149 | ret = self.sf.check_table(self.sf.DB_STUDENTFACE_PATH) 150 | table_nmu = len(ret) 151 | print("DB:{}\ntables:{}\ntable_nmu:{}".format(self.sf.DB_STUDENTFACE_PATH, ret, len(ret))) 152 | readlines = table_nmu 153 | lineindex = 0 154 | 155 | while lineindex < readlines: 156 | self.comboBox_face.addItem(ret[lineindex]) 157 | lineindex += 1 158 | if checked_table != '' or checked_table is None: 159 | self.comboBox_face.setCurrentText(checked_table) 160 | print('combobox_face_init done\n') 161 | 162 | # 初始化id列表 163 | self.combobox_id_init(self.comboBox_face.currentText()) 164 | 165 | def combobox_id_init(self, table): 166 | # if table == "": 167 | # return 168 | # 读取人脸数据库中所有id 169 | field = [] 170 | field.append("id") 171 | print('====', table) 172 | cmd = self.sf.auto_select(table, field) 173 | print("cmd-->", cmd) 174 | ret = self.sf.executeCMD(self.sf.DB_STUDENTFACE_PATH, cmd) 175 | print("ret:", ret) 176 | 177 | self.comboBox_id.clear() 178 | print(len(ret)) 179 | for i in range(len(ret)): 180 | self.comboBox_id.addItem(str(ret[i][0])) 181 | 182 | # 刷新显示数据库并且显示id号 183 | def refresh(self): 184 | 185 | # 获取当前选中表明 186 | checked_face = self.comboBox_face.currentText() 187 | checked_cw = self.comboBox_checkWork.currentText() 188 | 189 | print("当前选中:{},{}".format(checked_face, checked_cw)) 190 | 191 | self.combobox_face_init(checked_table=checked_face) 192 | self.combobox_checkWork_init(checktable=checked_cw) 193 | 194 | def train(self): 195 | 196 | ret = QMessageBox.question(self, "Train", "训练过程中,画面无法更新,训练时间随机器性能决定", QMessageBox.Yes | QMessageBox.No, 197 | QMessageBox.No) 198 | if ret == QMessageBox.Yes: 199 | get_face.detection() 200 | 201 | # 打开识别摄像头 202 | def open_recognition_camera(self): 203 | 204 | if self.btn_openCamera.text() == '关闭摄像头': 205 | msg = QtWidgets.QMessageBox.warning(self, u"警告", u"请先关闭摄像头!", 206 | buttons=QtWidgets.QMessageBox.Ok, 207 | defaultButton=QtWidgets.QMessageBox.Ok) 208 | else: 209 | ret = QMessageBox.question(self, "Train", "1、启动时间根据设备性能强弱决定\n\n2、程序启动后按下esc退出检测窗口", 210 | QMessageBox.Yes | QMessageBox.No, 211 | QMessageBox.No) 212 | if ret == QMessageBox.Yes: 213 | print('开启摄像头') 214 | face = self.comboBox_face.currentText() 215 | cw = self.comboBox_checkWork.currentText() 216 | self.face.main(face, cw) 217 | 218 | 219 | if __name__ == "__main__": 220 | app = QApplication(sys.argv) 221 | ui = MainWindow() 222 | ui.show() 223 | sys.exit((app.exec_())) 224 | -------------------------------------------------------------------------------- /ui_src/sqlite_main_window.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'sqlite_main_window.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.9.2 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_SqliteMainWindow(object): 12 | def setupUi(self, SqliteMainWindow): 13 | SqliteMainWindow.setObjectName("SqliteMainWindow") 14 | SqliteMainWindow.resize(922, 688) 15 | self.centralwidget = QtWidgets.QWidget(SqliteMainWindow) 16 | self.centralwidget.setObjectName("centralwidget") 17 | self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) 18 | self.gridLayout.setObjectName("gridLayout") 19 | self.groupBox_table_field = QtWidgets.QGroupBox(self.centralwidget) 20 | self.groupBox_table_field.setObjectName("groupBox_table_field") 21 | self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.groupBox_table_field) 22 | self.horizontalLayout_2.setObjectName("horizontalLayout_2") 23 | self.horizontalLayout = QtWidgets.QHBoxLayout() 24 | self.horizontalLayout.setObjectName("horizontalLayout") 25 | self.verticalLayout_6 = QtWidgets.QVBoxLayout() 26 | self.verticalLayout_6.setObjectName("verticalLayout_6") 27 | self.label_table = QtWidgets.QLabel(self.groupBox_table_field) 28 | font = QtGui.QFont() 29 | font.setPointSize(16) 30 | self.label_table.setFont(font) 31 | self.label_table.setAlignment(QtCore.Qt.AlignCenter) 32 | self.label_table.setObjectName("label_table") 33 | self.verticalLayout_6.addWidget(self.label_table) 34 | self.scrollArea_table = QtWidgets.QScrollArea(self.groupBox_table_field) 35 | self.scrollArea_table.setWidgetResizable(True) 36 | self.scrollArea_table.setObjectName("scrollArea_table") 37 | self.scrollAreaWidgetContents = QtWidgets.QWidget() 38 | self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 182, 497)) 39 | self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents") 40 | self.scrollArea_table.setWidget(self.scrollAreaWidgetContents) 41 | self.verticalLayout_6.addWidget(self.scrollArea_table) 42 | self.horizontalLayout.addLayout(self.verticalLayout_6) 43 | self.verticalLayout_5 = QtWidgets.QVBoxLayout() 44 | self.verticalLayout_5.setObjectName("verticalLayout_5") 45 | self.verticalLayout_4 = QtWidgets.QVBoxLayout() 46 | self.verticalLayout_4.setObjectName("verticalLayout_4") 47 | self.label_field = QtWidgets.QLabel(self.groupBox_table_field) 48 | font = QtGui.QFont() 49 | font.setPointSize(16) 50 | self.label_field.setFont(font) 51 | self.label_field.setAlignment(QtCore.Qt.AlignCenter) 52 | self.label_field.setObjectName("label_field") 53 | self.verticalLayout_4.addWidget(self.label_field) 54 | self.scrollArea_field = QtWidgets.QScrollArea(self.groupBox_table_field) 55 | self.scrollArea_field.setWidgetResizable(True) 56 | self.scrollArea_field.setObjectName("scrollArea_field") 57 | self.scrollAreaWidgetContents_2 = QtWidgets.QWidget() 58 | self.scrollAreaWidgetContents_2.setGeometry(QtCore.QRect(0, 0, 180, 412)) 59 | self.scrollAreaWidgetContents_2.setObjectName("scrollAreaWidgetContents_2") 60 | self.scrollArea_field.setWidget(self.scrollAreaWidgetContents_2) 61 | self.verticalLayout_4.addWidget(self.scrollArea_field) 62 | self.verticalLayout_5.addLayout(self.verticalLayout_4) 63 | self.groupBox = QtWidgets.QGroupBox(self.groupBox_table_field) 64 | self.groupBox.setTitle("") 65 | self.groupBox.setObjectName("groupBox") 66 | self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.groupBox) 67 | self.verticalLayout_3.setObjectName("verticalLayout_3") 68 | self.horizontalLayout_3 = QtWidgets.QHBoxLayout() 69 | self.horizontalLayout_3.setObjectName("horizontalLayout_3") 70 | self.radioButton_notall = QtWidgets.QRadioButton(self.groupBox) 71 | font = QtGui.QFont() 72 | font.setPointSize(12) 73 | self.radioButton_notall.setFont(font) 74 | self.radioButton_notall.setObjectName("radioButton_notall") 75 | self.horizontalLayout_3.addWidget(self.radioButton_notall) 76 | self.radioButton_all = QtWidgets.QRadioButton(self.groupBox) 77 | font = QtGui.QFont() 78 | font.setPointSize(12) 79 | self.radioButton_all.setFont(font) 80 | self.radioButton_all.setObjectName("radioButton_all") 81 | self.horizontalLayout_3.addWidget(self.radioButton_all) 82 | self.verticalLayout_3.addLayout(self.horizontalLayout_3) 83 | self.verticalLayout_5.addWidget(self.groupBox) 84 | self.horizontalLayout.addLayout(self.verticalLayout_5) 85 | self.horizontalLayout_2.addLayout(self.horizontalLayout) 86 | self.gridLayout.addWidget(self.groupBox_table_field, 0, 0, 1, 1) 87 | self.tableView_content = QtWidgets.QTableView(self.centralwidget) 88 | self.tableView_content.setObjectName("tableView_content") 89 | self.gridLayout.addWidget(self.tableView_content, 0, 1, 1, 1) 90 | self.verticalLayout_8 = QtWidgets.QVBoxLayout() 91 | self.verticalLayout_8.setObjectName("verticalLayout_8") 92 | self.verticalLayout = QtWidgets.QVBoxLayout() 93 | self.verticalLayout.setObjectName("verticalLayout") 94 | self.pushButton_newTable = QtWidgets.QPushButton(self.centralwidget) 95 | self.pushButton_newTable.setObjectName("pushButton_newTable") 96 | self.verticalLayout.addWidget(self.pushButton_newTable) 97 | self.pushButton_delTable = QtWidgets.QPushButton(self.centralwidget) 98 | self.pushButton_delTable.setObjectName("pushButton_delTable") 99 | self.verticalLayout.addWidget(self.pushButton_delTable) 100 | self.verticalLayout_8.addLayout(self.verticalLayout) 101 | self.verticalLayout_2 = QtWidgets.QVBoxLayout() 102 | self.verticalLayout_2.setObjectName("verticalLayout_2") 103 | self.pushButton_add = QtWidgets.QPushButton(self.centralwidget) 104 | self.pushButton_add.setObjectName("pushButton_add") 105 | self.verticalLayout_2.addWidget(self.pushButton_add) 106 | self.pushButton_del = QtWidgets.QPushButton(self.centralwidget) 107 | self.pushButton_del.setObjectName("pushButton_del") 108 | self.verticalLayout_2.addWidget(self.pushButton_del) 109 | self.verticalLayout_8.addLayout(self.verticalLayout_2) 110 | self.verticalLayout_7 = QtWidgets.QVBoxLayout() 111 | self.verticalLayout_7.setObjectName("verticalLayout_7") 112 | self.pushButton_update = QtWidgets.QPushButton(self.centralwidget) 113 | self.pushButton_update.setObjectName("pushButton_update") 114 | self.verticalLayout_7.addWidget(self.pushButton_update) 115 | self.pushButton_query = QtWidgets.QPushButton(self.centralwidget) 116 | self.pushButton_query.setObjectName("pushButton_query") 117 | self.verticalLayout_7.addWidget(self.pushButton_query) 118 | self.verticalLayout_8.addLayout(self.verticalLayout_7) 119 | self.gridLayout.addLayout(self.verticalLayout_8, 0, 2, 1, 1) 120 | self.label_cmd = QtWidgets.QLabel(self.centralwidget) 121 | font = QtGui.QFont() 122 | font.setPointSize(16) 123 | self.label_cmd.setFont(font) 124 | self.label_cmd.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) 125 | self.label_cmd.setObjectName("label_cmd") 126 | self.gridLayout.addWidget(self.label_cmd, 1, 0, 1, 1) 127 | self.lineEdit_cmd = QtWidgets.QLineEdit(self.centralwidget) 128 | self.lineEdit_cmd.setObjectName("lineEdit_cmd") 129 | self.gridLayout.addWidget(self.lineEdit_cmd, 1, 1, 1, 1) 130 | SqliteMainWindow.setCentralWidget(self.centralwidget) 131 | self.menubar = QtWidgets.QMenuBar(SqliteMainWindow) 132 | self.menubar.setGeometry(QtCore.QRect(0, 0, 922, 23)) 133 | self.menubar.setObjectName("menubar") 134 | self.menuFile = QtWidgets.QMenu(self.menubar) 135 | self.menuFile.setObjectName("menuFile") 136 | SqliteMainWindow.setMenuBar(self.menubar) 137 | self.statusbar = QtWidgets.QStatusBar(SqliteMainWindow) 138 | self.statusbar.setObjectName("statusbar") 139 | SqliteMainWindow.setStatusBar(self.statusbar) 140 | self.actionOpen_File = QtWidgets.QAction(SqliteMainWindow) 141 | self.actionOpen_File.setObjectName("actionOpen_File") 142 | self.menuFile.addAction(self.actionOpen_File) 143 | self.menubar.addAction(self.menuFile.menuAction()) 144 | 145 | self.retranslateUi(SqliteMainWindow) 146 | QtCore.QMetaObject.connectSlotsByName(SqliteMainWindow) 147 | 148 | def retranslateUi(self, SqliteMainWindow): 149 | _translate = QtCore.QCoreApplication.translate 150 | SqliteMainWindow.setWindowTitle(_translate("SqliteMainWindow", "Sqlite Main Window")) 151 | self.groupBox_table_field.setTitle(_translate("SqliteMainWindow", "选择一个表和若干字段")) 152 | self.label_table.setText(_translate("SqliteMainWindow", "表")) 153 | self.label_field.setText(_translate("SqliteMainWindow", "字段")) 154 | self.radioButton_notall.setText(_translate("SqliteMainWindow", "全不选")) 155 | self.radioButton_all.setText(_translate("SqliteMainWindow", "全选")) 156 | self.pushButton_newTable.setText(_translate("SqliteMainWindow", "创建新表")) 157 | self.pushButton_delTable.setText(_translate("SqliteMainWindow", " 删除表")) 158 | self.pushButton_add.setText(_translate("SqliteMainWindow", "添加数据")) 159 | self.pushButton_del.setText(_translate("SqliteMainWindow", "删除数据")) 160 | self.pushButton_update.setText(_translate("SqliteMainWindow", "更新数据")) 161 | self.pushButton_query.setText(_translate("SqliteMainWindow", "查询数据")) 162 | self.label_cmd.setText(_translate("SqliteMainWindow", "命令")) 163 | self.menuFile.setTitle(_translate("SqliteMainWindow", "File")) 164 | self.actionOpen_File.setText(_translate("SqliteMainWindow", "Open File")) 165 | 166 | -------------------------------------------------------------------------------- /ui_src/MainUI.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Face_Recognition_window 4 | 5 | 6 | 7 | 0 8 | 0 9 | 843 10 | 694 11 | 12 | 13 | 14 | 15 | 843 16 | 694 17 | 18 | 19 | 20 | 21 | 843 22 | 694 23 | 24 | 25 | 26 | ArrowCursor 27 | 28 | 29 | 人脸识别1.0 30 | 31 | 32 | 33 | 34 | 35 | 30 36 | 40 37 | 798 38 | 603 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | true 48 | 49 | 50 | 51 | 641 52 | 481 53 | 54 | 55 | 56 | 57 | 641 58 | 481 59 | 60 | 61 | 62 | 63 | 30 64 | 50 65 | false 66 | 67 | 68 | 69 | 70 | 71 | 72 | 没有图像输入 73 | 74 | 75 | Qt::RichText 76 | 77 | 78 | Qt::AlignCenter 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 16 91 | 92 | 93 | 94 | 选择人脸数据表(Face) 95 | 96 | 97 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 16 106 | 107 | 108 | 109 | 选择学号(Face) 110 | 111 | 112 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 16 121 | 122 | 123 | 124 | 选择考勤表(CheckWork) 125 | 126 | 127 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 200 157 | 60 158 | 159 | 160 | 161 | 162 | 16 163 | 50 164 | false 165 | 166 | 167 | 168 | 打开摄像头 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 50 177 | 50 178 | 179 | 180 | 181 | 182 | 200 183 | 60 184 | 185 | 186 | 187 | 188 | 16 189 | 50 190 | false 191 | 192 | 193 | 194 | 数据库管理 195 | 196 | 197 | 100 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 200 206 | 60 207 | 208 | 209 | 210 | 211 | 16 212 | 50 213 | false 214 | 215 | 216 | 217 | 录入人脸 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 100 226 | 50 227 | 228 | 229 | 230 | 231 | 200 232 | 60 233 | 234 | 235 | 236 | 237 | 16 238 | 50 239 | false 240 | 241 | 242 | 243 | 生成模型 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 100 252 | 50 253 | 254 | 255 | 256 | 257 | 200 258 | 60 259 | 260 | 261 | 262 | 263 | 16 264 | 50 265 | false 266 | 267 | 268 | 269 | 开始检测 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 100 278 | 50 279 | 280 | 281 | 282 | 283 | 200 284 | 60 285 | 286 | 287 | 288 | 289 | 16 290 | 50 291 | false 292 | 293 | 294 | 295 | 刷新 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 0 308 | 0 309 | 843 310 | 23 311 | 312 | 313 | 314 | 315 | 316 | 317 | 添加人脸 318 | 319 | 320 | 321 | 322 | 删除人脸 323 | 324 | 325 | 326 | 327 | 操作细节 328 | 329 | 330 | 331 | 332 | 退出 333 | 334 | 335 | 336 | 337 | 关于作者 338 | 339 | 340 | 341 | 342 | 添加人脸数据表 343 | 344 | 345 | 346 | 347 | 删除人脸数据表 348 | 349 | 350 | 351 | 352 | 添加考勤表 353 | 354 | 355 | 356 | 357 | 删除考勤表 358 | 359 | 360 | 361 | 362 | 363 | 364 | -------------------------------------------------------------------------------- /ui_src/MainUI.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'MainUI.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.9.2 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_Face_Recognition_window(object): 12 | def setupUi(self, Face_Recognition_window): 13 | Face_Recognition_window.setObjectName("Face_Recognition_window") 14 | Face_Recognition_window.resize(843, 694) 15 | Face_Recognition_window.setMinimumSize(QtCore.QSize(843, 694)) 16 | Face_Recognition_window.setMaximumSize(QtCore.QSize(843, 694)) 17 | Face_Recognition_window.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) 18 | self.centralwidget = QtWidgets.QWidget(Face_Recognition_window) 19 | self.centralwidget.setObjectName("centralwidget") 20 | self.layoutWidget = QtWidgets.QWidget(self.centralwidget) 21 | self.layoutWidget.setGeometry(QtCore.QRect(30, 40, 798, 603)) 22 | self.layoutWidget.setObjectName("layoutWidget") 23 | self.horizontalLayout = QtWidgets.QHBoxLayout(self.layoutWidget) 24 | self.horizontalLayout.setContentsMargins(0, 0, 0, 0) 25 | self.horizontalLayout.setObjectName("horizontalLayout") 26 | self.verticalLayout = QtWidgets.QVBoxLayout() 27 | self.verticalLayout.setObjectName("verticalLayout") 28 | self.lab_frame = QtWidgets.QLabel(self.layoutWidget) 29 | self.lab_frame.setEnabled(True) 30 | self.lab_frame.setMinimumSize(QtCore.QSize(641, 481)) 31 | self.lab_frame.setMaximumSize(QtCore.QSize(641, 481)) 32 | font = QtGui.QFont() 33 | font.setPointSize(30) 34 | font.setBold(False) 35 | font.setWeight(50) 36 | self.lab_frame.setFont(font) 37 | self.lab_frame.setToolTip("") 38 | self.lab_frame.setTextFormat(QtCore.Qt.RichText) 39 | self.lab_frame.setAlignment(QtCore.Qt.AlignCenter) 40 | self.lab_frame.setObjectName("lab_frame") 41 | self.verticalLayout.addWidget(self.lab_frame) 42 | self.horizontalLayout_3 = QtWidgets.QHBoxLayout() 43 | self.horizontalLayout_3.setObjectName("horizontalLayout_3") 44 | self.verticalLayout_2 = QtWidgets.QVBoxLayout() 45 | self.verticalLayout_2.setObjectName("verticalLayout_2") 46 | self.lab_selecCalss = QtWidgets.QLabel(self.layoutWidget) 47 | font = QtGui.QFont() 48 | font.setPointSize(16) 49 | self.lab_selecCalss.setFont(font) 50 | self.lab_selecCalss.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) 51 | self.lab_selecCalss.setObjectName("lab_selecCalss") 52 | self.verticalLayout_2.addWidget(self.lab_selecCalss) 53 | self.lab_selecLable = QtWidgets.QLabel(self.layoutWidget) 54 | font = QtGui.QFont() 55 | font.setPointSize(16) 56 | self.lab_selecLable.setFont(font) 57 | self.lab_selecLable.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) 58 | self.lab_selecLable.setObjectName("lab_selecLable") 59 | self.verticalLayout_2.addWidget(self.lab_selecLable) 60 | self.lab_selecLable_2 = QtWidgets.QLabel(self.layoutWidget) 61 | font = QtGui.QFont() 62 | font.setPointSize(16) 63 | self.lab_selecLable_2.setFont(font) 64 | self.lab_selecLable_2.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) 65 | self.lab_selecLable_2.setObjectName("lab_selecLable_2") 66 | self.verticalLayout_2.addWidget(self.lab_selecLable_2) 67 | self.horizontalLayout_3.addLayout(self.verticalLayout_2) 68 | self.verticalLayout_3 = QtWidgets.QVBoxLayout() 69 | self.verticalLayout_3.setObjectName("verticalLayout_3") 70 | self.comboBox_face = QtWidgets.QComboBox(self.layoutWidget) 71 | self.comboBox_face.setObjectName("comboBox_face") 72 | self.verticalLayout_3.addWidget(self.comboBox_face) 73 | self.comboBox_id = QtWidgets.QComboBox(self.layoutWidget) 74 | self.comboBox_id.setObjectName("comboBox_id") 75 | self.verticalLayout_3.addWidget(self.comboBox_id) 76 | self.comboBox_checkWork = QtWidgets.QComboBox(self.layoutWidget) 77 | self.comboBox_checkWork.setObjectName("comboBox_checkWork") 78 | self.verticalLayout_3.addWidget(self.comboBox_checkWork) 79 | self.horizontalLayout_3.addLayout(self.verticalLayout_3) 80 | self.verticalLayout.addLayout(self.horizontalLayout_3) 81 | self.horizontalLayout.addLayout(self.verticalLayout) 82 | self.verticalLayout_4 = QtWidgets.QVBoxLayout() 83 | self.verticalLayout_4.setObjectName("verticalLayout_4") 84 | self.btn_openCamera = QtWidgets.QPushButton(self.layoutWidget) 85 | self.btn_openCamera.setMaximumSize(QtCore.QSize(200, 60)) 86 | font = QtGui.QFont() 87 | font.setPointSize(16) 88 | font.setBold(False) 89 | font.setWeight(50) 90 | self.btn_openCamera.setFont(font) 91 | self.btn_openCamera.setObjectName("btn_openCamera") 92 | self.verticalLayout_4.addWidget(self.btn_openCamera) 93 | self.btn_sqlite = QtWidgets.QPushButton(self.layoutWidget) 94 | self.btn_sqlite.setMinimumSize(QtCore.QSize(50, 50)) 95 | self.btn_sqlite.setMaximumSize(QtCore.QSize(200, 60)) 96 | font = QtGui.QFont() 97 | font.setPointSize(16) 98 | font.setBold(False) 99 | font.setWeight(50) 100 | self.btn_sqlite.setFont(font) 101 | self.btn_sqlite.setAutoRepeatInterval(100) 102 | self.btn_sqlite.setObjectName("btn_sqlite") 103 | self.verticalLayout_4.addWidget(self.btn_sqlite) 104 | self.btn_takePhoto = QtWidgets.QPushButton(self.layoutWidget) 105 | self.btn_takePhoto.setMaximumSize(QtCore.QSize(200, 60)) 106 | font = QtGui.QFont() 107 | font.setPointSize(16) 108 | font.setBold(False) 109 | font.setWeight(50) 110 | self.btn_takePhoto.setFont(font) 111 | self.btn_takePhoto.setObjectName("btn_takePhoto") 112 | self.verticalLayout_4.addWidget(self.btn_takePhoto) 113 | self.btn_train = QtWidgets.QPushButton(self.layoutWidget) 114 | self.btn_train.setMinimumSize(QtCore.QSize(100, 50)) 115 | self.btn_train.setMaximumSize(QtCore.QSize(200, 60)) 116 | font = QtGui.QFont() 117 | font.setPointSize(16) 118 | font.setBold(False) 119 | font.setWeight(50) 120 | self.btn_train.setFont(font) 121 | self.btn_train.setObjectName("btn_train") 122 | self.verticalLayout_4.addWidget(self.btn_train) 123 | self.btn_recogniton = QtWidgets.QPushButton(self.layoutWidget) 124 | self.btn_recogniton.setMinimumSize(QtCore.QSize(100, 50)) 125 | self.btn_recogniton.setMaximumSize(QtCore.QSize(200, 60)) 126 | font = QtGui.QFont() 127 | font.setPointSize(16) 128 | font.setBold(False) 129 | font.setWeight(50) 130 | self.btn_recogniton.setFont(font) 131 | self.btn_recogniton.setObjectName("btn_recogniton") 132 | self.verticalLayout_4.addWidget(self.btn_recogniton) 133 | self.btn_refresh = QtWidgets.QPushButton(self.layoutWidget) 134 | self.btn_refresh.setMinimumSize(QtCore.QSize(100, 50)) 135 | self.btn_refresh.setMaximumSize(QtCore.QSize(200, 60)) 136 | font = QtGui.QFont() 137 | font.setPointSize(16) 138 | font.setBold(False) 139 | font.setWeight(50) 140 | self.btn_refresh.setFont(font) 141 | self.btn_refresh.setObjectName("btn_refresh") 142 | self.verticalLayout_4.addWidget(self.btn_refresh) 143 | self.horizontalLayout.addLayout(self.verticalLayout_4) 144 | Face_Recognition_window.setCentralWidget(self.centralwidget) 145 | self.menubar = QtWidgets.QMenuBar(Face_Recognition_window) 146 | self.menubar.setGeometry(QtCore.QRect(0, 0, 843, 23)) 147 | self.menubar.setObjectName("menubar") 148 | Face_Recognition_window.setMenuBar(self.menubar) 149 | self.statusbar = QtWidgets.QStatusBar(Face_Recognition_window) 150 | self.statusbar.setObjectName("statusbar") 151 | Face_Recognition_window.setStatusBar(self.statusbar) 152 | self.actionAdd_Person = QtWidgets.QAction(Face_Recognition_window) 153 | self.actionAdd_Person.setObjectName("actionAdd_Person") 154 | self.actionDelete_Person = QtWidgets.QAction(Face_Recognition_window) 155 | self.actionDelete_Person.setObjectName("actionDelete_Person") 156 | self.actionHelp = QtWidgets.QAction(Face_Recognition_window) 157 | self.actionHelp.setObjectName("actionHelp") 158 | self.actionExit = QtWidgets.QAction(Face_Recognition_window) 159 | self.actionExit.setObjectName("actionExit") 160 | self.actionauthor = QtWidgets.QAction(Face_Recognition_window) 161 | self.actionauthor.setObjectName("actionauthor") 162 | self.actionAddClass = QtWidgets.QAction(Face_Recognition_window) 163 | self.actionAddClass.setObjectName("actionAddClass") 164 | self.actionDelClass = QtWidgets.QAction(Face_Recognition_window) 165 | self.actionDelClass.setObjectName("actionDelClass") 166 | self.actionAddCheck = QtWidgets.QAction(Face_Recognition_window) 167 | self.actionAddCheck.setObjectName("actionAddCheck") 168 | self.actionDelCheck = QtWidgets.QAction(Face_Recognition_window) 169 | self.actionDelCheck.setObjectName("actionDelCheck") 170 | 171 | self.retranslateUi(Face_Recognition_window) 172 | QtCore.QMetaObject.connectSlotsByName(Face_Recognition_window) 173 | 174 | def retranslateUi(self, Face_Recognition_window): 175 | _translate = QtCore.QCoreApplication.translate 176 | Face_Recognition_window.setWindowTitle(_translate("Face_Recognition_window", "人脸识别1.0")) 177 | self.lab_frame.setText(_translate("Face_Recognition_window", "没有图像输入")) 178 | self.lab_selecCalss.setText(_translate("Face_Recognition_window", "选择人脸数据表(Face)")) 179 | self.lab_selecLable.setText(_translate("Face_Recognition_window", "选择学号(Face)")) 180 | self.lab_selecLable_2.setText(_translate("Face_Recognition_window", "选择考勤表(CheckWork)")) 181 | self.btn_openCamera.setText(_translate("Face_Recognition_window", "打开摄像头")) 182 | self.btn_sqlite.setText(_translate("Face_Recognition_window", "数据库管理")) 183 | self.btn_takePhoto.setText(_translate("Face_Recognition_window", "录入人脸")) 184 | self.btn_train.setText(_translate("Face_Recognition_window", "生成模型")) 185 | self.btn_recogniton.setText(_translate("Face_Recognition_window", "开始检测")) 186 | self.btn_refresh.setText(_translate("Face_Recognition_window", "刷新")) 187 | self.actionAdd_Person.setText(_translate("Face_Recognition_window", "添加人脸")) 188 | self.actionDelete_Person.setText(_translate("Face_Recognition_window", "删除人脸")) 189 | self.actionHelp.setText(_translate("Face_Recognition_window", "操作细节")) 190 | self.actionExit.setText(_translate("Face_Recognition_window", "退出")) 191 | self.actionauthor.setText(_translate("Face_Recognition_window", "关于作者")) 192 | self.actionAddClass.setText(_translate("Face_Recognition_window", "添加人脸数据表")) 193 | self.actionDelClass.setText(_translate("Face_Recognition_window", "删除人脸数据表")) 194 | self.actionAddCheck.setText(_translate("Face_Recognition_window", "添加考勤表")) 195 | self.actionDelCheck.setText(_translate("Face_Recognition_window", "删除考勤表")) 196 | 197 | -------------------------------------------------------------------------------- /ui_src/addStudent.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Form 4 | 5 | 6 | 7 | 0 8 | 0 9 | 730 10 | 379 11 | 12 | 13 | 14 | 添加新用户 15 | 16 | 17 | 18 | 19 | 50 20 | 50 21 | 639 22 | 282 23 | 24 | 25 | 26 | 27 | 0 28 | 0 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 0 41 | 0 42 | 43 | 44 | 45 | 46 | 16 47 | 48 | 49 | 50 | Qt::LeftToRight 51 | 52 | 53 | 选择人脸数据表 54 | 55 | 56 | Qt::AlignCenter 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 0 65 | 0 66 | 67 | 68 | 69 | 70 | 16 71 | 72 | 73 | 74 | Qt::LeftToRight 75 | 76 | 77 | 添加用户标签(姓名拼音) 78 | 79 | 80 | Qt::AlignCenter 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 0 89 | 0 90 | 91 | 92 | 93 | 94 | 16 95 | 96 | 97 | 98 | Qt::LeftToRight 99 | 100 | 101 | 添加用户姓名 102 | 103 | 104 | Qt::AlignCenter 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 0 113 | 0 114 | 115 | 116 | 117 | 118 | 16 119 | 120 | 121 | 122 | Qt::LeftToRight 123 | 124 | 125 | 添加用户性别 126 | 127 | 128 | Qt::AlignCenter 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 0 137 | 0 138 | 139 | 140 | 141 | 142 | 16 143 | 144 | 145 | 146 | Qt::LeftToRight 147 | 148 | 149 | 添加用户学号 150 | 151 | 152 | Qt::AlignCenter 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 0 165 | 0 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | true 174 | 175 | 176 | 177 | 0 178 | 0 179 | 180 | 181 | 182 | 183 | 16 184 | 185 | 186 | 187 | Qt::LeftToRight 188 | 189 | 190 | 191 | 192 | 193 | 194 | true 195 | 196 | 197 | 198 | 0 199 | 0 200 | 201 | 202 | 203 | 204 | 16 205 | 206 | 207 | 208 | Qt::LeftToRight 209 | 210 | 211 | 212 | 213 | 214 | 215 | true 216 | 217 | 218 | 219 | 0 220 | 0 221 | 222 | 223 | 224 | 225 | 16 226 | 227 | 228 | 229 | Qt::LeftToRight 230 | 231 | 232 | 233 | 234 | 235 | 236 | true 237 | 238 | 239 | 240 | 0 241 | 0 242 | 243 | 244 | 245 | 246 | 16 247 | 248 | 249 | 250 | Qt::LeftToRight 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 0 265 | 0 266 | 267 | 268 | 269 | 270 | 200 271 | 60 272 | 273 | 274 | 275 | 276 | 16 277 | 50 278 | false 279 | 280 | 281 | 282 | Qt::LeftToRight 283 | 284 | 285 | 确定 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 0 294 | 0 295 | 296 | 297 | 298 | 299 | 200 300 | 60 301 | 302 | 303 | 304 | 305 | 16 306 | 50 307 | false 308 | 309 | 310 | 311 | Qt::LeftToRight 312 | 313 | 314 | 刷新 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 0 323 | 0 324 | 325 | 326 | 327 | 328 | 200 329 | 60 330 | 331 | 332 | 333 | 334 | 16 335 | 50 336 | false 337 | 338 | 339 | 340 | Qt::LeftToRight 341 | 342 | 343 | 取消 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | -------------------------------------------------------------------------------- /src/face_recognition.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from __future__ import division 3 | from __future__ import print_function 4 | 5 | import imageio 6 | import cv2 7 | import tensorflow as tf 8 | import numpy as np 9 | import os 10 | 11 | import facenet 12 | import align.detect_face 13 | from tools.sqlite_func import Sqlite_Func 14 | 15 | 16 | # 交并比 17 | def iou(a, b): 18 | area_a = (a[2] - a[0]) * (a[3] - a[1]) 19 | area_b = (b[2] - b[0]) * (b[3] - b[1]) 20 | 21 | iou_x1 = np.maximum(a[0], b[0]) 22 | iou_y1 = np.maximum(a[1], b[1]) 23 | iou_x2 = np.minimum(a[2], b[2]) 24 | iou_y2 = np.minimum(a[3], b[3]) 25 | 26 | iou_w = iou_x2 - iou_x1 27 | iou_h = iou_y2 - iou_y1 28 | area_iou = iou_w * iou_h 29 | iou = area_iou / (area_a + area_b - area_iou) 30 | 31 | return iou 32 | 33 | 34 | # 获取最大人脸索引 35 | def max_face(area, position): 36 | max_face_position = [] 37 | max_area_index = np.argmax(area) 38 | # print('最大面积索引:', np.argmax(area), '最大面积:', max(area)) 39 | max_face_position = position[max_area_index] 40 | return max_face_position 41 | 42 | 43 | class face(): 44 | def __init__(self): 45 | self.init_mtcnn() 46 | self.train = False 47 | self.sqlite = Sqlite_Func() 48 | 49 | # 初始化MTCNN 50 | def init_mtcnn(self): 51 | print('初始化MTCNN') 52 | with tf.Graph().as_default(): 53 | gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=1.0) 54 | sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options, 55 | log_device_placement=False)) 56 | with sess.as_default(): 57 | global pnet, rnet, onet 58 | pnet, rnet, onet = align.detect_face.create_mtcnn(sess, None) 59 | 60 | # 提前计算pre_embadding 61 | def init_pre_embdading(slef): 62 | print('初始化 Facenet') 63 | with tf.Graph().as_default(): 64 | with tf.Session() as sess: 65 | model = '../20170512-110547/' 66 | facenet.load_model(model) 67 | images_placeholder = tf.get_default_graph().get_tensor_by_name("input:0") 68 | embeddings = tf.get_default_graph().get_tensor_by_name("embeddings:0") 69 | phase_train_placeholder = tf.get_default_graph().get_tensor_by_name("phase_train:0") 70 | image = [] 71 | nrof_images = 0 72 | global compare_emb, compare_num, all_obj_name 73 | emb_dir = '../emb_img' 74 | all_obj_name = [] 75 | for i in os.listdir(emb_dir): 76 | all_obj_name.append(i) 77 | img = imageio.imread(os.path.join(emb_dir, i)) 78 | print('img.shape:', img.shape) 79 | prewhitened = facenet.prewhiten(img) # 预白化去除冗余信息 80 | image.append(prewhitened) 81 | nrof_images = nrof_images + 1 82 | # global compare_emb, compare_num 83 | images = np.stack(image) # 沿着新轴连接数组的序列。 84 | feed_dict = { 85 | images_placeholder: images, 86 | phase_train_placeholder: False} 87 | # 计算对比图片embadding,embdadding是一个128维的张量 88 | compare_emb = sess.run(embeddings, feed_dict=feed_dict) 89 | print('compare_emb:', compare_emb) 90 | print('compare_emb_shape:', compare_emb.shape) 91 | compare_num = len(compare_emb) 92 | print("pre_embadding计算完成") 93 | return compare_emb, compare_num, all_obj_name # 数据库embadding,人数,目录标签 94 | 95 | def main(self, face, checkwork): 96 | with tf.Graph().as_default(): 97 | with tf.Session() as sess: 98 | model = '../20170512-110547/' 99 | facenet.load_model(model) 100 | images_placeholder = tf.get_default_graph().get_tensor_by_name("input:0") 101 | embeddings = tf.get_default_graph().get_tensor_by_name("embeddings:0") 102 | phase_train_placeholder = tf.get_default_graph().get_tensor_by_name("phase_train:0") 103 | 104 | ''' 105 | id:学号 106 | compare_emb:特征值 107 | compare_num:数据库中的数据条数 108 | ''' 109 | 110 | # 找到当表主键 111 | face_key_idx, face_key = self.sqlite.find_primary_key(self.sqlite.DB_STUDENTFACE_PATH, face) 112 | # cw_key_idx,cw_key=self.sqlite.find_primary_key(self.sqlite.DB_STUDENTCHECKWORK_PATH,checkwork) 113 | 114 | # 从数据库获取人脸数据 115 | cmd = self.sqlite.auto_select(face) 116 | rows = self.sqlite.executeCMD(self.sqlite.DB_STUDENTFACE_PATH, cmd) 117 | 118 | id = [] 119 | 120 | num = len(rows) 121 | emb_idx = len(rows[0]) - 1 122 | 123 | compare_num = num 124 | compare_emb = np.zeros([num, 128]) 125 | 126 | for lineIndex in range(num): 127 | row = rows[lineIndex] # 获取某一行的数据,类型是tuple 128 | id.append(row[face_key_idx]) # 获取id 129 | emb_str = row[emb_idx] # 获取一个组数据中的emb数据 130 | if emb_str is None: 131 | compare_emb[lineIndex] = np.full((1, 128), 10) 132 | else: 133 | str_list = emb_str.split(' ') # 以空格分割字符串 134 | if len(str_list) < 10: 135 | continue 136 | for i in range(128): 137 | compare_emb[lineIndex][i] = float(str_list[i]) # 'list转ndarray:',str->float 138 | 139 | capture = cv2.VideoCapture(0) 140 | cv2.namedWindow("face recognition", 1) 141 | 142 | while True: 143 | ret, frame = capture.read() 144 | frame = cv2.flip(frame, 1) 145 | rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) 146 | 147 | # 识别框 148 | cv2.putText(frame, 'Identification Box', (200, 90), cv2.FONT_HERSHEY_COMPLEX_SMALL, 149 | 1, (0, 0, 255), 150 | thickness=2, 151 | lineType=1) 152 | cv2.rectangle(frame, (150, 100), (490, 380), (165, 245, 25), 2) 153 | BOX = [150, 100, 490, 380] 154 | 155 | # 获取视频流中的最大人脸 判断标识 bounding_box crop_image 156 | mark, bounding_box, crop_image = self.load_and_align_data(rgb_frame, 160) 157 | 158 | ''' 159 | 范围限制 160 | ''' 161 | if mark: 162 | if bounding_box[0] < 75: 163 | mark = False 164 | # print('left') 165 | if bounding_box[2] > 565: 166 | mark = False 167 | # print('right') 168 | 169 | if mark: 170 | # print('计算视频帧的embadding') 171 | emb = sess.run(embeddings, feed_dict={images_placeholder: crop_image, 172 | phase_train_placeholder: False}) 173 | pre_person_num = len(emb) 174 | find_obj = [] 175 | # print('识别到的人数:', pre_person_num) 176 | cv2.putText(frame, 177 | 'Press esc to exit', 178 | (10, 30), 179 | cv2.FONT_HERSHEY_COMPLEX_SMALL, 180 | 1, (0, 0, 255), 181 | thickness=1, 182 | lineType=1) 183 | # 逐一对比 184 | for i in range(pre_person_num): # 为bounding_box 匹配标签 185 | dist_list = [] # 距离列表 186 | 187 | for j in range(compare_num): 188 | # 求误差(欧氏距离) 189 | dist = np.sqrt(np.sum(np.square(np.subtract(emb[i, :], compare_emb[j, :])))) 190 | dist_list.append(dist) 191 | # 求视频帧和对比图直接最小的差值,即表示为最相似的图片 192 | min_value = min(dist_list) 193 | # print("最小差值:", min_value) 194 | if min_value > 0.65: 195 | find_obj.append('Unknow') 196 | else: 197 | dist_index = dist_list.index(min_value) 198 | find_obj.append(id[dist_index]) 199 | 200 | # 在frame上绘制边框和文字 201 | cv2.rectangle(frame, 202 | (bounding_box[0], bounding_box[1]), 203 | (bounding_box[2], bounding_box[3]), 204 | (0, 255, 0), 1, 8, 0) 205 | cv2.putText(frame, str(find_obj[0]), 206 | (bounding_box[0], bounding_box[1]), 207 | cv2.FONT_HERSHEY_COMPLEX_SMALL, 208 | 1, 209 | (0, 0, 255), 210 | thickness=2, 211 | lineType=2) 212 | 213 | # 将学号插入到选择的考勤表中 214 | if find_obj[0] != "Unknow": 215 | self.sqlite.update_checkwork(self.sqlite.DB_STUDENTCHECKWORK_PATH, checkwork, find_obj[0]) 216 | cv2.imshow('face recognition', frame) 217 | key = cv2.waitKey(3) 218 | if key == 27: 219 | break 220 | capture.release() 221 | cv2.destroyWindow("face recognition") 222 | 223 | def load_and_align_data(self, img, image_size): 224 | 225 | minsize = 20 226 | threshold = [0.6, 0.7, 0.7] 227 | factor = 0.709 228 | bounding_boxes, _ = align.detect_face.detect_face(img, minsize, pnet, rnet, onet, threshold, factor) 229 | Index = [] # 序列 230 | Area = [] # 面积 231 | Position = [] # 坐标 232 | 233 | # print('len(bounding_boxes):', len(bounding_boxes)) 234 | 235 | # 如果未发现目标 直接返回 236 | if len(bounding_boxes) < 1: 237 | # print('没有发现人脸') 238 | return False, 0, 0 239 | 240 | for i, face_position in enumerate(bounding_boxes): 241 | face_position = face_position.astype(int) 242 | w = face_position[2] - face_position[0] 243 | h = face_position[3] - face_position[1] 244 | S = w * h 245 | # print('第:', i) 246 | # print('w:', w) 247 | # print('h:', h) 248 | 249 | Index.append(i) 250 | Area.append(S) 251 | Position.append(face_position) 252 | 253 | max_face_position = max_face(Area, Position) 254 | 255 | # print('bbox:', (max_face_position[0], max_face_position[1]), 256 | # (max_face_position[2], max_face_position[3])) 257 | 258 | # 裁剪 259 | temp_crop = img[max_face_position[1]:max_face_position[3], max_face_position[0]:max_face_position[2], :] 260 | 261 | if max_face_position[0] < 75: # 左边 262 | return False, 0, 0 263 | 264 | if max_face_position[2] > 565: # 右边 265 | return False, 0, 0 266 | 267 | if max_face_position[1] < 75: # 上面 268 | return False, 0, 0 269 | 270 | aligned = cv2.resize(temp_crop, (image_size, image_size), 271 | interpolation=cv2.INTER_CUBIC) 272 | face_out = facenet.prewhiten(aligned) 273 | crop_image = [] 274 | crop_image.append(np.stack(face_out)) 275 | return True, max_face_position, crop_image # mark标记位置,回归边框,切割图片 276 | 277 | 278 | if __name__ == '__main__': 279 | face_test = face() 280 | face_test.main('cs172', 'cs172') 281 | -------------------------------------------------------------------------------- /ui_src/addStudent.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'addStudent.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.9.2 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_Form_Student(object): 12 | def setupUi(self, Form): 13 | Form.setObjectName("Form") 14 | Form.resize(730, 379) 15 | self.layoutWidget = QtWidgets.QWidget(Form) 16 | self.layoutWidget.setGeometry(QtCore.QRect(50, 50, 639, 282)) 17 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) 18 | sizePolicy.setHorizontalStretch(0) 19 | sizePolicy.setVerticalStretch(0) 20 | sizePolicy.setHeightForWidth(self.layoutWidget.sizePolicy().hasHeightForWidth()) 21 | self.layoutWidget.setSizePolicy(sizePolicy) 22 | self.layoutWidget.setObjectName("layoutWidget") 23 | self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.layoutWidget) 24 | self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) 25 | self.verticalLayout_3.setObjectName("verticalLayout_3") 26 | self.horizontalLayout = QtWidgets.QHBoxLayout() 27 | self.horizontalLayout.setObjectName("horizontalLayout") 28 | self.verticalLayout = QtWidgets.QVBoxLayout() 29 | self.verticalLayout.setObjectName("verticalLayout") 30 | self.lab_addTest_6 = QtWidgets.QLabel(self.layoutWidget) 31 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) 32 | sizePolicy.setHorizontalStretch(0) 33 | sizePolicy.setVerticalStretch(0) 34 | sizePolicy.setHeightForWidth(self.lab_addTest_6.sizePolicy().hasHeightForWidth()) 35 | self.lab_addTest_6.setSizePolicy(sizePolicy) 36 | font = QtGui.QFont() 37 | font.setPointSize(16) 38 | self.lab_addTest_6.setFont(font) 39 | self.lab_addTest_6.setLayoutDirection(QtCore.Qt.LeftToRight) 40 | self.lab_addTest_6.setAlignment(QtCore.Qt.AlignCenter) 41 | self.lab_addTest_6.setObjectName("lab_addTest_6") 42 | self.verticalLayout.addWidget(self.lab_addTest_6) 43 | self.lab_addTest = QtWidgets.QLabel(self.layoutWidget) 44 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) 45 | sizePolicy.setHorizontalStretch(0) 46 | sizePolicy.setVerticalStretch(0) 47 | sizePolicy.setHeightForWidth(self.lab_addTest.sizePolicy().hasHeightForWidth()) 48 | self.lab_addTest.setSizePolicy(sizePolicy) 49 | font = QtGui.QFont() 50 | font.setPointSize(16) 51 | self.lab_addTest.setFont(font) 52 | self.lab_addTest.setLayoutDirection(QtCore.Qt.LeftToRight) 53 | self.lab_addTest.setAlignment(QtCore.Qt.AlignCenter) 54 | self.lab_addTest.setObjectName("lab_addTest") 55 | self.verticalLayout.addWidget(self.lab_addTest) 56 | self.lab_addTest_2 = QtWidgets.QLabel(self.layoutWidget) 57 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) 58 | sizePolicy.setHorizontalStretch(0) 59 | sizePolicy.setVerticalStretch(0) 60 | sizePolicy.setHeightForWidth(self.lab_addTest_2.sizePolicy().hasHeightForWidth()) 61 | self.lab_addTest_2.setSizePolicy(sizePolicy) 62 | font = QtGui.QFont() 63 | font.setPointSize(16) 64 | self.lab_addTest_2.setFont(font) 65 | self.lab_addTest_2.setLayoutDirection(QtCore.Qt.LeftToRight) 66 | self.lab_addTest_2.setAlignment(QtCore.Qt.AlignCenter) 67 | self.lab_addTest_2.setObjectName("lab_addTest_2") 68 | self.verticalLayout.addWidget(self.lab_addTest_2) 69 | self.lab_addTest_3 = QtWidgets.QLabel(self.layoutWidget) 70 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) 71 | sizePolicy.setHorizontalStretch(0) 72 | sizePolicy.setVerticalStretch(0) 73 | sizePolicy.setHeightForWidth(self.lab_addTest_3.sizePolicy().hasHeightForWidth()) 74 | self.lab_addTest_3.setSizePolicy(sizePolicy) 75 | font = QtGui.QFont() 76 | font.setPointSize(16) 77 | self.lab_addTest_3.setFont(font) 78 | self.lab_addTest_3.setLayoutDirection(QtCore.Qt.LeftToRight) 79 | self.lab_addTest_3.setAlignment(QtCore.Qt.AlignCenter) 80 | self.lab_addTest_3.setObjectName("lab_addTest_3") 81 | self.verticalLayout.addWidget(self.lab_addTest_3) 82 | self.lab_addTest_4 = QtWidgets.QLabel(self.layoutWidget) 83 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) 84 | sizePolicy.setHorizontalStretch(0) 85 | sizePolicy.setVerticalStretch(0) 86 | sizePolicy.setHeightForWidth(self.lab_addTest_4.sizePolicy().hasHeightForWidth()) 87 | self.lab_addTest_4.setSizePolicy(sizePolicy) 88 | font = QtGui.QFont() 89 | font.setPointSize(16) 90 | self.lab_addTest_4.setFont(font) 91 | self.lab_addTest_4.setLayoutDirection(QtCore.Qt.LeftToRight) 92 | self.lab_addTest_4.setAlignment(QtCore.Qt.AlignCenter) 93 | self.lab_addTest_4.setObjectName("lab_addTest_4") 94 | self.verticalLayout.addWidget(self.lab_addTest_4) 95 | self.horizontalLayout.addLayout(self.verticalLayout) 96 | self.verticalLayout_2 = QtWidgets.QVBoxLayout() 97 | self.verticalLayout_2.setObjectName("verticalLayout_2") 98 | self.SelectClass = QtWidgets.QComboBox(self.layoutWidget) 99 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) 100 | sizePolicy.setHorizontalStretch(0) 101 | sizePolicy.setVerticalStretch(0) 102 | sizePolicy.setHeightForWidth(self.SelectClass.sizePolicy().hasHeightForWidth()) 103 | self.SelectClass.setSizePolicy(sizePolicy) 104 | self.SelectClass.setObjectName("SelectClass") 105 | self.verticalLayout_2.addWidget(self.SelectClass) 106 | self.line_addLabel = QtWidgets.QLineEdit(self.layoutWidget) 107 | self.line_addLabel.setEnabled(True) 108 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) 109 | sizePolicy.setHorizontalStretch(0) 110 | sizePolicy.setVerticalStretch(0) 111 | sizePolicy.setHeightForWidth(self.line_addLabel.sizePolicy().hasHeightForWidth()) 112 | self.line_addLabel.setSizePolicy(sizePolicy) 113 | font = QtGui.QFont() 114 | font.setPointSize(16) 115 | self.line_addLabel.setFont(font) 116 | self.line_addLabel.setLayoutDirection(QtCore.Qt.LeftToRight) 117 | self.line_addLabel.setObjectName("line_addLabel") 118 | self.verticalLayout_2.addWidget(self.line_addLabel) 119 | self.line_addName = QtWidgets.QLineEdit(self.layoutWidget) 120 | self.line_addName.setEnabled(True) 121 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) 122 | sizePolicy.setHorizontalStretch(0) 123 | sizePolicy.setVerticalStretch(0) 124 | sizePolicy.setHeightForWidth(self.line_addName.sizePolicy().hasHeightForWidth()) 125 | self.line_addName.setSizePolicy(sizePolicy) 126 | font = QtGui.QFont() 127 | font.setPointSize(16) 128 | self.line_addName.setFont(font) 129 | self.line_addName.setLayoutDirection(QtCore.Qt.LeftToRight) 130 | self.line_addName.setObjectName("line_addName") 131 | self.verticalLayout_2.addWidget(self.line_addName) 132 | self.line_addSex = QtWidgets.QLineEdit(self.layoutWidget) 133 | self.line_addSex.setEnabled(True) 134 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) 135 | sizePolicy.setHorizontalStretch(0) 136 | sizePolicy.setVerticalStretch(0) 137 | sizePolicy.setHeightForWidth(self.line_addSex.sizePolicy().hasHeightForWidth()) 138 | self.line_addSex.setSizePolicy(sizePolicy) 139 | font = QtGui.QFont() 140 | font.setPointSize(16) 141 | self.line_addSex.setFont(font) 142 | self.line_addSex.setLayoutDirection(QtCore.Qt.LeftToRight) 143 | self.line_addSex.setObjectName("line_addSex") 144 | self.verticalLayout_2.addWidget(self.line_addSex) 145 | self.line_addId = QtWidgets.QLineEdit(self.layoutWidget) 146 | self.line_addId.setEnabled(True) 147 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) 148 | sizePolicy.setHorizontalStretch(0) 149 | sizePolicy.setVerticalStretch(0) 150 | sizePolicy.setHeightForWidth(self.line_addId.sizePolicy().hasHeightForWidth()) 151 | self.line_addId.setSizePolicy(sizePolicy) 152 | font = QtGui.QFont() 153 | font.setPointSize(16) 154 | self.line_addId.setFont(font) 155 | self.line_addId.setLayoutDirection(QtCore.Qt.LeftToRight) 156 | self.line_addId.setObjectName("line_addId") 157 | self.verticalLayout_2.addWidget(self.line_addId) 158 | self.horizontalLayout.addLayout(self.verticalLayout_2) 159 | self.verticalLayout_3.addLayout(self.horizontalLayout) 160 | self.horizontalLayout_2 = QtWidgets.QHBoxLayout() 161 | self.horizontalLayout_2.setObjectName("horizontalLayout_2") 162 | self.btn_confirm = QtWidgets.QPushButton(self.layoutWidget) 163 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) 164 | sizePolicy.setHorizontalStretch(0) 165 | sizePolicy.setVerticalStretch(0) 166 | sizePolicy.setHeightForWidth(self.btn_confirm.sizePolicy().hasHeightForWidth()) 167 | self.btn_confirm.setSizePolicy(sizePolicy) 168 | self.btn_confirm.setMaximumSize(QtCore.QSize(200, 60)) 169 | font = QtGui.QFont() 170 | font.setPointSize(16) 171 | font.setBold(False) 172 | font.setWeight(50) 173 | self.btn_confirm.setFont(font) 174 | self.btn_confirm.setLayoutDirection(QtCore.Qt.LeftToRight) 175 | self.btn_confirm.setObjectName("btn_confirm") 176 | self.horizontalLayout_2.addWidget(self.btn_confirm) 177 | self.btn_refresh = QtWidgets.QPushButton(self.layoutWidget) 178 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) 179 | sizePolicy.setHorizontalStretch(0) 180 | sizePolicy.setVerticalStretch(0) 181 | sizePolicy.setHeightForWidth(self.btn_refresh.sizePolicy().hasHeightForWidth()) 182 | self.btn_refresh.setSizePolicy(sizePolicy) 183 | self.btn_refresh.setMaximumSize(QtCore.QSize(200, 60)) 184 | font = QtGui.QFont() 185 | font.setPointSize(16) 186 | font.setBold(False) 187 | font.setWeight(50) 188 | self.btn_refresh.setFont(font) 189 | self.btn_refresh.setLayoutDirection(QtCore.Qt.LeftToRight) 190 | self.btn_refresh.setObjectName("btn_refresh") 191 | self.horizontalLayout_2.addWidget(self.btn_refresh) 192 | self.btn_cancel = QtWidgets.QPushButton(self.layoutWidget) 193 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) 194 | sizePolicy.setHorizontalStretch(0) 195 | sizePolicy.setVerticalStretch(0) 196 | sizePolicy.setHeightForWidth(self.btn_cancel.sizePolicy().hasHeightForWidth()) 197 | self.btn_cancel.setSizePolicy(sizePolicy) 198 | self.btn_cancel.setMaximumSize(QtCore.QSize(200, 60)) 199 | font = QtGui.QFont() 200 | font.setPointSize(16) 201 | font.setBold(False) 202 | font.setWeight(50) 203 | self.btn_cancel.setFont(font) 204 | self.btn_cancel.setLayoutDirection(QtCore.Qt.LeftToRight) 205 | self.btn_cancel.setObjectName("btn_cancel") 206 | self.horizontalLayout_2.addWidget(self.btn_cancel) 207 | self.verticalLayout_3.addLayout(self.horizontalLayout_2) 208 | 209 | self.retranslateUi(Form) 210 | QtCore.QMetaObject.connectSlotsByName(Form) 211 | 212 | def retranslateUi(self, Form): 213 | _translate = QtCore.QCoreApplication.translate 214 | Form.setWindowTitle(_translate("Form", "添加新用户")) 215 | self.lab_addTest_6.setText(_translate("Form", "选择人脸数据表")) 216 | self.lab_addTest.setText(_translate("Form", "添加用户标签(姓名拼音)")) 217 | self.lab_addTest_2.setText(_translate("Form", "添加用户姓名")) 218 | self.lab_addTest_3.setText(_translate("Form", "添加用户性别")) 219 | self.lab_addTest_4.setText(_translate("Form", "添加用户学号")) 220 | self.btn_confirm.setText(_translate("Form", "确定")) 221 | self.btn_refresh.setText(_translate("Form", "刷新")) 222 | self.btn_cancel.setText(_translate("Form", "取消")) 223 | 224 | -------------------------------------------------------------------------------- /src/Sqlite_UI.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from PyQt5.QtWidgets import QDialog, QLabel, QTableView, QLineEdit, QPushButton, QMessageBox 4 | from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout 5 | from PyQt5 import QtWidgets 6 | from PyQt5.QtWidgets import QWidget 7 | from PyQt5.QtWidgets import QFileDialog 8 | from PyQt5.QtWidgets import QApplication, QAbstractItemView 9 | from PyQt5.Qt import Qt 10 | from PyQt5.QtGui import QStandardItemModel, QStandardItem 11 | from PyQt5.QtCore import pyqtSignal 12 | 13 | from ui_src.sqlite_main_window import Ui_SqliteMainWindow 14 | from ui_src.Add_Data import Ui_Dialog_Add_Data 15 | from ui_src.Add_Table import Ui_Dialog_Add_Table 16 | from functools import partial 17 | from tools.sqlite_func import Sqlite_Func 18 | 19 | 20 | class Add_Table_UI(QDialog, Ui_Dialog_Add_Table): 21 | signal_status = pyqtSignal() 22 | 23 | def __init__(self, db_path, parent=None): 24 | super(Add_Table_UI, self).__init__(parent) 25 | 26 | self.db_path = db_path 27 | 28 | self.sf = Sqlite_Func() 29 | 30 | h_layout = QHBoxLayout() 31 | label_table_name = QLabel("表名字:") 32 | self.lineEdit_table_name = QLineEdit() 33 | # 水平放置 34 | h_layout.addWidget(label_table_name) 35 | h_layout.addWidget(self.lineEdit_table_name) 36 | 37 | btn_ok = QPushButton() 38 | btn_ok.setText("OK") 39 | 40 | v_layout = QVBoxLayout() 41 | 42 | # 垂直放置 43 | v_layout.addLayout(h_layout) 44 | v_layout.addWidget(btn_ok) 45 | 46 | self.setLayout(v_layout) 47 | 48 | btn_ok.clicked.connect(self.create_table) 49 | 50 | def create_table(self): 51 | sstr = self.db_path.split('/') 52 | self.db_type = sstr[len(sstr) - 1] 53 | print("db_type:", self.db_type) 54 | print("创建新表") 55 | if self.lineEdit_table_name == "": 56 | print("表名字为空") 57 | else: 58 | self.sf.create_table(self.db_path, self.lineEdit_table_name.text(), str(self.db_type).upper()) 59 | status = 1 60 | 61 | self.signal_status.emit() 62 | self.close() 63 | 64 | def test(self, s): 65 | print("s:", s) 66 | 67 | 68 | class Add_Data_UI(QDialog, Ui_Dialog_Add_Data): 69 | signal_status = pyqtSignal() 70 | 71 | def __init__(self, db_path, table, field, parent=None): 72 | super(Add_Data_UI, self).__init__(parent) 73 | 74 | self.db_path = db_path 75 | self.table = table 76 | self.field = field 77 | 78 | self.sf = Sqlite_Func() 79 | 80 | v_label_layout = QVBoxLayout() 81 | v_layout = QVBoxLayout() 82 | v_lineEdit_layout = QVBoxLayout() 83 | 84 | h_layout = QHBoxLayout() 85 | 86 | self.lineEdit_list = [] 87 | self.field_len = len(field) 88 | 89 | db_type = str(db_path).split('/') 90 | print("db type:", db_type[len(db_type) - 1].upper()) 91 | if db_type[len(db_type) - 1].upper() == self.sf.DB_TYPE_CHECKWORK: 92 | self.field_len = len(field) - 1 93 | 94 | for i in range(self.field_len): 95 | label = QLabel() 96 | label.setText("{}:".format(str(field[i]).upper())) 97 | v_label_layout.addWidget(label) 98 | 99 | lineEdit = QLineEdit() 100 | self.lineEdit_list.append(lineEdit) 101 | 102 | v_lineEdit_layout.addWidget(lineEdit) 103 | 104 | if db_type[len(db_type) - 1].upper() == self.sf.DB_TYPE_CHECKWORK: 105 | # 对于考勤表 flag不允许手动写入 106 | 107 | label = QLabel() 108 | label.setText("{}:".format(str(field[self.field_len]).upper())) 109 | v_label_layout.addWidget(label) 110 | 111 | lineEdit_flag = QLineEdit() 112 | lineEdit_flag.setReadOnly(True) 113 | lineEdit_flag.setText("0") 114 | 115 | self.lineEdit_list.append(lineEdit_flag) 116 | v_lineEdit_layout.addWidget(lineEdit_flag) 117 | 118 | h_layout.addLayout(v_label_layout) 119 | h_layout.addLayout(v_lineEdit_layout) 120 | 121 | btn_ok = QPushButton() 122 | btn_ok.setText("确定") 123 | 124 | v_layout.addLayout(h_layout) 125 | v_layout.addWidget(btn_ok) 126 | 127 | self.setLayout(v_layout) 128 | 129 | self.setupUi(self) 130 | btn_ok.clicked.connect(self.insert_data) 131 | 132 | def insert_data(self): 133 | lineEdit_data = [] 134 | for i in range(len(self.lineEdit_list)): 135 | lineEdit_data.append(self.lineEdit_list[i].text()) 136 | 137 | # 插入数据库 138 | ret = self.sf.insert(self.db_path, self.table, lineEdit_data) 139 | if ret == -1: 140 | QMessageBox.about(self, "Error", "有数据为空") 141 | if ret == -2: 142 | QMessageBox.about(self, "Error", "主键重复") 143 | self.signal_status.emit() 144 | self.close() 145 | 146 | 147 | class Sqlite_UI(QtWidgets.QMainWindow, Ui_SqliteMainWindow): 148 | def __init__(self, parent=None): 149 | super(Sqlite_UI, self).__init__(parent) 150 | self.setupUi(self) 151 | 152 | # 隐藏两个组件:因为我不想写了 153 | self.label_cmd.hide() 154 | self.lineEdit_cmd.hide() 155 | 156 | # slot init 157 | self.slot_init() 158 | 159 | self.sf = Sqlite_Func() 160 | 161 | # 数据库路径 162 | self.db_path = "" 163 | # 选择的表名 164 | self.table = "" 165 | # 所有数据表 166 | self.table_list = [] 167 | # 当前表所有字段 168 | self.field_list = [] 169 | # 创建的按钮字段列表 170 | self.btn_field_list = [] 171 | # 被勾选的字段 172 | self.select_field_list = [] 173 | # 当前行列 174 | self.len_row = 0 175 | self.len_col = 0 176 | 177 | self.model = QStandardItemModel() 178 | 179 | # 数据库类型 180 | self.db_type = "" 181 | 182 | def slot_init(self): 183 | print("slot init...") 184 | self.actionOpen_File.triggered.connect(self.open_db) 185 | 186 | self.radioButton_all.clicked.connect(self.selectAll_radiobtn) 187 | self.radioButton_notall.clicked.connect(self.selectNotAll_radiobtn) 188 | 189 | self.pushButton_query.clicked.connect(self.query) 190 | self.pushButton_update.clicked.connect(self.update_data) 191 | self.pushButton_del.clicked.connect(self.delete_data) 192 | self.pushButton_add.clicked.connect(self.add_data) 193 | self.pushButton_delTable.clicked.connect(self.del_table) 194 | self.pushButton_newTable.clicked.connect(self.add_table) 195 | 196 | def open_db(self): 197 | print("打开文件") 198 | self.db_path, file_type = QFileDialog.getOpenFileName(self, "select db files", "", 199 | "*.db;;*.png;;All Files(*)") 200 | print("文件路径:{}\n文件类型:{}\n".format(self.db_path, file_type)) 201 | 202 | self.table_list = self.sf.check_table(self.db_path) 203 | print("当前数据库含有表:", self.table_list) 204 | 205 | # 设置窗口名字 206 | QDialog.setWindowTitle(self, self.db_path) 207 | sstr = self.db_path.split('/') 208 | 209 | print(sstr) 210 | self.groupBox_table_field.setTitle("数据库:{}".format(sstr[len(sstr) - 1])) 211 | 212 | self.db_type = sstr[len(sstr) - 1] 213 | 214 | self.create_radiobox_table() 215 | 216 | # 创建数据库表选项 217 | def create_radiobox_table(self): 218 | self.count = 0 219 | self.btn_layer = QWidget() 220 | for i, data in enumerate(self.table_list): 221 | self.count += 1 222 | self.btn = QtWidgets.QRadioButton(self.btn_layer) 223 | self.btn.setText(str(data)) 224 | self.btn.clicked.connect(partial(self.create_checkbox_field, self.btn.text(), False)) 225 | self.btn.move(10, i * 60) 226 | 227 | self.btn_layer.setMinimumSize(250, self.count * 60) 228 | self.scrollArea_table.setWidget(self.btn_layer) 229 | self.scrollArea_table.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) 230 | 231 | # 创建字段表 232 | def create_checkbox_field(self, table, ischeck): 233 | self.btn_field_list.clear() 234 | self.count = 0 235 | 236 | self.table = table 237 | print("选择了{}表".format(str(table))) 238 | ret = self.sf.check_field(self.db_path, table) 239 | self.field_list = ret 240 | print("当前表含有{}字段:".format(ret)) 241 | self.btn_layer = QWidget() 242 | for i, data in enumerate(ret): 243 | self.count += 1 244 | self.btn = QtWidgets.QCheckBox(self.btn_layer) 245 | self.btn.setText("{}".format(str(data))) 246 | self.btn.setChecked(ischeck) 247 | self.btn.move(10, i * 60) 248 | self.btn_field_list.append(self.btn) 249 | 250 | self.btn_layer.setMinimumSize(250, self.count * 60) 251 | self.scrollArea_field.setWidget(self.btn_layer) 252 | self.scrollArea_field.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) 253 | 254 | def selectAll_radiobtn(self): 255 | if self.btn_field_list == []: 256 | print("没有选择表") 257 | else: 258 | print("全选字段") 259 | self.create_checkbox_field(self.table, True) 260 | self.select_field_list.clear() 261 | for btn in self.btn_field_list: 262 | self.select_field_list.append(btn.text()) 263 | 264 | def selectNotAll_radiobtn(self): 265 | if self.btn_field_list == []: 266 | print("没有选择表") 267 | else: 268 | print("全选字段") 269 | self.create_checkbox_field(self.table, False) 270 | self.select_field_list.clear() 271 | 272 | # param:字段,内容 273 | def show_table(self, fields, data): 274 | print("显示表内容") 275 | print("字段:{}\n数据:{}".format(fields, data)) 276 | 277 | # 行数 278 | # 列数 279 | self.len_row = len(data) 280 | self.len_col = len(fields) 281 | print("row:{},col:{}".format(self.len_row, self.len_col)) 282 | # self.model = QStandardItemModel(self.len_row, self.len_col, self) 283 | self.model.setRowCount(self.len_row) 284 | self.model.setColumnCount(self.len_col) 285 | for row in range(self.len_row): 286 | for col in range(len(data[0])): 287 | item = QStandardItem("{}".format(data[row][col])) 288 | 289 | self.model.setItem(row, col, item) 290 | 291 | self.tableView_content.setModel(self.model) 292 | self.tableView_content.horizontalHeader().setStretchLastSection(True) 293 | self.tableView_content.setEditTriggers(QAbstractItemView.DoubleClicked) 294 | self.tableView_content.clicked.connect(lambda x: print(self.tableView_content.currentIndex().data())) 295 | 296 | # 通过按键更新数据到数据库 297 | def update_data(self): 298 | print(self.btn_field_list) 299 | if self.btn_field_list == []: 300 | print("没有选择表") 301 | else: 302 | update_data = [] 303 | if self.len_row == 0: 304 | print("没有数据") 305 | return 306 | 307 | # 读取新数据 308 | for i in range(self.len_row): 309 | update_data_item = [] 310 | for j in range(self.len_col): 311 | if self.model.item(i, j).text() != None: 312 | update_data_item.append(self.model.item(i, j).text()) 313 | update_data.append(update_data_item) 314 | print("update data", update_data) 315 | 316 | if len(update_data[0]) != len(self.field_list): 317 | print("数据不足") 318 | return 319 | # 查找主键 320 | i, key = self.sf.find_primary_key(self.db_path, self.table) 321 | 322 | # 更新数据 323 | ret = self.sf.update(self.db_path, self.table, self.field_list, update_data, i) 324 | if ret == -1: 325 | QMessageBox.about(self, "Error", "有数据为空") 326 | if ret==-2: 327 | print("更新异常") 328 | if ret == -3: 329 | print("主键被修改,停止更新") 330 | QMessageBox.about(self,"Error","主键被修改") 331 | else: 332 | print("更新完成\n") 333 | 334 | # 查询 335 | def query(self): 336 | self.select_field_list.clear() 337 | for btn in self.btn_field_list: 338 | print(btn.isChecked()) 339 | if btn.isChecked() == True: 340 | self.select_field_list.append(btn.text()) 341 | 342 | print("self.select_field_list:", self.select_field_list) 343 | 344 | if self.select_field_list != []: 345 | 346 | # 根据所选字段和表构建查询语句:select field1,field2,...,fieldN from table 347 | str_sql = self.sf.auto_select(self.table, self.select_field_list) 348 | ret = self.sf.executeCMD(self.db_path, str_sql) 349 | print(ret) 350 | for i, data in enumerate(ret): 351 | print("{}->{}\n".format(i, data)) 352 | 353 | # 打印数据 354 | self.show_table(self.select_field_list, ret) 355 | 356 | if self.select_field_list == []: 357 | self.tableView_content.setModel(self.model.clear()) 358 | 359 | # 进行删除操作需要选中所有字段 360 | def delete_data(self): 361 | if self.table == "": 362 | print("未选择表") 363 | return 364 | if self.select_field_list == []: 365 | print("未选择字段") 366 | return 367 | if self.tableView_content.currentIndex().row() == -1: 368 | print("未选择数据") 369 | return 370 | else: 371 | del_row = self.tableView_content.currentIndex().row() 372 | print("选择{}行".format(del_row)) 373 | 374 | # 主键index和获取主键 375 | key_idx, key = self.sf.find_primary_key(self.db_path, self.table) 376 | del_data = [] 377 | # 读取当前行所有数据 378 | for i in range(self.len_col): 379 | if self.model.item(del_row, i).text() != None: 380 | del_data.append(self.model.item(del_row, i).text()) 381 | 382 | if len(del_data) != len(self.field_list): 383 | print("数据不全") 384 | return 385 | print("del data:", del_data) 386 | self.sf.delete(self.db_path, self.table, key, key_idx, del_data) 387 | self.query() 388 | 389 | def add_data(self): 390 | if self.db_path == "": 391 | print("未选择数据库") 392 | return 393 | if self.table == "": 394 | print("未选择表") 395 | return 396 | if self.select_field_list == []: 397 | print("未选择字段") 398 | return 399 | 400 | print("添加数据") 401 | self.add_data_ui = Add_Data_UI(self.db_path, self.table, self.field_list) 402 | self.add_data_ui.show() 403 | self.add_data_ui.signal_status.connect(self.query) 404 | # self.query() 405 | 406 | def flash_table(self): 407 | # 刷新数据库表 408 | self.table_list = self.sf.check_table(self.db_path) 409 | print("当前数据库含有表:", self.table_list) 410 | self.create_radiobox_table() 411 | 412 | def add_table(self): 413 | 414 | if self.db_path == "": 415 | print("没有选择数据库") 416 | else: 417 | self.add_table_ui = Add_Table_UI(self.db_path) 418 | self.add_table_ui.show() 419 | 420 | # 子窗口链接主窗口函数 421 | self.add_table_ui.signal_status.connect(self.flash_table) 422 | 423 | def del_table(self): 424 | if self.table == "": 425 | print("没有选择表") 426 | return 427 | print("当前选择表:{}".format(self.table)) 428 | ret = QMessageBox.question(self, "delete table", "sure to delete this table?", QMessageBox.Yes | QMessageBox.No, 429 | QMessageBox.No) 430 | if ret == QMessageBox.Yes: 431 | self.sf.delete_table(self.db_path, self.table) 432 | self.tableView_content.setModel(self.model.clear()) 433 | 434 | # 刷新数据库表 435 | self.table_list = self.sf.check_table(self.db_path) 436 | print("当前数据库含有表:", self.table_list) 437 | self.create_radiobox_table() 438 | 439 | 440 | if __name__ == "__main__": 441 | app = QApplication(sys.argv) 442 | ui = Sqlite_UI() 443 | # ui = Add_Data_UI() 444 | ui.show() 445 | sys.exit((app.exec_())) 446 | -------------------------------------------------------------------------------- /src/facenet.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from __future__ import division 3 | from __future__ import print_function 4 | 5 | import os 6 | from subprocess import Popen, PIPE 7 | import tensorflow as tf 8 | import numpy as np 9 | from scipy import misc 10 | from sklearn.model_selection import KFold 11 | from scipy import interpolate 12 | from tensorflow.python.training import training 13 | import random 14 | import re 15 | from tensorflow.python.platform import gfile 16 | import math 17 | from six import iteritems 18 | 19 | 20 | def triplet_loss(anchor, positive, negative, alpha): 21 | """Calculate the triplet loss according to the FaceNet paper 22 | 23 | Args: 24 | anchor: the embeddings for the anchor images. 25 | positive: the embeddings for the positive images. 26 | negative: the embeddings for the negative images. 27 | 28 | Returns: 29 | the triplet loss according to the FaceNet paper as a float tensor. 30 | """ 31 | with tf.variable_scope('triplet_loss'): 32 | pos_dist = tf.reduce_sum(tf.square(tf.subtract(anchor, positive)), 1) 33 | neg_dist = tf.reduce_sum(tf.square(tf.subtract(anchor, negative)), 1) 34 | 35 | basic_loss = tf.add(tf.subtract(pos_dist, neg_dist), alpha) 36 | loss = tf.reduce_mean(tf.maximum(basic_loss, 0.0), 0) 37 | 38 | return loss 39 | 40 | 41 | def center_loss(features, label, alfa, nrof_classes): 42 | """Center loss based on the paper "A Discriminative Feature Learning Approach for Deep Face Recognition" 43 | (http://ydwen.github.io/papers/WenECCV16.pdf) 44 | """ 45 | nrof_features = features.get_shape()[1] 46 | centers = tf.get_variable('centers', [nrof_classes, nrof_features], dtype=tf.float32, 47 | initializer=tf.constant_initializer(0), trainable=False) 48 | label = tf.reshape(label, [-1]) 49 | centers_batch = tf.gather(centers, label) 50 | diff = (1 - alfa) * (centers_batch - features) 51 | centers = tf.scatter_sub(centers, label, diff) 52 | with tf.control_dependencies([centers]): 53 | loss = tf.reduce_mean(tf.square(features - centers_batch)) 54 | return loss, centers 55 | 56 | 57 | # 获取图片路径和标签 58 | def get_image_paths_and_labels(dataset): 59 | image_paths_flat = [] 60 | labels_flat = [] 61 | for i in range(len(dataset)): 62 | image_paths_flat += dataset[i].image_paths 63 | labels_flat += [i] * len(dataset[i].image_paths) 64 | return image_paths_flat, labels_flat 65 | 66 | 67 | def shuffle_examples(image_paths, labels): 68 | shuffle_list = list(zip(image_paths, labels)) 69 | random.shuffle(shuffle_list) 70 | image_paths_shuff, labels_shuff = zip(*shuffle_list) 71 | return image_paths_shuff, labels_shuff 72 | 73 | 74 | # 随机旋转图像 75 | def random_rotate_image(image): 76 | angle = np.random.uniform(low=-10.0, high=10.0) 77 | return misc.imrotate(image, angle, 'bicubic') 78 | 79 | 80 | # 1: Random rotate 2: Random crop 4: Random flip 8: Fixed markdown_imgs standardization 16: Flip 81 | RANDOM_ROTATE = 1 82 | RANDOM_CROP = 2 83 | RANDOM_FLIP = 4 84 | FIXED_STANDARDIZATION = 8 85 | FLIP = 16 86 | 87 | 88 | def create_input_pipeline(input_queue, image_size, nrof_preprocess_threads, batch_size_placeholder): 89 | images_and_labels_list = [] 90 | for _ in range(nrof_preprocess_threads): 91 | filenames, label, control = input_queue.dequeue() 92 | images = [] 93 | for filename in tf.unstack(filenames): 94 | file_contents = tf.read_file(filename) 95 | image = tf.image.decode_image(file_contents, 3) 96 | image = tf.cond(get_control_flag(control[0], RANDOM_ROTATE), 97 | lambda: tf.py_func(random_rotate_image, [image], tf.uint8), 98 | lambda: tf.identity(image)) 99 | image = tf.cond(get_control_flag(control[0], RANDOM_CROP), 100 | lambda: tf.random_crop(image, image_size + (3,)), 101 | lambda: tf.image.resize_image_with_crop_or_pad(image, image_size[0], image_size[1])) 102 | image = tf.cond(get_control_flag(control[0], RANDOM_FLIP), 103 | lambda: tf.image.random_flip_left_right(image), 104 | lambda: tf.identity(image)) 105 | image = tf.cond(get_control_flag(control[0], FIXED_STANDARDIZATION), 106 | lambda: (tf.cast(image, tf.float32) - 127.5) / 128.0, 107 | lambda: tf.image.per_image_standardization(image)) 108 | image = tf.cond(get_control_flag(control[0], FLIP), 109 | lambda: tf.image.flip_left_right(image), 110 | lambda: tf.identity(image)) 111 | # pylint: disable=no-member 112 | image.set_shape(image_size + (3,)) 113 | images.append(image) 114 | images_and_labels_list.append([images, label]) 115 | 116 | image_batch, label_batch = tf.train.batch_join( 117 | images_and_labels_list, batch_size=batch_size_placeholder, 118 | shapes=[image_size + (3,), ()], enqueue_many=True, 119 | capacity=4 * nrof_preprocess_threads * 100, 120 | allow_smaller_final_batch=True) 121 | 122 | return image_batch, label_batch 123 | 124 | 125 | def get_control_flag(control, field): 126 | return tf.equal(tf.mod(tf.floor_div(control, field), 2), 1) 127 | 128 | 129 | def _add_loss_summaries(total_loss): 130 | """Add summaries for losses. 131 | 132 | Generates moving average for all losses and associated summaries for 133 | visualizing the performance of the network. 134 | 135 | Args: 136 | total_loss: Total loss from loss(). 137 | Returns: 138 | loss_averages_op: op for generating moving averages of losses. 139 | """ 140 | # Compute the moving average of all individual losses and the total loss. 141 | loss_averages = tf.train.ExponentialMovingAverage(0.9, name='avg') 142 | losses = tf.get_collection('losses') 143 | loss_averages_op = loss_averages.apply(losses + [total_loss]) 144 | 145 | # Attach a scalar summmary to all individual losses and the total loss; do the 146 | # same for the averaged version of the losses. 147 | for l in losses + [total_loss]: 148 | # Name each loss as '(raw)' and name the moving average version of the loss 149 | # as the original loss name. 150 | tf.summary.scalar(l.op.name + ' (raw)', l) 151 | tf.summary.scalar(l.op.name, loss_averages.average(l)) 152 | 153 | return loss_averages_op 154 | 155 | 156 | def train(total_loss, global_step, optimizer, learning_rate, moving_average_decay, update_gradient_vars, 157 | log_histograms=True): 158 | # Generate moving averages of all losses and associated summaries. 159 | loss_averages_op = _add_loss_summaries(total_loss) 160 | # 计算梯度 161 | with tf.control_dependencies([loss_averages_op]): 162 | if optimizer == 'ADAGRAD': 163 | opt = tf.train.AdagradOptimizer(learning_rate) 164 | elif optimizer == 'ADADELTA': 165 | opt = tf.train.AdadeltaOptimizer(learning_rate, rho=0.9, epsilon=1e-6) 166 | elif optimizer == 'ADAM': 167 | opt = tf.train.AdamOptimizer(learning_rate, beta1=0.9, beta2=0.999, epsilon=0.1) 168 | elif optimizer == 'RMSPROP': 169 | opt = tf.train.RMSPropOptimizer(learning_rate, decay=0.9, momentum=0.9, epsilon=1.0) 170 | elif optimizer == 'MOM': 171 | opt = tf.train.MomentumOptimizer(learning_rate, 0.9, use_nesterov=True) 172 | else: 173 | raise ValueError('Invalid optimization algorithm') 174 | 175 | grads = opt.compute_gradients(total_loss, update_gradient_vars) 176 | 177 | # Apply gradients. 178 | apply_gradient_op = opt.apply_gradients(grads, global_step=global_step) 179 | 180 | # Add histograms for trainable variables. 181 | if log_histograms: 182 | for var in tf.trainable_variables(): 183 | tf.summary.histogram(var.op.name, var) 184 | 185 | # Add histograms for gradients. 186 | if log_histograms: 187 | for grad, var in grads: 188 | if grad is not None: 189 | tf.summary.histogram(var.op.name + '/gradients', grad) 190 | 191 | # Track the moving averages of all trainable variables. 192 | variable_averages = tf.train.ExponentialMovingAverage( 193 | moving_average_decay, global_step) 194 | variables_averages_op = variable_averages.apply(tf.trainable_variables()) 195 | 196 | with tf.control_dependencies([apply_gradient_op, variables_averages_op]): 197 | train_op = tf.no_op(name='train') 198 | 199 | return train_op 200 | 201 | 202 | def prewhiten(x): 203 | mean = np.mean(x) 204 | std = np.std(x) 205 | std_adj = np.maximum(std, 1.0 / np.sqrt(x.size)) 206 | y = np.multiply(np.subtract(x, mean), 1 / std_adj) 207 | return y 208 | 209 | 210 | def crop(image, random_crop, image_size): 211 | if image.shape[1] > image_size: 212 | sz1 = int(image.shape[1] // 2) 213 | sz2 = int(image_size // 2) 214 | if random_crop: 215 | diff = sz1 - sz2 216 | (h, v) = (np.random.randint(-diff, diff + 1), np.random.randint(-diff, diff + 1)) 217 | else: 218 | (h, v) = (0, 0) 219 | image = image[(sz1 - sz2 + v):(sz1 + sz2 + v), (sz1 - sz2 + h):(sz1 + sz2 + h), :] 220 | return image 221 | 222 | 223 | def flip(image, random_flip): 224 | if random_flip and np.random.choice([True, False]): 225 | image = np.fliplr(image) 226 | return image 227 | 228 | 229 | def to_rgb(img): 230 | w, h = img.shape 231 | ret = np.empty((w, h, 3), dtype=np.uint8) 232 | ret[:, :, 0] = ret[:, :, 1] = ret[:, :, 2] = img 233 | return ret 234 | 235 | 236 | def load_data(image_paths, do_random_crop, do_random_flip, image_size, do_prewhiten=True): 237 | nrof_samples = len(image_paths) 238 | images = np.zeros((nrof_samples, image_size, image_size, 3)) 239 | for i in range(nrof_samples): 240 | img = misc.imread(image_paths[i]) 241 | if img.ndim == 2: 242 | img = to_rgb(img) 243 | if do_prewhiten: 244 | img = prewhiten(img) 245 | img = crop(img, do_random_crop, image_size) 246 | img = flip(img, do_random_flip) 247 | images[i, :, :, :] = img 248 | return images 249 | 250 | 251 | def get_label_batch(label_data, batch_size, batch_index): 252 | nrof_examples = np.size(label_data, 0) 253 | j = batch_index * batch_size % nrof_examples 254 | if j + batch_size <= nrof_examples: 255 | batch = label_data[j:j + batch_size] 256 | else: 257 | x1 = label_data[j:nrof_examples] 258 | x2 = label_data[0:nrof_examples - j] 259 | batch = np.vstack([x1, x2]) 260 | batch_int = batch.astype(np.int64) 261 | return batch_int 262 | 263 | 264 | def get_batch(image_data, batch_size, batch_index): 265 | nrof_examples = np.size(image_data, 0) 266 | j = batch_index * batch_size % nrof_examples 267 | if j + batch_size <= nrof_examples: 268 | batch = image_data[j:j + batch_size, :, :, :] 269 | else: 270 | x1 = image_data[j:nrof_examples, :, :, :] 271 | x2 = image_data[0:nrof_examples - j, :, :, :] 272 | batch = np.vstack([x1, x2]) 273 | batch_float = batch.astype(np.float32) 274 | return batch_float 275 | 276 | 277 | def get_triplet_batch(triplets, batch_index, batch_size): 278 | ax, px, nx = triplets 279 | a = get_batch(ax, int(batch_size / 3), batch_index) 280 | p = get_batch(px, int(batch_size / 3), batch_index) 281 | n = get_batch(nx, int(batch_size / 3), batch_index) 282 | batch = np.vstack([a, p, n]) 283 | return batch 284 | 285 | 286 | def get_learning_rate_from_file(filename, epoch): 287 | with open(filename, 'r') as f: 288 | for line in f.readlines(): 289 | line = line.split('#', 1)[0] 290 | if line: 291 | par = line.strip().split(':') 292 | e = int(par[0]) 293 | if par[1] == '-': 294 | lr = -1 295 | else: 296 | lr = float(par[1]) 297 | if e <= epoch: 298 | learning_rate = lr 299 | else: 300 | return learning_rate 301 | 302 | 303 | class ImageClass(): 304 | "Stores the paths to images for a given class" 305 | 306 | def __init__(self, name, image_paths): 307 | self.name = name 308 | self.image_paths = image_paths 309 | 310 | def __str__(self): 311 | return self.name + ', ' + str(len(self.image_paths)) + ' images' 312 | 313 | def __len__(self): 314 | return len(self.image_paths) 315 | 316 | 317 | def get_dataset(path, has_class_directories=True): 318 | dataset = [] 319 | path_exp = os.path.expanduser(path) 320 | classes = [path for path in os.listdir(path_exp) \ 321 | if os.path.isdir(os.path.join(path_exp, path))] 322 | classes.sort() 323 | nrof_classes = len(classes) 324 | for i in range(nrof_classes): 325 | class_name = classes[i] 326 | facedir = os.path.join(path_exp, class_name) 327 | image_paths = get_image_paths(facedir) 328 | dataset.append(ImageClass(class_name, image_paths)) 329 | 330 | return dataset 331 | 332 | 333 | def get_image_paths(facedir): 334 | image_paths = [] 335 | if os.path.isdir(facedir): 336 | images = os.listdir(facedir) 337 | image_paths = [os.path.join(facedir, img) for img in images] 338 | return image_paths 339 | 340 | 341 | def split_dataset(dataset, split_ratio, min_nrof_images_per_class, mode): 342 | if mode == 'SPLIT_CLASSES': 343 | nrof_classes = len(dataset) 344 | class_indices = np.arange(nrof_classes) 345 | np.random.shuffle(class_indices) 346 | split = int(round(nrof_classes * (1 - split_ratio))) 347 | train_set = [dataset[i] for i in class_indices[0:split]] 348 | test_set = [dataset[i] for i in class_indices[split:-1]] 349 | elif mode == 'SPLIT_IMAGES': 350 | train_set = [] 351 | test_set = [] 352 | for cls in dataset: 353 | paths = cls.image_paths 354 | np.random.shuffle(paths) 355 | nrof_images_in_class = len(paths) 356 | split = int(math.floor(nrof_images_in_class * (1 - split_ratio))) 357 | if split == nrof_images_in_class: 358 | split = nrof_images_in_class - 1 359 | if split >= min_nrof_images_per_class and nrof_images_in_class - split >= 1: 360 | train_set.append(ImageClass(cls.name, paths[:split])) 361 | test_set.append(ImageClass(cls.name, paths[split:])) 362 | else: 363 | raise ValueError('Invalid train/test split mode "%s"' % mode) 364 | return train_set, test_set 365 | 366 | 367 | def load_model(model, input_map=None): 368 | # Check if the model is a model directory (containing a metagraph and a checkpoint file) 369 | # or if it is a protobuf file with a frozen graph 370 | model_exp = os.path.expanduser(model) 371 | if (os.path.isfile(model_exp)): 372 | print('Model filename: %s' % model_exp) 373 | with gfile.FastGFile(model_exp, 'rb') as f: 374 | graph_def = tf.GraphDef() 375 | graph_def.ParseFromString(f.read()) 376 | tf.import_graph_def(graph_def, input_map=input_map, name='') 377 | else: 378 | print('Model directory: %s' % model_exp) 379 | meta_file, ckpt_file = get_model_filenames(model_exp) 380 | 381 | print('Metagraph file: %s' % meta_file) 382 | print('Checkpoint file: %s' % ckpt_file) 383 | 384 | saver = tf.train.import_meta_graph(os.path.join(model_exp, meta_file), input_map=input_map) 385 | saver.restore(tf.get_default_session(), os.path.join(model_exp, ckpt_file)) 386 | 387 | 388 | def get_model_filenames(model_dir): 389 | files = os.listdir(model_dir) 390 | meta_files = [s for s in files if s.endswith('.meta')] 391 | if len(meta_files) == 0: 392 | raise ValueError('No meta file found in the model directory (%s)' % model_dir) 393 | elif len(meta_files) > 1: 394 | raise ValueError('There should not be more than one meta file in the model directory (%s)' % model_dir) 395 | meta_file = meta_files[0] 396 | ckpt = tf.train.get_checkpoint_state(model_dir) 397 | if ckpt and ckpt.model_checkpoint_path: 398 | ckpt_file = os.path.basename(ckpt.model_checkpoint_path) 399 | return meta_file, ckpt_file 400 | 401 | meta_files = [s for s in files if '.ckpt' in s] 402 | max_step = -1 403 | for f in files: 404 | step_str = re.match(r'(^model-[\w\- ]+.ckpt-(\d+))', f) 405 | if step_str is not None and len(step_str.groups()) >= 2: 406 | step = int(step_str.groups()[1]) 407 | if step > max_step: 408 | max_step = step 409 | ckpt_file = step_str.groups()[0] 410 | return meta_file, ckpt_file 411 | 412 | 413 | def distance(embeddings1, embeddings2, distance_metric=0): 414 | if distance_metric == 0: 415 | # Euclidian distance 416 | diff = np.subtract(embeddings1, embeddings2) 417 | dist = np.sum(np.square(diff), 1) 418 | elif distance_metric == 1: 419 | # Distance based on cosine similarity 420 | dot = np.sum(np.multiply(embeddings1, embeddings2), axis=1) 421 | norm = np.linalg.norm(embeddings1, axis=1) * np.linalg.norm(embeddings2, axis=1) 422 | similarity = dot / norm 423 | dist = np.arccos(similarity) / math.pi 424 | else: 425 | raise 'Undefined distance metric %d' % distance_metric 426 | 427 | return dist 428 | 429 | 430 | def calculate_roc(thresholds, embeddings1, embeddings2, actual_issame, nrof_folds=10, distance_metric=0, 431 | subtract_mean=False): 432 | assert (embeddings1.shape[0] == embeddings2.shape[0]) 433 | assert (embeddings1.shape[1] == embeddings2.shape[1]) 434 | nrof_pairs = min(len(actual_issame), embeddings1.shape[0]) 435 | nrof_thresholds = len(thresholds) 436 | k_fold = KFold(n_splits=nrof_folds, shuffle=False) 437 | 438 | tprs = np.zeros((nrof_folds, nrof_thresholds)) 439 | fprs = np.zeros((nrof_folds, nrof_thresholds)) 440 | accuracy = np.zeros((nrof_folds)) 441 | 442 | indices = np.arange(nrof_pairs) 443 | 444 | for fold_idx, (train_set, test_set) in enumerate(k_fold.split(indices)): 445 | if subtract_mean: 446 | mean = np.mean(np.concatenate([embeddings1[train_set], embeddings2[train_set]]), axis=0) 447 | else: 448 | mean = 0.0 449 | dist = distance(embeddings1 - mean, embeddings2 - mean, distance_metric) 450 | 451 | # Find the best threshold for the fold 452 | acc_train = np.zeros((nrof_thresholds)) 453 | for threshold_idx, threshold in enumerate(thresholds): 454 | _, _, acc_train[threshold_idx] = calculate_accuracy(threshold, dist[train_set], actual_issame[train_set]) 455 | best_threshold_index = np.argmax(acc_train) 456 | for threshold_idx, threshold in enumerate(thresholds): 457 | tprs[fold_idx, threshold_idx], fprs[fold_idx, threshold_idx], _ = calculate_accuracy(threshold, 458 | dist[test_set], 459 | actual_issame[ 460 | test_set]) 461 | _, _, accuracy[fold_idx] = calculate_accuracy(thresholds[best_threshold_index], dist[test_set], 462 | actual_issame[test_set]) 463 | 464 | tpr = np.mean(tprs, 0) 465 | fpr = np.mean(fprs, 0) 466 | return tpr, fpr, accuracy 467 | 468 | 469 | def calculate_accuracy(threshold, dist, actual_issame): 470 | predict_issame = np.less(dist, threshold) 471 | tp = np.sum(np.logical_and(predict_issame, actual_issame)) 472 | fp = np.sum(np.logical_and(predict_issame, np.logical_not(actual_issame))) 473 | tn = np.sum(np.logical_and(np.logical_not(predict_issame), np.logical_not(actual_issame))) 474 | fn = np.sum(np.logical_and(np.logical_not(predict_issame), actual_issame)) 475 | 476 | tpr = 0 if (tp + fn == 0) else float(tp) / float(tp + fn) 477 | fpr = 0 if (fp + tn == 0) else float(fp) / float(fp + tn) 478 | acc = float(tp + tn) / dist.size 479 | return tpr, fpr, acc 480 | 481 | 482 | def calculate_val(thresholds, embeddings1, embeddings2, actual_issame, far_target, nrof_folds=10, distance_metric=0, 483 | subtract_mean=False): 484 | assert (embeddings1.shape[0] == embeddings2.shape[0]) 485 | assert (embeddings1.shape[1] == embeddings2.shape[1]) 486 | nrof_pairs = min(len(actual_issame), embeddings1.shape[0]) 487 | nrof_thresholds = len(thresholds) 488 | k_fold = KFold(n_splits=nrof_folds, shuffle=False) 489 | 490 | val = np.zeros(nrof_folds) 491 | far = np.zeros(nrof_folds) 492 | 493 | indices = np.arange(nrof_pairs) 494 | 495 | for fold_idx, (train_set, test_set) in enumerate(k_fold.split(indices)): 496 | if subtract_mean: 497 | mean = np.mean(np.concatenate([embeddings1[train_set], embeddings2[train_set]]), axis=0) 498 | else: 499 | mean = 0.0 500 | dist = distance(embeddings1 - mean, embeddings2 - mean, distance_metric) 501 | 502 | # Find the threshold that gives FAR = far_target 503 | far_train = np.zeros(nrof_thresholds) 504 | for threshold_idx, threshold in enumerate(thresholds): 505 | _, far_train[threshold_idx] = calculate_val_far(threshold, dist[train_set], actual_issame[train_set]) 506 | if np.max(far_train) >= far_target: 507 | f = interpolate.interp1d(far_train, thresholds, kind='slinear') 508 | threshold = f(far_target) 509 | else: 510 | threshold = 0.0 511 | 512 | val[fold_idx], far[fold_idx] = calculate_val_far(threshold, dist[test_set], actual_issame[test_set]) 513 | 514 | val_mean = np.mean(val) 515 | far_mean = np.mean(far) 516 | val_std = np.std(val) 517 | return val_mean, val_std, far_mean 518 | 519 | 520 | def calculate_val_far(threshold, dist, actual_issame): 521 | predict_issame = np.less(dist, threshold) 522 | true_accept = np.sum(np.logical_and(predict_issame, actual_issame)) 523 | false_accept = np.sum(np.logical_and(predict_issame, np.logical_not(actual_issame))) 524 | n_same = np.sum(actual_issame) 525 | n_diff = np.sum(np.logical_not(actual_issame)) 526 | val = float(true_accept) / float(n_same) 527 | far = float(false_accept) / float(n_diff) 528 | return val, far 529 | 530 | 531 | def store_revision_info(src_path, output_dir, arg_string): 532 | try: 533 | # Get git hash 534 | cmd = ['git', 'rev-parse', 'HEAD'] 535 | gitproc = Popen(cmd, stdout=PIPE, cwd=src_path) 536 | (stdout, _) = gitproc.communicate() 537 | git_hash = stdout.strip() 538 | except OSError as e: 539 | git_hash = ' '.join(cmd) + ': ' + e.strerror 540 | 541 | try: 542 | # Get local changes 543 | cmd = ['git', 'diff', 'HEAD'] 544 | gitproc = Popen(cmd, stdout=PIPE, cwd=src_path) 545 | (stdout, _) = gitproc.communicate() 546 | git_diff = stdout.strip() 547 | except OSError as e: 548 | git_diff = ' '.join(cmd) + ': ' + e.strerror 549 | 550 | # Store a text file in the log directory 551 | rev_info_filename = os.path.join(output_dir, 'revision_info.txt') 552 | with open(rev_info_filename, "w") as text_file: 553 | text_file.write('arguments: %s\n--------------------\n' % arg_string) 554 | text_file.write('tensorflow version: %s\n--------------------\n' % tf.__version__) # @UndefinedVariable 555 | text_file.write('git hash: %s\n--------------------\n' % git_hash) 556 | text_file.write('%s' % git_diff) 557 | 558 | 559 | def list_variables(filename): 560 | reader = training.NewCheckpointReader(filename) 561 | variable_map = reader.get_variable_to_shape_map() 562 | names = sorted(variable_map.keys()) 563 | return names 564 | 565 | 566 | def put_images_on_grid(images, shape=(16, 8)): 567 | nrof_images = images.shape[0] 568 | img_size = images.shape[1] 569 | bw = 3 570 | img = np.zeros((shape[1] * (img_size + bw) + bw, shape[0] * (img_size + bw) + bw, 3), np.float32) 571 | for i in range(shape[1]): 572 | x_start = i * (img_size + bw) + bw 573 | for j in range(shape[0]): 574 | img_index = i * shape[0] + j 575 | if img_index >= nrof_images: 576 | break 577 | y_start = j * (img_size + bw) + bw 578 | img[x_start:x_start + img_size, y_start:y_start + img_size, :] = images[img_index, :, :, :] 579 | if img_index >= nrof_images: 580 | break 581 | return img 582 | 583 | 584 | def write_arguments_to_file(args, filename): 585 | with open(filename, 'w') as f: 586 | for key, value in iteritems(vars(args)): 587 | f.write('%s: %s\n' % (key, str(value))) 588 | --------------------------------------------------------------------------------