You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt人脸识别考勤应用UI卡顿:如何正确实现EncodeFaceThread?

解决PyQt5人脸识别线程导致UI卡顿的问题

问题核心原因

摄像头采集帧的速度远快于人脸识别逻辑的处理速度,导致Queue中积压了大量未处理的旧帧,EncodeFaceThread一直忙于处理过期帧,抢占了过多系统资源,间接拖慢了UI线程的响应。而替换为sleep逻辑时,线程没有密集计算任务,不会抢占资源,因此UI恢复流畅。

解决方案

1. 限制队列长度,只保留最新帧

给队列设置最大长度,当队列满时自动丢弃最早的帧,确保EncodeFaceThread始终处理最新的摄像头帧,避免旧帧积压。

2. 控制摄像头采集帧率

避免摄像头无限制快速采集帧,添加帧率控制,减少不必要的帧生成和队列推送,平衡流畅度与处理压力。

3. 优化人脸识别计算

缩小帧尺寸可显著加快face_locations和face_encodings的处理速度,因为人脸识别算法的计算量与图像像素数正相关,缩小帧对编码结果的影响极小。

修改后的完整代码

from queue import Queue
from sys import argv
from cv2 import COLOR_BGR2RGB, VideoCapture, cvtColor, resize
from face_recognition import compare_faces, face_encodings, face_locations
from numpy import ndarray
from time import time, sleep
from PyQt5.QtCore import QThread, pyqtSignal, pyqtSlot
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow


class WebcamThread(QThread):
    ndarray_frame_signal = pyqtSignal(ndarray)
    qimage_frame_signal = pyqtSignal(QImage)

    def __init__(self, fps=15):
        super().__init__()
        self.cap = VideoCapture(0)
        self.fps = fps
        self.frame_interval = 1.0 / fps  # 每帧间隔时间

    def run(self):
        while self.isRunning():
            start_time = time()
            # 读取摄像头帧,判断读取是否成功
            ret, frame = self.cap.read()
            if not ret:
                break
            frame = cvtColor(frame, COLOR_BGR2RGB)
            self.ndarray_frame_signal.emit(frame)
            # 转换为QImage用于UI显示
            h, w, _ = frame.shape
            qimage_frame = QImage(frame.data, w, h, QImage.Format.Format_RGB888)
            self.qimage_frame_signal.emit(qimage_frame)
            # 控制帧率,确保每帧间隔符合设置
            elapsed = time() - start_time
            if elapsed < self.frame_interval:
                sleep(self.frame_interval - elapsed)


class EncodeFaceThread(QThread):
    def __init__(self):
        super().__init__()
        self.known_encodings = []
        # 设置队列最大长度为2,满时自动丢弃旧帧
        self.queue = Queue(maxsize=2)

    def run(self):
        while self.isRunning():
            try:
                # 添加超时,避免线程无帧时一直阻塞
                frame = self.queue.get(block=True, timeout=0.1)
                # 缩小帧尺寸到原大小的1/2,加快人脸识别速度
                small_frame = resize(frame, (0, 0), fx=0.5, fy=0.5)
                f_locations = face_locations(small_frame)
                if len(f_locations) != 1:
                    continue
                # 生成人脸编码
                f_encoding = face_encodings(small_frame, f_locations)[0]
                # 匹配已知编码,未匹配则添加
                if not any(compare_faces(self.known_encodings, f_encoding)):
                    self.known_encodings.append(f_encoding)
                self.queue.task_done()
            except:
                continue


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        # UI设置
        self.setMinimumSize(660, 500)
        self.image_display = QLabel(self)
        self.image_display.setGeometry(10, 10, 640, 480)
        # 初始化线程
        self.webcam_thread = WebcamThread(fps=15)
        self.webcam_thread.ndarray_frame_signal.connect(self.push_in_queue)
        self.webcam_thread.qimage_frame_signal.connect(self.display)
        self.webcam_thread.start()
        self.encode_face_thread = EncodeFaceThread()
        self.encode_face_thread.start()

    @pyqtSlot(ndarray)
    def push_in_queue(self, frame):
        try:
            # 非阻塞放入队列,满时丢弃当前帧
            self.encode_face_thread.queue.put_nowait(frame)
        except:
            pass

    @pyqtSlot(QImage)
    def display(self, frame):
        qpixmap_frame = QPixmap.fromImage(frame)
        self.image_display.setPixmap(qpixmap_frame)


app = QApplication(argv)
window = MainWindow()
window.show()
app.exec()

关键修改说明

  • 队列限制:Queue(maxsize=2)避免无限积压,put_nowait确保摄像头线程不会因队列满而阻塞。
  • 帧率控制:通过计算帧处理耗时,动态补充睡眠时长,严格控制采集频率。
  • 帧缩小优化:将帧尺寸减半,大幅降低人脸识别的计算量,同时不影响编码准确性。
  • 线程超时处理:queue.get添加超时,避免人脸识别线程在无帧时持续阻塞,提升响应性。

内容的提问来源于stack exchange,提问作者brownfox2k6

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 20:13:20