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

lic*_*.mk 5 python opencv video-capture gstreamer raspberry-pi3

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

\n\n
    \n
  1. 硬件软件。

    \n\n
      \n
    • 带 HDMI 显示屏的 Raspberry Pi 3(1.2 GHz 四核 ARM)
    • \n
    • 网络摄像机:LAN 连接、RTSP、H264 编解码器、1280x720 分辨率、20 fps、1 GOP、2500 kB/s VBR 比特率(参数可更改)。
    • \n
    • 操作系统 Raspbian Stretch
    • \n
    • Python 3.5
    • \n
    • OpenCV 4.1
    • \n
    • 流媒体1.0
    • \n
  2. \n
  3. 任务。

  4. \n
\n\n

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

\n\n

重要特点:实时处理、高清分辨率(1280x720)、高帧率(>20 fps)、连续运行数小时。

\n\n
    \n
  1. 我的解决方案。
  2. \n
\n\n

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

\n\n

OpenCV 输出/显示方法 - imshow - 即使在低分辨率视频下也不能很好地工作。唯一允许使用 Raspberry Pi GPU 解码和显示视频的库是 Gstreamer。

\n\n

我编译了具有 OMX 支持的 Gstreamer 模块(gstreamer1.0-plugins-bad、gstreamer1.0-omx)并对其进行了测试:

\n\n
gst-launch-1.0 rtspsrc location=\'rtsp://web_camera_ip\' latency=400 ! queue ! rtph264depay ! h264parse ! omxh264dec ! glimagesink\n
Run Code Online (Sandbox Code Playgroud)\n\n

运行良好,CPU 使用率约为 9%

\n\n

接下来我编译了支持 Gstreamer、NEON、VFPV3 的 OpenCV。

\n\n

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

\n\n
import cv2\nimport numpy as np\n\nsrc=\'rtsp://web_camera_ip\'\nstream_in = cv2.VideoCapture(src)\n\npipeline_out = "appsrc ! videoconvert ! video/x-raw, framerate=20/1, format=RGBA ! glimagesink sync=false"\nfourcc = cv2.VideoWriter_fourcc(*\'H264\')\n\nstream_out = cv2.VideoWriter(pipeline_out, cv2.CAP_GSTREAMER, fourcc, 20.0, (1280,720))\nwhile True:\n    ret, frame = stream_out.read()\n    if ret:\n      stream_out.write(frame)\n      cv2.waitKey(1)\n
Run Code Online (Sandbox Code Playgroud)\n\n

它也能工作,但不如 Gstreamer 本身那么好。CPU使用率约为50%没有stream_out.write(frame) - 35%帧速率高于 15时,会出现滞后和延迟。

\n\n
    \n
  1. 我如何尝试解决这个问题。
  2. \n
\n\n

4.1. 使用Gstreamer解码视频流:

\n\n
pipline_in=\'rtspsrc location=rtsp://web_camera_ip latency=400 ! queue ! rtph264depay ! h264parse ! omxh264dec ! videoconvert ! appsink\'\nstream_in = cv2.VideoCapture(pipline_in)\n
Run Code Online (Sandbox Code Playgroud)\n\n

甚至使情况变得更糟——CPU负载增加了几个百分点,延迟也变得更多。

\n\n

4.2. 我还尝试使用PyImageSearch.com 中的方法来优化该库- 使用 imutils 库中的 WebcamVideoStream 进行线程化。

\n\n
from threading import Thread\nimport cv2\nimport numpy as np\nimport imutils\n\nsrc=\'rtsp://web_camera_ip\'\nstream_in = WebcamVideoStream(src).start()\npipeline_out = "appsrc ! videoconvert ! video/x-raw, framerate=20/1, format=RGBA ! glimagesink sync=false"\nfourcc = cv2.VideoWriter_fourcc(*\'H264\')\n\nstream_out = cv2.VideoWriter(pipeline_out, cv2.CAP_GSTREAMER, fourcc, 20.0, (1280,720))\nwhile True:\n    frame = stream_in.read()\n    out.write(frame)\n    cv2.waitKey(1)\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

4.3 \xd0\xa1挂起以下参数没有帮助:whitKey(1-50)、视频流比特率(1000-5000 kB/s)、视频流GOP (1-20)。

\n\n
    \n
  1. 问题。
  2. \n
\n\n

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

\n\n
    \n
  • 是否可以提高 VideoCaputre\n(Videowriter) 的性能?
  • \n
  • 是否有其他方法可以从视频捕获帧到 OpenCV?
  • \n
\n\n

预先感谢您的答复!

\n\n

更新1

\n\n

我想我知道问题是什么,但我不知道如何解决。

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

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

\n\n

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

\n\n
gst-launch-1.0 rtspsrc location=\'web_camera_ip\' latency=400 ! queue ! rtph264depay ! h264parse ! omxh264dec ! videoconvert ! video/x-raw, format=BGR ! glimagesink sync=false\n
Run Code Online (Sandbox Code Playgroud)\n\n

黑屏显示,CPU负载为25%

\n\n

检查这个管道:

\n\n
gst-launch-1.0 rtspsrc location=\'web_camera_ip\' latency=400 ! queue ! rtph264depay ! h264parse ! omxh264dec ! videoconvert ! video/x-raw, format=RGBA ! glimagesink sync=false\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

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

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

\n\n

有什么想法吗?

\n

小智 1

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