Распознавание лиц Opencv в прямом эфире видео с использованием Qt Gui, выполняющее медленно - PullRequest
0 голосов
/ 30 марта 2020

У меня есть проект, в котором мне нужно создать gui в qt. Этот дизайн содержит виджет, где live video feed будет отображаться с веб-камеры USB, используя opencv. Этот проект обнаружит faces и также распознает их, что означает, что на каждом кадре будет происходить большая обработка.

Для этого я создал поток, который инициализирует камеру и принимает кадры из него с помощью opencv. Затем он помещает весь кадр в очередь, и эта очередь затем читается функцией update_frame, которая в основном отображает кадр в виджете qt. Это работает нормально без задержки.

Внутри функции update_frame я добавил face detection, из-за чего она работала очень медленно. Поэтому я создал другой поток start_inferencing, который в основном читает кадр из queue, и после обнаружения лица он снова помещает кадр в другую очередь q2, которая затем читается update_frame, и он отображает, но все еще реагирует очень медленно. Ниже приведен код:

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)

Основная причина медленной подачи живого видео состоит в том, что кадр Функция read in grab не может обрабатывать быстрее, и, таким образом, размер queue постоянно увеличивается, и поэтому он в целом становится очень медленным. Есть ли какой-нибудь хороший подход, который я могу использовать, который может обнаружить лицо, а также показать его без каких-либо задержек. Пожалуйста помоги. Спасибо

Ответы [ 2 ]

1 голос
/ 30 марта 2020

У вас есть последовательность производителей / потребителей ...

  1. захват кадра и pu sh в очереди 1
  2. удаление кадра из очереди1, обработка и постановка результатов в очередь 2
  3. вывод из очереди queue2 и отображение

Из того, что вы заявили, этап 2. является узким местом. В этом случае вы можете попытаться назначить больше ресурсов (т. Е. Потоков) для этого этапа, чтобы 2. несколько потоков считывали из очереди 1, обрабатывали и помещали результаты в очередь 2. Вам просто нужно убедиться, что обработанные данные, извлеченные из очереди 2, упорядочены правильно - предположительно, присваивая каждому начальному кадру порядковый номер или идентификатор.

1 голос
/ 30 марта 2020

Очередь накапливает кадры, которые поток не может обработать. Таким образом, нет возможности обрабатывать их вообще. Вот почему очередь здесь бесполезна. Рабочие часы здесь определяются поступающими кадрами, каждый кадр генерирует событие, которое может работать в своем собственном потоке (скажем, в потоке обработки), после того как обработка фрейма завершена, поток обработки генерирует другое событие и обрабатывается в другом потоке, скажем, в GUI поток, и он показывает результат для пользователя.

Если вам обязательно нужен некоторый буфер, проверьте, что кольцевой буфер имеет конечную длину.

...