如何在OpenCV中优化从视频流抓取帧?

时间:2019-07-07 17:59:05

标签: python opencv raspberry-pi3 gstreamer video-capture

我遇到了OpenCV中帧捕获效率低的问题。

  1. 硬件和软件。

    • 具有HDMI显示屏的Raspberry Pi 3(1,2 GHz四核ARM)
    • IP摄像机:已连接LAN,RTSP,H264编解码器,1280x720分辨率,20 fps,1 GOP,2500 kB / s VBR比特率(可以更改参数)。
    • OS Raspbian Stretch
    • Python 3.5
    • OpenCV 4.1
    • Gstreamer 1.0
  2. 任务。

从IP摄像机获取视频流,识别图像并显示生成的视频(带有标记和消息)。

重要功能:实时处理,高清分辨率(1280x720),高帧率(> 20 fps),连续运行几个小时。

  1. 我的解决方案。

常规算法:源视频流->解码和抓帧->在OpenCV中处理帧->将处理后的帧组合成视频流->使用Raspberry Pi GPU显示视频

OpenCV输出/显示方法- imshow -即使在低分辨率视频中也无法正常工作。唯一允许使用Raspberry Pi GPU解码和显示视频的库是Gstreamer。

我使用OMX支持编译了Gstreamer模块(gstreamer1.0-plugins-bad,gstreamer1.0-omx)并对其进行了测试:

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

效果很好, CPU使用率约为9%

接下来,我使用Gstreamer,NEON,VFPV3支持编译了OpenCV。

我使用以下代码进行测试:

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本身好。 CPU使用率约为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)

情况甚至更糟了- CPU负载增加了百分之几,延迟变得更大了。

4.2。我还尝试使用来自PyImageSearch.com的method优化库-使用来自imutils库的WebcamVideoStream进行线程化。

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)

CPU使用率已提高到70%,输出视频流的质量没有改变。

4.3挂起以下参数无济于事:whaitKey(1-50),视频流比特率(1000-5000 kB / s),视频流GOP(1-20)。

  1. 问题。

据我了解,VideoCaputre / Videowritter方法的效率非常低。也许它在PC上并不明显,但是对于Raspberry Pi 3来说至关重要。

  • 是否有可能提高VideoCaputre的性能 (录像机)?
  • 有没有其他方法可以从中捕获帧 视频到OpenCV?

提前感谢您的回答!

更新1

我想我知道问题出在哪里,但是我不知道如何解决。

  1. 有关使用VideoCapture和VideoCapture + Gstreamer时的CPU使用情况。 VideoCapture(src)+ VideoWriter(gstreamer_piplene_out)-50-60%,VideoCapture(gstreamer_pipline_in)+ VideoWriter(gstreamer_piplene_out)-40-50%。
  2. 我程序的不同部分可以使用的
  3. 颜色格式。 H264视频流- YUV ,OpenCV- BGR ,OMX图层输出- RGBA 。 OpenCV仅可用于BGR颜色格式的帧。尝试以其他颜色格式启动收集的视频时,OMX层输出会显示黑屏。
  4. 使用 videoconvert 在Gstremaer管道中进行
  5. 颜色格式转换。在某些情况下,该方法可以自动运行(无需指定参数),也可以强制指定颜色格式。而且我不知道它在“纯” VideoCapture(src)中如何工作。

主要问题是 videoconvert 不支持GPU -主CPU负载是由于颜色格式转换造成的!

我使用“纯” 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

黑屏显示, CPU负载为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

显示视频, CPU负载为5%。我还假设omxh264dec使用GPU将颜色格式YUV转换为RGBA(在omxh264dec之后,videoconver不会加载CPU)。

  1. 我不知道如何在Raspberry上的VideoCapture / Gstreamer中使用GPU进行颜色格式转换。

Rapberry工程师兼图形编程专家在this线程6by9中写道:“ IL video_encode组件支持OMX_COLOR_Format24bitBGR888,我似乎想起了映射到OpenCV RGB的映射。”

有什么想法吗?

1 个答案:

答案 0 :(得分:0)

您真的需要识别所捕获的每个图像吗?您可以将第一个管道用于显示图像(可以将视频覆盖用于水印和其他伪像),但是例如每6个图像进行解码以进行CPU识别。 在这种情况下,您将只使用GPU来捕获和显示视频,而不会占用CPU,而使用CPU来选择性地识别图像