我正在尝试开发具有面部识别功能的Pyqt应用程序。对于人脸识别,我使用python软件包face_recognition。为了使UI保持响应,我确实将具有面部识别功能的工作人员移动到了另一个QThread。但是,UI仍然非常呆滞和落后。为了检查是否在实现多线程过程中出错,我确实用一个长的活动等待循环替换了面部识别部分,如下所示:
原始人脸识别代码:
face_recognition.face_locations(frame, model="hog")
已替换为活动的等待循环:
for x in range(59999999):
pass
但是,在这种情况下,用户界面反应非常快。因此相关部分确实在另一个线程上。但是,当我将其替换为面部识别时,为什么UI线程会滞后?
[我也曾尝试将UI线程的优先级设置为QThread.TimeCriticalPriority
(最高),将工作线程的优先级设置为QThread.IdlePriority
(最低),但这实际上没有效果。
这里是一个最小的示例,在这里我也可以观察到这种行为。虽然滞后不如我的实际应用程序那么大,但在调整窗口大小时仍然很明显。但是,我必须将特定的QWidget(例如ScrollArea或LineEdit)添加到UI。否则(例如仅显示标签)调整大小是平滑的。
#!/usr/bin/env python3
import sys, cv2, face_recognition
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog
from PyQt5.QtCore import QThread, QObject, pyqtSlot
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setup_test_ui()
self.open_file()
# QThread.currentThread().setPriority(QThread.TimeCriticalPriority)
def setup_test_ui(self):
self.centralwidget = QtWidgets.QWidget(self)
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.centralwidget)
self.scrollArea = QtWidgets.QScrollArea(self.centralwidget)
self.scrollArea.setWidgetResizable(True)
self.lineEdit = QtWidgets.QLineEdit(self.scrollArea)
self.scrollArea.setWidget(self.lineEdit)
self.verticalLayout_2.addWidget(self.scrollArea)
self.setCentralWidget(self.centralwidget)
def open_file(self):
file_name, _ = QFileDialog.getOpenFileName(self, "Open video", "", "All Files (*);;Movie Files (*.mp4 *.avi)")
if (file_name):
self.setup_worker(file_name)
def setup_worker(self, *args, **kwargs):
worker = Worker(*args, **kwargs)
thread = QThread()
self.worker = (worker, thread)
worker.moveToThread(thread)
thread.started.connect(worker.work)
thread.start()
# thread.start(QThread.IdlePriority)
class Worker(QObject):
def __init__(self, video_source=0, *args, **kwargs):
super().__init__(*args, **kwargs)
self.vid = cv2.VideoCapture(video_source)
if not self.vid.isOpened():
raise ValueError("Unable to open video source", video_source)
@pyqtSlot()
def work(self):
while (True):
ret, frame = self.vid.read()
if ret:
# for x in range(59999999):
# pass
face_locations = face_recognition.face_locations(frame, model="hog")
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
注意:确保安装所有依赖项:OpenCV,PyQt5,人脸识别。对于最后一个,您可能必须提前编译dlib(遵循these instructions)。然后启动应用程序,使用任何视频文件作为face_recognition的输入并调整窗口大小(这对我来说有点滞后)。然后,您可以编辑work
方法,并使用活动的等待循环代替face_recognition行。现在执行应用程序时,调整大小非常敏感。
因此,在尝试了一些东西之后,看来问题确实出在Pythons GIL上。使用单独的进程而不是线程,程序可以按预期工作,并且UI保持响应。