Я столкнулся с проблемой низкой эффективности захвата кадров в OpenCV.
Аппаратное и программное обеспечение.
- 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
Задача.
Получение видеопотока с IP-камеры, распознавание изображений и отображение полученного видео (с отметками и сообщениями).
Важные функции: обработка в реальном времени, разрешение HD (1280x720), высокая частота кадров (> 20 к / с), непрерывная работа в течение нескольких часов.
- Мое решение.
Общий алгоритм: исходный видеопоток -> декодирование и захват кадров -> работа с кадрами в 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 возникают лаги и задержки.
- Как я пытался решить проблему.
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).
- Вопросы.
Как я понимаю, методы VideoCaputre / Videowritter имеют очень низкую эффективность. Может быть, это не заметно на ПК, но критично для Raspberry Pi 3.
- Возможно ли повысить производительность VideoCaputre
(Videowritter)?
- Есть ли альтернативный способ захвата кадров из
видео в OpenCV?
Заранее спасибо за ответы!
ОБНОВЛЕНИЕ 1
Мне кажется, я знаю, в чем проблема, но не знаю, как ее решить.
- Уточнение использования процессора при работе с VideoCapture и VideoCapture + Gstreamer. VideoCapture (src) + VideoWriter (gstreamer_piplene_out) - 50-60%, VideoCapture (gstreamer_pipline_in) + VideoWriter (gstreamer_piplene_out) - 40-50%.
- Цветовые форматы , с которыми работают различные части моей программы. Видеопоток H264 - YUV , OpenCV - BGR , выход слоя OMX - RGBA . OpenCV может работать только с кадрами в цветном формате BGR. Вывод слоя OMX при попытке запустить собранное видео в другом цветовом формате отображает черный экран.
- Преобразование формата цвета в трубопроводе 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».
Есть какие-нибудь идеи?