【问题标题】:How to optimize frame grabbing from video stream in OpenCV?如何优化 OpenCV 中视频流的帧抓取?
【发布时间】:2019-11-17 08:49:52
【问题描述】:

我在OpenCV中遇到了抓帧效率低的问题。

  1. 硬件和软件。

    • Raspberry Pi 3(1.2 GHz 四核 ARM),带 HDMI 显示器
    • 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 Сhanging 以下参数无济于事:whaitKey(1-50)、视频流比特率 (1000-5000 kB/s)、视频流 GOP (1-20)。

  1. 问题。

据我了解,VideoCaputre/Videowritter 方法的效率非常低。可能在 PC 上不明显,但对树莓派 3 来说很关键。

  • 是否可以提高 VideoCaputre 的性能 (视频作者)?
  • 是否有其他方法可以从 视频到 OpenCV?

提前感谢您的回答!

更新 1

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

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

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

我使用“纯”Gstreamer 测试了这个假设,添加了 videoconvert:

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 进行颜色格式转换。

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

有什么想法吗?

【问题讨论】:

  • 你应该知道你在哪个内存空间工作。您的第一个管道是最有效的:您在显卡上解码视频并告诉显卡显示它。如果要在解码和显示之间做 CPU 处理,则需要将图像数据下载到 CPU 主机内存中,进行处理后上传回显卡内存。这很昂贵,尤其是对于像 Pi 这样的嵌入式设备。理想情况下,您可以直接在 GPU 上对 OpenGL 纹理进行处理,避免复制图像数据。

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


【解决方案1】:

您真的需要识别您拍摄的每张图像吗?您可以将第一个管道用于显示图像(您可以将视频叠加用于水印和其他伪影),但例如每 6 个图像解码一次以进行 CPU 识别。 在这种情况下,您将仅使用 GPU 来捕获和显示视频,而无需加载 CPU,而 CPU 则用于选择性地进行图像识别

【讨论】:

  • 感谢您的回答!我正在寻找一种使用 GPU 在 Gstreamer 中转换颜色格式的方法。如果我找不到解决方案,我将使用您提出的方法。分离流以进行识别和输出的主要缺点是无法标记已识别的对象。
猜你喜欢
  • 2013-03-18
  • 1970-01-01
  • 2015-08-28
  • 1970-01-01
  • 1970-01-01
  • 2016-07-15
  • 1970-01-01
  • 1970-01-01
  • 2018-03-09
相关资源
最近更新 更多