Как оптимизировать захват кадров из видеопотока в OpenCV? - PullRequest
1 голос
/ 07 июля 2019

Я столкнулся с проблемой низкой эффективности захвата кадров в OpenCV.

  1. Аппаратное и программное обеспечение.

    • Raspberry Pi 3 (четырехъядерный ARM 1,2 ГГц) с дисплеем HDMI
    • IP-камера: ЛВС подключена, RTSP, кодек H264, разрешение 1280x720, 20 к / с, 1 GOP, битрейт VBR 2500 кБ / с (параметры могут быть изменены).
    • OS Raspbian Stretch
    • Python 3,5
    • OpenCV 4.1
    • Gstreamer 1.0
  2. Задача.

Получение видеопотока с IP-камеры, распознавание изображений и отображение полученного видео (с отметками и сообщениями).

Важные функции: обработка в реальном времени, разрешение HD (1280x720), высокая частота кадров (> 20 к / с), непрерывная работа в течение нескольких часов.

  1. Мое решение.

Общий алгоритм: исходный видеопоток -> декодирование и захват кадров -> работа с кадрами в OpenCV -> сборка обработанных кадров в видеопоток -> отображение видео с помощью графического процессора Raspberry Pi

Метод вывода / отображения OpenCV - imshow - не работает даже на видео с низким разрешением. Единственная библиотека, которая позволяет использовать графический процессор Raspberry Pi для декодирования и отображения видео, - это Gstreamer.

Я скомпилировал модули Gstreamer (gstreamer1.0-plugins-bad, gstreamer1.0-omx) с поддержкой OMX и протестировал его:

gst-launch-1.0 rtspsrc location='rtsp://web_camera_ip' latency=400 ! queue ! rtph264depay ! h264parse ! omxh264dec ! glimagesink

Отлично работает, загрузка процессора составляет около 9% .

Далее я скомпилировал OpenCV с поддержкой Gstreamer, NEON, VFPV3.

Я использую следующий код для тестирования:

import cv2
import numpy as np

src='rtsp://web_camera_ip'
stream_in = cv2.VideoCapture(src)

pipeline_out = "appsrc ! videoconvert ! video/x-raw, framerate=20/1, format=RGBA ! glimagesink sync=false"
fourcc = cv2.VideoWriter_fourcc(*'H264')

stream_out = cv2.VideoWriter(pipeline_out, cv2.CAP_GSTREAMER, fourcc, 20.0, (1280,720))
while True:
    ret, frame = stream_out.read()
    if ret:
      stream_out.write(frame)
      cv2.waitKey(1)

Это также работало, но не так хорошо, как сам Gstreamer. Загрузка ЦП составляет около 50% , без stream_out.write (frame) - 35% . При частоте кадров выше 15 возникают лаги и задержки.

  1. Как я пытался решить проблему.

4,1. Используйте Gstreamer для декодирования видеопотока:

pipline_in='rtspsrc location=rtsp://web_camera_ip latency=400 ! queue ! rtph264depay ! h264parse ! omxh264dec ! videoconvert ! appsink'
stream_in = cv2.VideoCapture(pipline_in)

Это даже ухудшило ситуацию - загрузка процессора увеличилась на несколько процентов , задержка стала больше.

4,2. Я также пытался оптимизировать библиотеку, используя метод из PyImageSearch.com - многопоточность с использованием WebcamVideoStream из библиотеки imutils.

from threading import Thread
import cv2
import numpy as np
import imutils

src='rtsp://web_camera_ip'
stream_in = WebcamVideoStream(src).start()
pipeline_out = "appsrc ! videoconvert ! video/x-raw, framerate=20/1, format=RGBA ! glimagesink sync=false"
fourcc = cv2.VideoWriter_fourcc(*'H264')

stream_out = cv2.VideoWriter(pipeline_out, cv2.CAP_GSTREAMER, fourcc, 20.0, (1280,720))
while True:
    frame = stream_in.read()
    out.write(frame)
    cv2.waitKey(1)

Загрузка ЦП увеличена до 70% , качество выходного видеопотока не изменилось.

4.3 Изменение следующих параметров не помогает: whaitKey (1-50), битрейт видеопотока (1000-5000 кБ / с), GOP видеопотока (1-20).

  1. Вопросы.

Как я понимаю, методы VideoCaputre / Videowritter имеют очень низкую эффективность. Может быть, это не заметно на ПК, но критично для Raspberry Pi 3.

  • Возможно ли повысить производительность VideoCaputre (Videowritter)?
  • Есть ли альтернативный способ захвата кадров из видео в OpenCV?

Заранее спасибо за ответы!

ОБНОВЛЕНИЕ 1

Мне кажется, я знаю, в чем проблема, но не знаю, как ее решить.

  1. Уточнение использования процессора при работе с VideoCapture и VideoCapture + Gstreamer. VideoCapture (src) + VideoWriter (gstreamer_piplene_out) - 50-60%, VideoCapture (gstreamer_pipline_in) + VideoWriter (gstreamer_piplene_out) - 40-50%.
  2. Цветовые форматы , с которыми работают различные части моей программы. Видеопоток H264 - YUV , OpenCV - BGR , выход слоя OMX - RGBA . OpenCV может работать только с кадрами в цветном формате BGR. Вывод слоя OMX при попытке запустить собранное видео в другом цветовом формате отображает черный экран.
  3. Преобразование формата цвета в трубопроводе Gstremaer выполняется с использованием видеоконвертера . В некоторых случаях метод может работать автоматически (без указания параметров), также можно принудительно указать формат цвета. И я не знаю, как это работает в «чистом» VideoCapture (src).

Основная проблема в том, что видеоконвертер не поддерживает GPU - основная загрузка ЦП связана с преобразованием формата цвета!

Я проверил это предположениеиспользуя «чистый» Gstreamer, добавив видеоконвертер:

gst-launch-1.0 rtspsrc location='web_camera_ip' latency=400 ! queue ! rtph264depay ! h264parse ! omxh264dec ! videoconvert ! video/x-raw, format=BGR ! glimagesink sync=false

Черный дисплей, Загрузка процессора составляет 25% .

Проверьте эту линию:

gst-launch-1.0 rtspsrc location='web_camera_ip' latency=400 ! queue ! rtph264depay ! h264parse ! omxh264dec ! videoconvert ! video/x-raw, format=RGBA ! glimagesink sync=false

Отображается видео, загрузка процессора составляет 5% .Я также предполагаю, что omxh264dec преобразует цветовой формат YUV в RGBA с использованием графического процессора (после omxh264dec видеоконвертер не загружает процессор).

Я не знаю, как использовать графический процессор для преобразования цветового формата в VideoCapture / Gstreamer на Raspberry.

В этот поток 6by9, инженер Rapberry и специалист по графическому программированию,пишет, что «Компонент IL video_encode поддерживает OMX_COLOR_Format24bitBGR888, который, как мне кажется, напоминает карты в RGB OpenCV».

Есть какие-нибудь идеи?

1 Ответ

0 голосов
/ 09 июля 2019

Вам действительно нужно распознавать каждое изображение, которое вы сняли?Вы можете использовать первый конвейер для отображения изображения (вы можете использовать наложение видео для водяных знаков и других артефактов), но декодировать, например, каждое 6-е изображение для распознавания ЦП.В этом случае вы будете использовать только графический процессор для захвата и отображения видео без загрузки процессора и процессор для выборочного распознавания изображений

...