Use python and pyqt5 to easily get started with the face recognition system (including code)
- 1. Environment configuration
- 2. Face recognition module test
- 3. Database design based on sqlite3
- 4. GUI design based on PyQt5
- 5. Effect display
- 6. Code acquisition and download
Recently I am working on a face recognition attendance system, and I have summarized and recorded most of the content, so it is relatively complete! I will finish the rest later. Interested students can pay attention~ The end of the article gives how to obtain the code, please get it and eat it by yourself~
Station B: Update soon! ! ! _bilibili
CSDN: Use python and pyqt5 to easily get started with the face recognition system (including code)_Covered after a hundred years - CSDN blog
Public account: Capped after a hundred years
1. Environment configuration
The environment we use here mainly includes the following three aspects:
- The first is what is needed for development
python环境、包管理工具和IDE
, etc. The main things we need to install here areanaconda
andpycharm专业版
andpip镜像源
. It should be noted that the professional version of pycharm is paid software. If you do not want to check the detailed information of the database later, the community version is enough, but the professional version can be applied for by students for scientific research purposes. - This project uses
sqlite3
a database, but we'd better configuremysql
the database so that we can easily view the tables and information of the database in pycharm professional version. - The last is the python package that is relied upon in the face recognition and development process. Later we will show several methods of using python for face recognition. In addition, the others
opencv-python
basically requiredlib
this library. I will talk about the specific libraries that are relied on later, but ForNo Module Error
the situation,pip install xxx
it can be easily solved directly.
1.1 python environment configuration
Here we only provide the configuration method of python environment under windows. In fact, they are all similar.
1.1.1 Install anaconda
anaconda is a python package management software that can easily manage your 虚拟环境
and依赖的包
-
First go to the official website to download the installation package
-
Just follow the requirements and install it step by step. Just keep going next. If you don’t know how to install it, you can search it directly
anaconda的安装方法
and refer to other bloggers’ detailed installation instructions. We won’t go into details here.
-
Check whether anaconda is installed successfully
Open cmd and enter conda -V
. Generally, there will be two situations. The following one is installed.
If an error is reported, you need to find the installation path of anaconda first, for example, it is in C:\Users\xxx\anaconda3
, then you need to add the following paths to your system environment variables, path
that is, add the bin
and Scripts
path of anaconda Go to the environment variables as follows:
C:\Users\xxx\anaconda3\bin
C:\Users\xmhh\anaconda3\Scripts
C:\Users\xmhh\anaconda3
After the operation, just check whether conda is installed. 一般出问题就是环境变量没加入进去
Otherwise, there is no problem.
- Here are some commonly used conda commands:
# 建立新环境
conda create -n new env_name python=3.8
# conda初始化
conda init
# 激活虚拟环境
conda activate env_name 或者 activate env_name
# 查看虚拟环境
conda env list
# 删除虚拟环境
conda remove -n env_name --all
1.1.2 Install pycharm
- Go to the official website to download the installation package
- It should be noted that the professional version installation package on the left can be used free of charge for 30 days, or it can be extended by certification of educational discounts, while the community version on the right is free. The professional version can view databases, remote connections, etc., and has more comprehensive functions. The community version is barely enough.
- If you want to install it, just keep going next. There is nothing to say. Well, the effect after opening the project is as follows:
1.1.3 Configure pip source
Since we need to configure the virtual environment and install related dependency packages in the future, downloading python in China is very slow, so we need to configure the pip mirror source first. The specific steps are as follows:
C:\Users\xxx
Create apip
folder named in, and then create a file in it .pip.ini
Note that you need to modify the content of this file later, so you can change the name to firstpip.txt
, and then change it topip.ini
- Just modify
pip.ini
the content of the file and save it, as follows: If you still don’t understand it clearly, you can refer to other bloggers’ tutorials, such as this tutorial
[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple
- pip install later
1.2 mysql database installation
The mysql database is often used, so it is best to install and configure it. Here is a rough installation tutorial.
-
Download the installation package of mysql database.
As shown in the picture above, just select the first one. After unzipping, it will be ok, as shown in the picture below. At first, it does notmy.ini
seemdata
to be there, but it is not important. Download the official website and unzip it and it will be done后面再配
.
-
bin
Configure environment variables, which is the folder under the mysql folder
-
Create and configure in the root directory of the mysqll file
my.ini
my.ini
The configuration information is as follows. Just be sure to set the path inside to your own. No need to change anything else.
[mysqld]
explicit_defaults_for_timestamp=true
character-set-server=utf8mb4
#绑定IPv4和3306端口
bind-address = 0.0.0.0
port = 3306
sql_mode="STRICT_TRANS_TABLES,NO_ENGINE_SUBSTITUTION"
default_storage_engine=innodb
innodb_buffer_pool_size=1000M
innodb_log_file_size=50M
# 设置mysql的安装目录
basedir=G:\Program Files\mysql
# 设置mysql数据库的数据的存放目录
datadir=G:\Program Files\mysql\data
# 允许最大连接数
max_connections=200
# skip_grant_tables
[mysql]
default-character-set=utf8mb4
[mysql.server]
default-character-set=utf8mb4
[mysql_safe]
default-character-set=utf8mb4
[client]
port = 3306
default-character-set=utf8mb4
plugin-dir=G:\Program Files\mysql\lib\plugin
- Open
cmd
and entermysqld --initialize
to complete initialization. The folder appears in the root directorydata
, and now everything is alive. Note that during initialization, there will be an initial password. Remember to remember it. You will need it to log in and change the password later.
- Related uses
# 安装mysql服务
mysqld -install
# 启动mysql服务
net start mysql
# 登录数据库
mysql -u root -p
# 修改 root 密码为 root123
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'root123';
1.3 Related dependency installation
Here we introduce the dependencies and environment required for this project. Here we mainly need to use: first, numpy
and pandas
are the basic libraries for data processing; secondly, some python libraries for image processing, and cv2
; Pillow
then, the gui library, pyqt5
and finally the face recognition library cmake
, dlib
and face_recognition
. Basically, that's it. If there are any problems, please install it according to the error report. General configuration steps are given below:
cmd
First use the command in your project pathconda
to create a virtual environment, and then activate it
# 创建虚拟环境 名字是face_login python版本是3.8
conda create -n new face_login python=3.8
# 激活虚拟环境
activate face_login 或者 conda activate face_login
- Create a file named under your project path
requirements.txt
and fill in the following information. There seems to be no big problem with the version. Just install it in order. Thedlib
installation may be a bit slow. If you think it is too slow, you can still do it. Finally, use it alonepip install dlib
to install, but you need topip
installcmake
the package first, otherwise an error will occur.
numpy
pandas
pyqt5
cmake
opencv-python
Pillow
dlib
face_recognition
- Run
pip install -r requirements.txt
to install dependencies
2. Face recognition module test
As the most important module in the face recognition system, we need to first test the function of face recognition, and then embed it into our system as a module. The face recognition function is mainly divided into two steps according to the process. The first is to read the picture (local folder or camera); the second is to use the face recognition algorithm (face recognition model based on opencv's dnn or other deep learning framework) to perform face recognition. Face detection and recognition. The above two parts will be explained separately below.
2.1 Use opencv to read pictures from the camera
There are three main types of reading images from opencv. The codes for the three methods are given below:
2.1.1 Opencv reads picture/camera video frames
- Read a single image
# 单张图片读取
import cv2
img_filename = 'demo.png'
img = cv2.imread(img_filename, cv2.IMREAD_COLOR) # 彩色图像
# img = cv2.imread(img_filename, cv2.IMREAD_GRAYSCALE) # 灰度图像
- Read pictures from a folder
# 从文件夹读取
import glob
import cv2
img_dir = r'path/to/your/database'
for img_filename in glob.glob(img_dir + '/*.jpg' ) # 针对jpg图片
img = cv2.imread(img_filename, cv2.IMREAD_COLOR)
- Read video frames from camera
import cv2
def get_cap():
cap = cv2.VideoCapture(0)
return cap
cap = get_cap() # 获取摄像头视频流
id = 1
while True:
ret, frame = cap.read()
if cv2.waitKey(1) == ord('q'):#按Q退出
img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
img = cv2.resize(img, (480, 480))
# img = np.array(img)
break
else:
cv2.imshow('win', frame)
cv2.waitKey(10) # 可以理解为控制帧率
2.1.2 opencv save image as gif and video
Sometimes, we even need to display, so we need to save a video stream as a video file, convert an image to a gif, or convert an image to a video. Sample codes for these operations are also given below:
- Reference for saving video files in video streams.
It should be noted that you should try to save the video according to the encoding of the camera, otherwise problems may occur.
cv2.VideoWriter_fourcc('I','4','2','0'):YUV编码,4:2:0色度子采样。这种编码广泛兼容,但会产生大文件。文件扩展名应为.avi。
cv2.VideoWriter_fourcc('P','I','M','1'):MPEG-1编码。文件扩展名应为.avi。
cv2.VideoWriter_fourcc('X','V','I','D'):MPEG-4编码。如果要限制结果视频的大小,这是一个很好的选择。文件扩展名应为.avi。
cv2.VideoWriter_fourcc('m', 'p', '4', 'v'):较旧的MPEG-4编码。如果要限制结果视频的大小,这是一个很好的选择。文件扩展名应为.m4v。
cv2.VideoWriter_fourcc('X','2','6','4'):较新的MPEG-4编码。如果你想限制结果视频的大小,这可能是最好的选择。文件扩展名应为.mp4。
cv2.VideoWriter_fourcc('T','H','E','O'):这个选项是Ogg Vorbis。文件扩展名应为.ogv。
cv2.VideoWriter_fourcc('F','L','V','1'):此选项为Flash视频。文件扩展名应为.flv。
def save_video(video_name):
cap = cv2.VideoCapture(video_name)
# setting
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) # 获取原视频的宽
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 获取原视频的搞
fps = int(cap.get(cv2.CAP_PROP_FPS)) # 帧率
fourcc = int(cap.get(cv2.CAP_PROP_FOURCC)) # 视频的编码
# 定义视频保存的输出属性
out = cv2.VideoWriter('out.mp4', fourcc, fps, (width, height))
while cap.isOpened():
ret, frame = cap.read()
cv2.imshow('fame', frame)
key = cv2.waitKey(25)
out.write(frame)
if key == ord('q'):
break
cap.release()
out.release()
cv2.destroyAllWindows()
- Convert image to gif
import cv2
import imageio
def save_gif(video_name):
cap = cv2.VideoCapture(video_name)
# 定义视频保存的输出属性
out = []
while cap.isOpened():
ret, frame = cap.read()
cv2.imshow('fame', frame)
key = cv2.waitKey(15)
if not ret: continue
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
out.append(cv2.resize(frame, (w//2, h//2))) # 适当缩放,防止gif过大
if key == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
imageio.mimsave('demo.gif', out, fps=30) # 调整保存的帧率
- Picture to video
import cv2
import os
def img2video(img_dir, save_name):
# setting
width = 1080 # 获取原视频的宽
height = 720 # 获取原视频的搞
fps = 30 # 帧率
fourcc = cv2.VideoWriter_fourcc(*'DIVX') # 视频的编码
# 定义视频保存的输出属性
out = cv2.VideoWriter(save_name, fourcc, fps, (width, height))
for r, ds, fs in os.walk(img_dir):
for f in fs:
file_name = os.path.join(r, f)
img = cv2.imread(file_name)
out.write(img)
return
2.2 Use different face recognition algorithms for detection and recognition
The simplest method for face recognition is to use the dlib framework. The detection process is shown in the figure below:
2.2.1 Model loading
dlib.get_frontal_face_detector()
Three models need to be loaded here, namely the face detection model, the face key point prediction model, and the descriptor feature calculation model. The face detection model can directly call dlib. The other two can be downloaded directly from the dlib official website . Two models:
- shape_predictor_68_face_landmarks.dat
- dlib_face_recognition_resnet_model_v1.dat
2.2.2 Reading pictures
To read images, just use what was mentioned in 2.1, and I won’t go into details.
2.2.3 Face detection and key point extraction
import dlib
def detect_img():
cap = cv2.VideoCapture(0)
detector = dlib.get_frontal_face_detector() # 检测模型
path_pre = "../models/shape_predictor_68_face_landmarks.dat" # 68点模型
pre = dlib.shape_predictor(path_pre)
# 定义视频保存的输出属性
out = []
while cap.isOpened():
ret, frame = cap.read()
key = cv2.waitKey(15)
if not ret: continue
rects = detector(frame, 0)
for obj in rects: # 绘制所有的人脸
# print(dir(obj))
pt1, pt2 = rect2bb(obj)
cv2.rectangle(frame, pt1, pt2, (0, 255, 0), 2)
shapes = pre(frame, obj) # 对当前的人脸框做68点特征点预测
shapes = shape_to_np(shapes)
for (x, y) in shapes:
cv2.circle(frame, (x, y), 1, (255, 0, 0), -1)
cv2.imshow('fame', frame)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
h, w, c = frame.shape
out.append(cv2.resize(frame, (w//2, h//2)))
if key == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
imageio.mimsave('demo.gif', out, fps=20)
It can be found that two functions in the above code are not defined, rect2bb
and shape_to_np
. Since the output of dlib is a custom class, although print can obtain its rect information, we cannot directly pass it to cv2.rectangle, so we need to reprocess the rects and shapes obtained by dlib inference to facilitate processing:
def rect2bb(rect):
x1 = rect.left()
y1 = rect.top()
x2 = rect.right()
y2 = rect.bottom()
return (x1, y1), (x2, y2)
def shape_to_np(shape):
coords = np.zeros((68, 2), dtype=int)
for i in range(0, 68):
coords[i] = (shape.part(i).x, shape.part(i).y)
return coords
Through this demo, we can get the following detection results, which look OK hhh.
2.2.4 Descriptor matching
Through the above example, we have completed face detection and key point estimation, so how to match faces, that is, how to match the current face with the faces in our database? I think it is mainly divided into the following steps:
- Create a face data set.
Here we can place the face data into folders according to student ID or person name, as shown in the figure below:
Under each person's folder, pictures of the person's face in different postures are placed as the original picture data set. However, in the matching process, we often do not directly use the original pictures in the database because, therefore, it is more appropriate 计算特征是耗时的
. The method is to perform face recognition, feature point detection and feature extraction on the pictures in the database in advance, and generate a feature data set to replace the original picture data set, as shown in the following figure:
-
Calculate unknown facial features and facial features in the database separately
As the name suggests, we need to complete facial feature extraction based on the code in 2.2.3. The code is as follows:
def load_model():
detector = dlib.get_frontal_face_detector()
path_pre = "../models/shape_predictor_68_face_landmarks.dat" # 68点模型
pre = dlib.shape_predictor(path_pre)
path_model = "../models/dlib_face_recognition_resnet_model_v1.dat" # resent模型
model = dlib.face_recognition_model_v1(path_model)
return detector, pre, model
def get_describe_for_face(detector, pre, model, img):
det_img = detector(img, 0)
try:
shape = pre(img, det_img[0])
know_encode = model.compute_face_descriptor(img, shape)
except:
return -1
return know_encode
# 获取待检测图片的encode
unknown_encod = get_describe_for_face(detector, pre, model, unknown_img)
Above we have given the code for calculating unknown face features, and we also need to extract features from the known face data in the database. As mentioned in the first step of 2.2.4 above, we need to preprocess the features in the data set in advance and save them. for a similar face_fea_database
data set. 批处理获取特征
Reference code given here :
import os
import pickle
import numpy as np
from PIL import Image
def Eu(a, b): # 距离函数
return np.linalg.norm(np.array(a) - np.array(b), ord=2)
face_dir = '../face_database'
face_feature_dir = '../face_fea_database'
unknown_img = np.array(Image.open('../face_database/20221000/1.jpg'))
detector, pre, model = load_model()
unknown_fea = get_describe_for_face(detector, pre, model, unknown_img)
for id in os.listdir(face_dir):
face_path = os.path.join(face_dir, id)
face_fea_path = os.path.join(face_feature_dir, id)
os.makedirs(face_fea_path, exist_ok=True)
for img_name in os.listdir(face_path):
img_path = os.path.join(face_path, img_name)
fea_path = os.path.join(face_fea_path, img_name.replace('.jpg', '.ft'))
img = np.array(Image.open(img_path))
img_feature = get_describe_for_face(detector, pre, model, img)
with open(fea_path, 'wb') as f:
pickle.dump(img_feature, f)
with open(fea_path, 'rb') as f:
data = pickle.load(f)
print("save and load result is same? ", Eu(img_feature, unknown_fea) == Eu(data, unknown_fea))
- In this part of matching unknown faces with faces in the database,
we need to define our own matching rules. Here I use a double threshold filter for unknown faces. If the difference between the two face features is too big, then skip it; If the difference between the two faces is very small, the results are returned directly; those between the two thresholds are placed in a list, and finally sorted by distance, and the attributes of the person corresponding to the face with the smallest distance are returned.
The function code of the macth part is given below:
def record_status(status, name=None):
f = open('../recog_status.txt', 'w', encoding='utf-8')
if status == 3: # 打卡成功
info = STATUS_DICT[status] + name
else:
info = STATUS_DICT[status]
f.write(info)
f.close()
def match_face_by_face_recognize(unknown_img, face_dir, stu_lists, thres=0.4, min_thres=0.55):
MODEL_STATUS = 1
record_status(MODEL_STATUS)
# detector, pre, model = load_model()
MODEL_STATUS = 2
record_status(MODEL_STATUS)
# 获取待检测图片的encode
unknown_encod = face_recognition.face_encodings(unknown_img)
if unknown_encod == []:
record_status(4)
print('无法识别摄像头中的人脸')
return -1, 'Unknown'
else:
unknown_encod = unknown_encod[0]
stus_conf = {
stu[0]:[stu[1], 2] for stu in stu_lists}
for id, name in stu_lists:
# 获取当前学生的人脸地址
stu_face_dir = os.path.join(face_dir, str(id))
for img_name in os.listdir(stu_face_dir):
img_path = os.path.join(stu_face_dir, img_name)
# func1. use dlib to get encode if necessary
# img = np.array(Image.open(img_path))
# know_encode = get_describe_for_face(detector, pre, model, img)
# func2. use feature prepared by utils.prepare_feature.py
f = open(img_path, 'rb')
know_encode = pickle.load(f)
# func3. use face recognize
# img = face_recognition.load_image_file(img_path)
# know_encode = face_recognition.face_encodings(img)
if know_encode == []:
record_status(4)
print('无法识别人脸库中的人脸')
return -1, 'Unknown' # 人脸库一般不存在这种情况!!!必须保证高质量人脸
else:
know_encode = know_encode[0]
# 如果检测到差距小于阈值,认为检测成功, 退出
distance = Eu(know_encode, unknown_encod)
if distance > min_thres: break # 这个人必然不是
else:
if distance < thres: # 阈值很小了
MODEL_STATUS = 3
record_status(MODEL_STATUS, name)
return id, name
else: # 阈值一般
stus_conf[id][1] = min(stus_conf[id][1], distance)
# print(stus_conf)
res = sorted(stus_conf.items(), key=lambda x:x[1][1])[0]
print(res)
id, (name, conf) = res
if conf > min_thres:
MODEL_STATUS = 4
record_status(MODEL_STATUS)
return -1, 'Unknown'
else:
MODEL_STATUS = 3
record_status(MODEL_STATUS, name)
return id, name
if __name__ == '__main__':
cap = get_cap()
id = 1
while True:
ret, frame = cap.read()
if cv2.waitKey(1) == ord('q'):#按Q退出
img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
img = cv2.resize(img, (480, 480))
# img = np.array(img)
break
else:
cv2.imshow('win', frame)
stu_lists = [(20221001, '钱全'), (20221002, '葛娟'), (20221003, '卫雅'), (20221004, '王宁'), (20221005, '韩惠'),
(20221006, '邹慧')]
detector, pre, model = load_model()
result = match_face(img, '../face_fea_database', stu_lists, detector, pre, model)
print(result)
In fact, as can be seen from the above code, we actually have another way to quickly extract image features, which is to use face_recognize
this library. The code is as follows, but in terms of speed, it is definitely better to load the preprocessed feature file (the second method). quick.
func3. use face recognize
img = face_recognition.load_image_file(img_path)
know_encode = face_recognition.face_encodings(img)
3. Database design based on sqlite3
The database itself is not the focus of this project, so here I briefly use the sqlite3 database that comes with python. Here I only briefly define some necessary classes, because this is a face check-in system, so it inevitably requires students and courses. , check-in information and course selection information form.
3.1 Simple definition of database class
First define a database class to manage our data, including data import, data reading, data updating, etc. It is clearer and more intuitive to operate the database through a class. The ER diagram will not be drawn here. This task is relatively simple. For the sake of simplicity, four tables are designed. The specific contents are described in detail below.
3.1.1 CardRecord punch-in information table
3.1.2 Course course schedule
3.1.3 Relation course selection relationship table
3.1.4 Student student table
For people who have difficulty choosing names, naming is really painful. In order to quickly generate different student names and course names, I used random splicing to generate csv files, and then imported them into the database. Here I only give the csv generation code. You can Select and modify as needed:
def random_get_datas():
import random
start_id = 20221000
firstName = "赵钱孙李周吴郑王冯陈褚卫蒋沈韩陶姜戚谢邹喻水云苏潘葛奚范彭"
lastName = "秀娟英华慧巧美娜静淑惠珠翠雅力明永健宁贵福生龙元全国胜学祥才"
stu_infos, class_infos = [], []
with open('student.csv', 'w', encoding='utf-8') as f:
f.writelines('id,name,age,details\n')
for i in range(10):
id, name, age, details = start_id, \
random.choice(firstName) + random.choice(lastName), \
random.randint(18, 24), \
"喜欢" + random.choice(['足球', '篮球', '排球'])
start_id += 1
f.writelines("{},{},{},{}\n".format(id, name, age, details))
stu_infos.append((id, name, age, details))
with open('class.csv', 'w', encoding='utf-8') as f:
f.writelines('id,name,status\n')
start_id = 19334
firstName = ['高等','基础' ,'线性' ,'随机' ]
lastName = ['数学', '物理', '信号分析']
for i in range(4):
id, name, status = start_id, \
random.choice(firstName) + random.choice(lastName), \
1
start_id += 1
f.writelines("{},{},{}\n".format(id, name, status))
class_infos.append((id, name, status))
with open('relation.csv', 'w', encoding='utf-8') as f:
id = 0
f.writelines("id,stu_id,course_id,create_time\n")
for classes in class_infos:
a, b = random.randint(0, 4), random.randint(5, len(stu_infos))
for stu in stu_infos[a:b]:
time = "2022-5-" + str(random.randint(1, 10))
f.writelines("{},{},{},{}\n".format(id, stu[0], classes[0], time))
id += 1
print('random init success.')
It is quite easy to import sqlite from csv. The sample code is as follows, among which conn = sqlite3.connect(self.db_path)
:
def get_class_from_csv(self, csv_file):
df = pd.read_csv(csv_file)
try:
df.to_sql('Course', self.conn, if_exists='append', index=False)
except Exception as e:
print(e)
finally:
print("导入成功")
3.2 Encapsulate commonly used SQL queries into database class member functions
This is also relatively basic, integrating some commonly used query functions into the database class.
def get_courses(self):
# 返回课程编号和名称
sql = '''
select * from Course where status == 1;
'''
curr = self.conn.cursor()
curr.execute(sql)
return [item[:2] for item in curr.fetchall()]
def get_stu_info(self):
sql = '''
select * from student;
'''
curr = self.conn.cursor()
curr.execute(sql)
return {
item[0]:item[1:] for item in curr.fetchall()}
def get_stus_by_course(self, course_id):
# 返回课程编号和名称
sql = '''
select Student.id, Student.name from Student, Relation where Relation.course_id == ? and Student.id == Relation.stu_id
'''
curr = self.conn.cursor()
curr.execute(sql, [course_id])
In fact, what I wrote here is relatively simple, just to inspire others. You can refer to a similar method to write some functional SQL statements into functions for easy calling.
4. GUI design based on PyQt5
This part of GUI design is mainly an interactive function. Everyone chooses different frameworks according to their familiarity. The python client is mainly Heba. Those who are familiar with front-end and back- tkinter
end pyqt5
frameworks can also use html+css+js+django/flask
similar solutions. I have worked on a pyqt5 client before, so I am relatively familiar with it. I will use pyqt5 as an example to explain it here.
Comrades who want to use pyqt5 must install the basic pyqt5 python library. In order to facilitate GUI design, it is best to configure it, that 三件套
is:
qt designer
: Makes GUI design simpler. It can be understood as a software that can drag components around to complete the framework design.pyrcc
: Convert multiple resources referenced by the pyqt5 interface into a binary file, which is convenient to use without having to call each file.pyuic
: The GUI file of pyqt5 is a .ui file. This tool can convert the ui file into a py file for us to reuse classes.
I won’t go into details about the configuration and usage of these three things here. If you are interested, I will write a special explanation ~
4.1 Framework and folder structure design
Let me talk about the structure of the gui file. In fact, any pyqt5 application is similar. In your home directory, you can create a resource folder, and create a folder and a folder in UI
it images
;
UI
It mainly stores your UI source files for different interfaces, as well as your convertedpyuic
py files (enclosed in curly braces). The converted py files are actually the py class definition corresponding to the panel you designed in Qt Designer. and implementation. You can directly inherit this class later and then do some logic, including the implementation of signals and slot functions.images
It mainly stores some of your image resource files. The resource files are finally saved in.qrc
. Later, the resource files can be converted to images_rc.py through pyrcc for easy use later. Of course, if you have some audio data, you can create it in a similar way.
The rest of the folders and definitions are up to you~ It is best to use a whole main file, and then complete the jumps and interactions of different interfaces in it. This is more clear and intuitive, and the interfaces are decoupled as much as possible and have lower dependencies.
4.2 Start interface design
As shown in the picture above, it can actually be seen that the composition of the start interface is relatively simple, just a stack of buttons, labels and combo boxes, mainly to display the name of our software, add selection boxes to select courses, and select attendance time. Interface switching button and customized minimize and maximize buttons (qt comes with very ugly hhh)
You just need to choose the appropriate widget (layout) and organize them together. For beginners, you don’t need to worry too much. I think you only need to put the components you want, and then even if you fix their positions, as long as they can be used, it is a victory; there is a lot to say here, hahaha. If you want to design it yourself, just click on file in the upper left corner and create as follows. Then select different components on the left and drag them over.
Now that you have configured Qt Designer, you can open my UI file and look at the specific layout design, etc. In fact, it takes some effort to make Qt look good. Qt's QSS still feels inferior to CSS. Meaning, under some rounded corner design, color matching and mouse events, it still requires everyone to put some effort into making the changes of controls smooth.
4.3 Verification interface design
The verification interface is quite simple. In fact, it is to prevent students or non-administrators from messing around with the start interface and exporting and opening data. Therefore, identity verification is required. It is relatively simple. You only need to enter the password, and then verify or return.
4.4 Customized listwidget design
The purpose of designing this listwidget here is actually to display the avatar, name, student number and check-in information of the person who clocked in, and put him in a listwidget. However, Qt does not have a basic component that can meet this demand, so we can design a form , and then embed it into the listwidget. Of course, there are some details on how to update and sort the listwidget elements later. I won’t go into details here. If you are interested, you can find the answer in my code.
4.4 Main interface design
The main interface should be the most complicated, but in fact it is only relatively complicated. I will describe it according to the above 8 parts:
- Check-in panel:
- Status display bar
- Remaining time display:
- Check-in progress update:
- Customize check-in characters and status display:
- Camera and check-in:
- Data output:
- Interface jump:
4.5 How to effectively organize different UI interface classes
5. Effect display
5.1 Detection and recognition effect display
5.2 Database export and viewing
6. Code acquisition and download
The complete project code is posted on my public account: after a hundred years of closure,
if you reply to "Face Check-in System", you can get the download link of the complete code for free!
Creation is not easy, and everyone is welcome to criticize and correct it. Use your little hands, comment, and save it!
I will also continue to update projects of interest from time to time~