Use python and pyqt5 to easily get started with the face recognition system (including code)


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 are anacondaand pycharm专业版and pip镜像源. 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 sqlite3a database, but we'd better configure mysqlthe 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-pythonbasically require dlibthis library. I will talk about the specific libraries that are relied on later, but For No Module Errorthe situation, pip install xxxit 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依赖的包

  1. First go to the official website to download the installation package
    Insert image description here

  2. 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.
    Insert image description here

  3. Check whether anaconda is installed successfully

Open cmd and enter conda -V. Generally, there will be two situations. The following one is installed.
Insert image description here
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, paththat is, add the binand Scriptspath of anaconda Go to the environment variables as follows:

C:\Users\xxx\anaconda3\bin
C:\Users\xmhh\anaconda3\Scripts
C:\Users\xmhh\anaconda3

Insert image description here
Insert image description here

After the operation, just check whether conda is installed. 一般出问题就是环境变量没加入进去Otherwise, there is no problem.

  1. 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

  1. Go to the official website to download the installation package
    Insert image description here
  • 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:
    Insert image description here

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:

  1. C:\Users\xxxCreate a pipfolder named in, and then create a file in it . pip.iniNote that you need to modify the content of this file later, so you can change the name to first pip.txt, and then change it topip.ini
    Insert image description here
  2. Just modify pip.inithe 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
  1. 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.

  1. Download the installation package of mysql database.
    Insert image description here
    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 not my.iniseem datato be there, but it is not important. Download the official website and unzip it and it will be done 后面再配.
    Insert image description here

  2. binConfigure environment variables, which is the folder under the mysql folder
    Insert image description here

  3. Create and configure in the root directory of the mysqll filemy.ini

my.iniThe 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
  1. Open cmdand enter mysqld --initializeto complete initialization. The folder appears in the root directory data, 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.
    Insert image description here
    Insert image description here
  2. 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, numpyand pandasare the basic libraries for data processing; secondly, some python libraries for image processing, and cv2; Pillowthen, the gui library, pyqt5and finally the face recognition library cmake, dliband 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:

  1. cmdFirst use the command in your project path condato 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
  1. Create a file named under your project path requirements.txtand fill in the following information. There seems to be no big problem with the version. Just install it in order. The dlibinstallation may be a bit slow. If you think it is too slow, you can still do it. Finally, use it alone pip install dlibto install, but you need to pipinstall cmakethe package first, otherwise an error will occur.
numpy
pandas
pyqt5
cmake
opencv-python
Pillow
dlib
face_recognition
  1. Run pip install -r requirements.txtto 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) # 调整保存的帧率

Insert image description here

  • 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:
Insert image description here

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:

  1. shape_predictor_68_face_landmarks.dat
  2. 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, rect2bband 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.
Insert image description here

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:

  1. 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:
    Insert image description here
    Insert image description here

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:
Insert image description here

  1. 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_databasedata 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))

  1. 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_recognizethis 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

Insert image description here
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

Insert image description here

3.1.2 Course course schedule

Insert image description here

3.1.3 Relation course selection relationship table

Insert image description here

3.1.4 Student student table

Insert image description here

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- tkinterend pyqt5frameworks can also use html+css+js+django/flasksimilar 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

Insert image description here
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 UIit images;

  • UIIt mainly stores your UI source files for different interfaces, as well as your converted pyuicpy 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.
  • imagesIt 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

Insert image description here
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.

Insert image description here
Insert image description here

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

Insert image description here
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

Insert image description here
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.
Insert image description here

4.4 Main interface design

Insert image description here
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:

  1. Check-in panel:
  2. Status display bar
  3. Remaining time display:
  4. Check-in progress update:
  5. Customize check-in characters and status display:
  6. Camera and check-in:
  7. Data output:
  8. Interface jump:

4.5 How to effectively organize different UI interface classes

5. Effect display

5.1 Detection and recognition effect display

Insert image description here

Insert image description here

Insert image description here

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~

Guess you like

Origin blog.csdn.net/qq_36306288/article/details/124690867