Python 使用Qt Gui在实时视频提要上进行Opencv人脸检测

Python 使用Qt Gui在实时视频提要上进行Opencv人脸检测,python,qt,opencv,face-detection,Python,Qt,Opencv,Face Detection,我有一个项目,需要在qt中设计gui。此设计包含一个小部件,其中将使用opencv从usb网络摄像头显示live video feed。该项目将检测人脸,还将识别它们,这意味着在每一帧上都会进行大量处理 为此,我已经创建了一个线程来初始化相机,并使用opencv从中获取帧。然后它将所有帧放入队列中,然后通过函数update\u frame读取该队列,该函数基本上在qt小部件上显示帧。这是工作良好,没有延误 在update\u frame函数中,我添加了人脸检测,因此执行速度非常慢。因此,我创建了

我有一个项目,需要在
qt
中设计
gui
。此设计包含一个小部件,其中将使用
opencv
从usb网络摄像头显示
live video feed
。该项目将检测
人脸
,还将识别它们,这意味着在每一帧上都会进行大量处理

为此,我已经创建了一个线程来初始化相机,并使用opencv从中获取帧。然后它将所有帧放入队列中,然后通过函数
update\u frame
读取该队列,该函数基本上在qt小部件上显示帧。这是工作良好,没有延误

update\u frame
函数中,我添加了
人脸检测
,因此执行速度非常慢。因此,我创建了另一个线程
start\u推断
,它基本上从
队列
读取帧,在检测到人脸后,它将帧再次放入另一个队列
q2
,然后由
更新帧
读取并显示,但其响应仍然非常缓慢。代码如下:

q = queue.Queue()
q2 = queue.Queue()

def grab(cam, qu, width, height):
    global running
    capture = cv2.VideoCapture(cam)
    capture.set(cv2.CAP_PROP_FRAME_WIDTH, width)
    capture.set(cv2.CAP_PROP_FRAME_HEIGHT, height)

    while running:
        frame = {}
        capture.grab()
        ret_val, img = capture.retrieve(0)
        frame["img"] = img

        if qu.qsize() < 100:
            qu.put(frame)
        else:
            print(qu.qsize())

class Logic(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        QtWidgets.QMainWindow.__init__(self, parent)
        self.setupUi(self)

        set_initial_alert_temp()

        self.window_width = self.ImgWidget.frameSize().width()
        self.window_height = self.ImgWidget.frameSize().height()
        self.ImgWidget = OwnImageWidget(self.ImgWidget)

        self.timer = QtCore.QTimer(self)
        self.timer.timeout.connect(self.update_frame)
        self.timer.start(1)

        self.outside_temp_text_box.setText(str(curr_temp_cel))

    def update_frame(self):
        if not q2.empty():
            frame1 = q2.get()
            img = frame1["img"]

            img_height, img_width, img_colors = img.shape
            scale_w = float(self.window_width) / float(img_width)
            scale_h = float(self.window_height) / float(img_height)
            scale = min([scale_w, scale_h])

            if scale == 0:
                scale = 1

            img = cv2.resize(img, None, fx=scale, fy=scale, interpolation=cv2.INTER_CUBIC)
            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
            height, width, bpc = img.shape
            bpl = bpc * width
            image = QtGui.QImage(img.data, width, height, bpl, QtGui.QImage.Format_RGB888)
            self.ImgWidget.setImage(image)

def start_inferencing():
    while True:
        if not q.empty():
            frame = q.get()
            img = frame["img"]
            face_bbox = face.detect_face(img)
            if face_bbox is not None:
                (f_startX, f_startY, f_endX, f_endY) = face_bbox.astype("int")
                f_startX = f_startX + 10
                f_startY = f_startY + 10
                f_endX = f_endX - 10
                f_endY = f_endY - 10
                cv2.rectangle(img, (f_startX, f_startY), (f_endX, f_endY), (0, 255, 0), 2)

                frame1 = {"img": img}

                if q2.qsize() < 100:
                    q2.put(frame1)
                else:
                    print(q2.qsize())

def main():

    capture_thread = threading.Thread(target=grab, args=(0, q, 640, 480))
    capture_thread.start()

    infer_thread = threading.Thread(target=start_inferencing)
    infer_thread.start()

    app = QtWidgets.QApplication(sys.argv)
    w = Logic(None)
    w.setWindowTitle('Test')
    w.show()
    app.exec_()


main()
camera -> frame -> queue.put                     # (reading frame from camera and putting it in queue)
queue.get -> frame -> detect face -> queue2.put  # (getting frame from queue, detecting face in it and putting the updated frames in queue2)
queue2.get -> frame -> display it on qt widget   # (getting frame from queue2 and display it on qt widget)

直播视频馈送速度慢的主要原因是,在
抓取
功能中读取的帧无法更快地处理,因此
队列
大小不断增加,因此总体速度变得非常慢。有没有什么好的方法我可以使用,可以检测到的脸,以及显示它没有任何延误。请帮忙。感谢

队列累加线程无法处理的帧。因此,根本没有机会处理它们。这就是为什么这里的队列毫无用处。这里的工作时钟由到达的帧定义,每个帧生成事件,在帧处理完成后,它可能在自己的线程中工作(比如在处理线程中),处理线程生成另一个事件并在另一个线程中处理,比如在GUI线程中处理,并将结果显示给用户


如果您强制需要一些缓冲区,请选中环形缓冲区,因为它具有有限的长度。

队列会累积线程无法处理的帧。因此,根本没有机会处理它们。这就是为什么这里的队列毫无用处。这里的工作时钟由到达的帧定义,每个帧生成事件,在帧处理完成后,它可能在自己的线程中工作(比如在处理线程中),处理线程生成另一个事件并在另一个线程中处理,比如在GUI线程中处理,并将结果显示给用户


如果您强制需要一些缓冲区,请检查环形缓冲区是否有有限长度。

您有生产者/消费者序列

  • 抓住框架并推到队列1上
  • 队列1中的出队列帧,队列2上的进程和入队列结果
  • 从queue2中取出结果并显示

  • 从你所说的第二阶段开始。这是瓶颈。在这种情况下,您可以尝试将更多资源(即线程)分配给该阶段so 2。有多个线程从队列1读取、处理结果并将结果推送到队列2。您只需要确保从queue2弹出的已处理数据的顺序正确——可能是通过为每个初始帧分配序列号或id来实现的。

    您有一个生产者/消费者序列

  • 抓住框架并推到队列1上
  • 队列1中的出队列帧,队列2上的进程和入队列结果
  • 从queue2中取出结果并显示

  • 从你所说的第二阶段开始。这是瓶颈。在这种情况下,您可以尝试将更多资源(即线程)分配给该阶段so 2。有多个线程从队列1读取、处理结果并将结果推送到队列2。您只需确保从queue2弹出的已处理数据的顺序正确——大概是通过为每个初始帧分配一个序列号或id。

    可能是使用事件(例如“onFrame”、“onFaceDetected”等)?@Andreysorodov您可以添加更多描述您的基本设计出现在生产者/消费者系列中吗(或者可能应该这样对待)。那么,为什么您要从“毫秒计时器”触发
    Logic::update_frame
    ,而不是简单地阻塞直到相关队列有数据?可能是使用事件(例如“onFrame”、“onFaceDetected”等)?@Andreysorodov您能否添加更多描述您的基本设计出现在生产商/消费者系列中(或者可能应该这样对待)。那么,为什么您要从“毫秒计时器”触发
    Logic::update_frame
    ,而不是简单地阻塞,直到相关队列有数据?您能给我一个示例,说明您在回答中提到的id为的队列或出队。此外,我认为您在评论中提到的内容值得一试,因为没有使用运行update fra我会每毫秒更新一次。我会尝试并更新,但你认为这个管道是有效的并且可以提供良好的结果吗?你可以给我一个例子,说明你在回答中提到的id为的队列或出列。另外,我认为你在评论中提到的值得尝试,因为没有必要每毫秒运行更新框架。我会尝试并更新,但你认为这个管道是好的并且可以提供好的结果吗谢谢,我不擅长环形缓冲区或任何缓冲区,所以现在将坚持队列,但一定会在未来尝试,我不擅长环形缓冲区或任何缓冲区,所以现在将坚持队列,但一定会在未来尝试