博客汇总:Python | 人脸识别系统 — 博客索引

GitHub地址:Su-Face-Recognition

注:阅读本博客前请先参考

工具安装、环境配置:Python | 人脸识别系统 — 简介

UI界面设计:Python | 人脸识别系统 — UI界面设计

UI事件处理:Python | 人脸识别系统 — UI事件处理

摄像头画面展示:Python | 人脸识别系统 — 摄像头画面展示

更多关于人脸识别库 face_recognition 的基础使用教程请移步:face_recognition GitHub

一、初始化

        初始化 isFaceRecognition_flag 标志判断当前人脸识别状态。

        按钮绑定人脸识别判断器 recognize_face_judge 方法。

        self.isFaceRecognition_flag = False  # 是否打开人脸识别标志
        self.recognition_button.clicked.connect(self.recognize_face_judge)

二、判断器

        通过 self.isFaceRecognition_flag 标志判断当前人脸识别是否打开。

    # 人脸识别判断器
    def recognize_face_judge(self):
        if not self.cap.isOpened():
            QMessageBox.information(self, "提示", self.tr(u"请先打开摄像头"))
        else:
            # 点击人脸识别时,人脸识别是关闭的
            if not self.isFaceRecognition_flag:
                self.isFaceRecognition_flag = True
                self.recognition_button.setText(u'关闭人脸识别')
                self.recognize_continuous_face()
            # 点击人脸识别时,人脸识别已经开启
            elif self.isFaceRecognition_flag:
                self.isFaceRecognition_flag = False
                self.recognition_button.setText(u'人脸识别')
                self.clear_information()
                self.show_camera()

三、识别器

        1.瞬时人脸识别

                a.核心方法:

  • face_locations —— 定位图中所有的人脸的像素位置   
    • 返回值是一个列表形式。列表中每一个元素是一张人脸的位置信息,包括[top, right, bottom, left]。
  • face_encodings —— 获取图像文件中所有面部编码信息
    • 返回值是一个编码列表,参数仍然是要识别的图像对象,如果后续访问时需要加上索引或遍历进行访问,每张人脸的编码信息为一个128维向量。
  • compare_faces —— 由面部编码信息进行面部识别匹配

    • 主要用于匹配两个面部特征编码,利用这两个特征向量的内积来衡量相似度,根据阈值确认是否是同一个人。
    • 第一个参数是一个面部编码列表(很多张脸), 第二个参数是给出单个面部编码(一张脸), compare_faces 会将第二个参数中的编码信息与第一个参数中的所有编码信息依次匹配,返回值是一个布尔列表,匹配成功则返回 True,匹配失败则返回 False,顺序与第一个参数中脸部编码顺序一致。
    • 参数 tolerance 为识别阈值,默认值是 0.39。tolerance 值越小,匹配越严格。

                b.核心代码:                   

# 定位当前帧中人脸位置
unknown_locations = face_recognition.face_locations(frame)
# 对当前帧中所有的人脸进行编码
unknown_encodings = face_recognition.face_encodings(frame, unknown_locations)

for unknown_encoding in unknown_encodings:
    # 将未知的人脸 unknown_encoding 与已知的人脸编码 recognize_encodings 进行比对,判断是否为同一张脸,结果保存到match中
    match = face_recognition.compare_faces(recognize_encodings, unknown_encoding, tolerance=TOLERANCE)
    # 如果在结果中存在True,说明用户识别成功
    if True in match:
        return True

                c.全部代码:

    def recognize_instant_face(self, recognize_encoding):
        # 隔帧处理,减少计算量
        process_this_frame = True
        # 超过10帧判断识别失败,因为隔帧处理,一共判断5帧
        total_frame = 0
        # 已知的人脸编码集合
        recognize_encodings = [recognize_encoding]
        # 当摄像头打开时开始检测,当 检测成功 或 超过10帧 时推出循环
        while self.cap.isOpened():
            # 获取当前摄像头画面帧 frame
            ret, frame = self.cap.read()
            # 帧数加一
            total_frame += 1
            # 减少界面卡顿
            QApplication.processEvents()
            # 对帧进行裁剪处理,减少计算量
            small_frame = cv2.resize(frame, (0, 0), fx=SET_SIZE, fy=SET_SIZE)

            # 判断当前帧是否需要计算(隔帧处理)
            if process_this_frame:
                QApplication.processEvents()
                # 核心代码
                unknown_locations = face_recognition.face_locations(small_frame)
                unknown_encodings = face_recognition.face_encodings(small_frame, unknown_locations)
                for unknown_encoding in unknown_encodings:
                    match = face_recognition.compare_faces(recognize_encodings, unknown_encoding, tolerance=TOLERANCE)
                    if True in match:
                        return True
            # 隔帧处理
            process_this_frame = not process_this_frame

            # 超时退出
            if total_frame >= 10.0:
                return False

            # 对传回来的画面进行处理
            show_video = cv2.resize(frame, (self.WIN_WIDTH, self.WIN_HEIGHT))
            show_video = cv2.cvtColor(show_video, cv2.COLOR_BGR2RGB)
            self.show_image = QImage(show_video.data, show_video.shape[1], show_video.shape[0], QImage.Format_RGB888)
            self.camera_label.setPixmap(QPixmap.fromImage(self.show_image))

        2.连续人脸识别

        核心方法同上,只不过会对当前画面中的人脸实时使用红框进行标识,并在红框下方进行用户名的标识。如果人脸未知,则使用UnKnow进行标识。同上在下方提示框进行用户信息的标识。

                a.全部代码:

    # 持续人脸识别
    def recognize_continuous_face(self):
        # 通过数据库读取已知的用户姓名以及人脸编码
        self.read_person_msg()
        known_names = []  # 存放已知用户的名字
        known_encodings = []  # 存放已知用户的人脸特征信息
        for i in range(len(self.all_list)):
            known_names.append(self.all_list[i][0])
            known_encodings.append(FaceEncodingUtil.decoding_FaceStr(self.all_list[i][5]))

        # 从摄像头实时读取未知用户编码
        unknown_locations = []  # 存放未知用户的人脸位置
        unknown_names = [] # 存放经过识别的用户名字
        process_this_frame = True
        while self.cap.isOpened():
            ret, frame = self.cap.read()
            QApplication.processEvents()
            small_frame = cv2.resize(frame, (0, 0), fx=SET_SIZE, fy=SET_SIZE)

            if process_this_frame:
                QApplication.processEvents()
                unknown_locations = face_recognition.face_locations(small_frame)
                unknown_encodings = face_recognition.face_encodings(small_frame, unknown_locations)
                unknown_names = []
                for unknown_encoding in unknown_encodings:
                    name = "Unknown" # 默认未知
                    matches = face_recognition.compare_faces(known_encodings, unknown_encoding, tolerance=TOLERANCE)
                    if True in matches:
                        first_match_index = matches.index(True)
                        name = known_names[first_match_index]
                    unknown_names.append(name)

            process_this_frame = not process_this_frame

            # 保存捕捉到的人脸姓名信息
            self.set_name = set(unknown_names)
            self.set_names = tuple(self.set_name)

            # 绘制图像
            for (top, right, bottom, left), name in zip(unknown_locations, unknown_names):
                top *= int(1 / SET_SIZE)
                right *= int(1 / SET_SIZE)
                bottom *= int(1 / SET_SIZE)
                left *= int(1 / SET_SIZE)
                # 画矩形框
                cv2.rectangle(frame, (left, top), (right, bottom), (60, 20, 220), 2)

                # 由于opencv无法显示汉字,用PIL进行转换
                cv2_img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                pil_img = Image.fromarray(cv2_img)
                draw = ImageDraw.Draw(pil_img)
                # 参数1:字体文件路径,参数2:字体大小
                font = ImageFont.truetype(DATA_FOLDER_PATH + "MicrosoftYaHeiFont.ttf", 24, encoding="utf-8")
                # 参数1:打印坐标,参数2:文本,参数3:字体颜色,参数4:字体
                draw.text((left + 10, bottom), name, (220, 20, 60), font=font)
                frame = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)

            self.show_results()
            show_video = cv2.resize(frame, (self.WIN_WIDTH, self.WIN_HEIGHT))
            show_video = cv2.cvtColor(show_video, cv2.COLOR_BGR2RGB)
            self.show_image = QImage(show_video.data, show_video.shape[1], show_video.shape[0], QImage.Format_RGB888)
            self.camera_label.setPixmap(QPixmap.fromImage(self.show_image))

    # 展示人脸识别结果
    def show_results(self):
        if self.isFaceRecognition_flag:
            msg_label = {0: self.msg_label_a,
                         1: self.msg_label_b,
                         2: self.msg_label_c}

            # 最多放置3个人的信息
            if len(self.set_names) > 3:
                show_person = 3
            else:
                show_person = len(self.set_names)

            if show_person != 0:
                for show_index in range(show_person):
                    name = self.set_names[show_index]
                    try:
                        per_label = msg_label[show_index]
                        index = self.search_person_index(self.all_list, name)
                        if index != -1:
                            infor_str = ' 姓名: ' + name + '                ' + \
                                        ' 年龄: ' + self.all_list[index][2] + '                 ' + \
                                        ' 性别: ' + self.all_list[index][3] + '                 ' + \
                                        ' 更多: ' + self.all_list[index][4]
                            per_label.setText(infor_str)
                            per_label.setStyleSheet("color:white;font-size:20px;font-family:Microsoft YaHei;")
                            per_label.setWordWrap(True)
                    except:
                        QMessageBox.about(self, '警告', '请检查' + name + '的信息')

            if show_person != 3:
                for empty in range(3)[show_person:]:
                    per_label = msg_label[empty]
                    per_label.setText("")

    # 读取用户信息
    def read_person_msg(self):
        all_msg = UserSqlUtil.search_all_msg()
        for tup in all_msg:
            per_list = []
            for i in tup:
                per_list.append(i)
            self.all_list.append(per_list)

    # 查找指定用户下标
    @staticmethod
    def search_person_index(persons_infor, name):
        for i in range(len(persons_infor)):
            if persons_infor[i][0] == name:
                return i
        return -1

四、全部代码

注:以下代码仅为项目部分代码,完整代码参考GitHub:Su-Face-Recognition

# 主界面
class UserMainWindow(QMainWindow, UserMainUi):

    def __init__(self, parent=None):
        super(UserMainWindow, self).__init__(parent)
        self.setupUi(self)

        self.show_image = None
        self.set_name = None
        self.set_names = None
        self.need_record_name = ([])

        self.camera_start_time = None
        self.detect_start_time = None

        self.cap = cv2.VideoCapture()  # 相机
        self.source = CAPTURE_SOURCE  # 相机标号
        self.WIN_WIDTH = 800  # 相机展示画面宽度
        self.WIN_HEIGHT = 500  # 相机展示画面高度
        self.isFaceRecognition_flag = False  # 是否打开人脸识别标志

        self.all_list = []

        # 窗口控制
        self.close_button.clicked.connect(self.close_window)  # 关闭窗口
        self.minimize_button.clicked.connect(self.showMinimized)  # 最小化窗口

        self.recognition_button.clicked.connect(self.recognize_face_judge)  # 人脸识别



    # 人脸识别判断器
    def recognize_face_judge(self):
        if not self.cap.isOpened():
            QMessageBox.information(self, "提示", self.tr(u"请先打开摄像头"))
        else:
            # 点击人脸识别时,人脸识别是关闭的
            if not self.isFaceRecognition_flag:
                self.isFaceRecognition_flag = True
                self.recognition_button.setText(u'关闭人脸识别')
                self.recognize_continuous_face()
            # 点击人脸识别时,人脸识别已经开启
            elif self.isFaceRecognition_flag:
                self.isFaceRecognition_flag = False
                self.recognition_button.setText(u'人脸识别')
                self.clear_information()
                self.show_camera()

    # 瞬时人脸识别
    def recognize_instant_face(self, recognize_encoding):
        # 隔帧处理,减少计算量
        process_this_frame = True
        # 超过10帧判断识别失败,因为隔帧处理,一共判断5帧
        total_frame = 0
        # 已知的人脸编码集合
        recognize_encodings = [recognize_encoding]
        # 当摄像头打开时开始检测,当 检测成功 或 超过10帧 时推出循环
        while self.cap.isOpened():
            # 获取当前摄像头画面帧 frame
            ret, frame = self.cap.read()
            # 帧数加一
            total_frame += 1
            # 减少界面卡顿
            QApplication.processEvents()
            # 对帧进行裁剪处理,减少计算量
            small_frame = cv2.resize(frame, (0, 0), fx=SET_SIZE, fy=SET_SIZE)

            # 判断当前帧是否需要计算(隔帧处理)
            if process_this_frame:
                QApplication.processEvents()
                # 核心代码
                unknown_locations = face_recognition.face_locations(small_frame)
                unknown_encodings = face_recognition.face_encodings(small_frame, unknown_locations)
                for unknown_encoding in unknown_encodings:
                    match = face_recognition.compare_faces(recognize_encodings, unknown_encoding, tolerance=TOLERANCE)
                    if True in match:
                        return True
            # 隔帧处理
            process_this_frame = not process_this_frame

            # 超时退出
            if total_frame >= 10.0:
                return False

            # 对传回来的画面进行处理
            show_video = cv2.resize(frame, (self.WIN_WIDTH, self.WIN_HEIGHT))
            show_video = cv2.cvtColor(show_video, cv2.COLOR_BGR2RGB)
            self.show_image = QImage(show_video.data, show_video.shape[1], show_video.shape[0], QImage.Format_RGB888)
            self.camera_label.setPixmap(QPixmap.fromImage(self.show_image))

    # 持续人脸识别
    def recognize_continuous_face(self):
        # 通过数据库读取已知的用户姓名以及人脸编码
        self.read_person_msg()
        known_names = []  # 存放已知用户的名字
        known_encodings = []  # 存放已知用户的人脸特征信息
        for i in range(len(self.all_list)):
            known_names.append(self.all_list[i][0])
            known_encodings.append(FaceEncodingUtil.decoding_FaceStr(self.all_list[i][5]))

        # 从摄像头实时读取未知用户编码
        unknown_locations = []  # 存放未知用户的人脸位置
        unknown_names = [] # 存放经过识别的用户名字
        process_this_frame = True
        while self.cap.isOpened():
            ret, frame = self.cap.read()
            QApplication.processEvents()
            small_frame = cv2.resize(frame, (0, 0), fx=SET_SIZE, fy=SET_SIZE)

            if process_this_frame:
                QApplication.processEvents()
                unknown_locations = face_recognition.face_locations(small_frame)
                unknown_encodings = face_recognition.face_encodings(small_frame, unknown_locations)
                unknown_names = []
                for unknown_encoding in unknown_encodings:
                    name = "Unknown" # 默认未知
                    matches = face_recognition.compare_faces(known_encodings, unknown_encoding, tolerance=TOLERANCE)
                    if True in matches:
                        first_match_index = matches.index(True)
                        name = known_names[first_match_index]
                    unknown_names.append(name)

            process_this_frame = not process_this_frame

            # 保存捕捉到的人脸姓名信息
            self.set_name = set(unknown_names)
            self.set_names = tuple(self.set_name)

            # 绘制图像
            for (top, right, bottom, left), name in zip(unknown_locations, unknown_names):
                top *= int(1 / SET_SIZE)
                right *= int(1 / SET_SIZE)
                bottom *= int(1 / SET_SIZE)
                left *= int(1 / SET_SIZE)
                # 画矩形框
                cv2.rectangle(frame, (left, top), (right, bottom), (60, 20, 220), 2)

                # 由于opencv无法显示汉字,用PIL进行转换
                cv2_img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                pil_img = Image.fromarray(cv2_img)
                draw = ImageDraw.Draw(pil_img)
                # 参数1:字体文件路径,参数2:字体大小
                font = ImageFont.truetype(DATA_FOLDER_PATH + "MicrosoftYaHeiFont.ttf", 24, encoding="utf-8")
                # 参数1:打印坐标,参数2:文本,参数3:字体颜色,参数4:字体
                draw.text((left + 10, bottom), name, (220, 20, 60), font=font)
                frame = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)

            self.show_results()
            show_video = cv2.resize(frame, (self.WIN_WIDTH, self.WIN_HEIGHT))
            show_video = cv2.cvtColor(show_video, cv2.COLOR_BGR2RGB)
            self.show_image = QImage(show_video.data, show_video.shape[1], show_video.shape[0], QImage.Format_RGB888)
            self.camera_label.setPixmap(QPixmap.fromImage(self.show_image))

    # 展示人脸识别结果
    def show_results(self):
        if self.isFaceRecognition_flag:
            msg_label = {0: self.msg_label_a,
                         1: self.msg_label_b,
                         2: self.msg_label_c}

            # 最多放置3个人的信息
            if len(self.set_names) > 3:
                show_person = 3
            else:
                show_person = len(self.set_names)

            if show_person != 0:
                for show_index in range(show_person):
                    name = self.set_names[show_index]
                    try:
                        per_label = msg_label[show_index]
                        index = self.search_person_index(self.all_list, name)
                        if index != -1:
                            infor_str = ' 姓名: ' + name + '                ' + \
                                        ' 年龄: ' + self.all_list[index][2] + '                 ' + \
                                        ' 性别: ' + self.all_list[index][3] + '                 ' + \
                                        ' 更多: ' + self.all_list[index][4]
                            per_label.setText(infor_str)
                            per_label.setStyleSheet("color:white;font-size:20px;font-family:Microsoft YaHei;")
                            per_label.setWordWrap(True)
                    except:
                        QMessageBox.about(self, '警告', '请检查' + name + '的信息')

            if show_person != 3:
                for empty in range(3)[show_person:]:
                    per_label = msg_label[empty]
                    per_label.setText("")

    # 读取用户信息
    def read_person_msg(self):
        all_msg = UserSqlUtil.search_all_msg()
        for tup in all_msg:
            per_list = []
            for i in tup:
                per_list.append(i)
            self.all_list.append(per_list)

    # 查找指定用户下标
    @staticmethod
    def search_person_index(persons_infor, name):
        for i in range(len(persons_infor)):
            if persons_infor[i][0] == name:
                return i
        return -1

    # 清除人脸识别结果信息
    def clear_information(self):
        self.msg_label_a.setText("")
        self.msg_label_b.setText("")
        self.msg_label_c.setText("")

继续阅读:

用户端逻辑:

管理员端逻辑:

注:以上代码仅供参考,如需运行,参考GitHub源代码: Su-Face-Recognition 

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐