【发布时间】:2019-11-17 08:49:52
【问题描述】:
我在OpenCV中遇到了抓帧效率低的问题。
-
硬件和软件。
- 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
任务。
从 IP 摄像头获取视频流,识别图像并显示生成的视频(带有标记和消息)。
重要特性:实时处理、高清分辨率 (1280x720)、高帧率 (>20 fps)、连续运行数小时。
- 我的解决方案。
通用算法:源视频流 -> 解码和帧抓取 -> 在 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 时,会出现滞后和延迟。
- 我是如何尝试解决问题的。
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)。
- 问题。
据我了解,VideoCaputre/Videowritter 方法的效率非常低。可能在 PC 上不明显,但对树莓派 3 来说很关键。
- 是否可以提高 VideoCaputre 的性能 (视频作者)?
- 是否有其他方法可以从 视频到 OpenCV?
提前感谢您的回答!
更新 1
我想我知道问题出在哪里,但我不知道如何解决。
- 在使用 VideoCapture 和 VideoCapture+Gstreamer 时优化 CPU 使用率。 VideoCapture(src)+VideoWriter(gstreamer_pipline_out) - 50-60%,VideoCapture(gstreamer_pipline_in) +VideoWriter(gstreamer_pipline_out) - 40-50%。
- Сolor 格式,我的程序的不同部分可以使用。 H264 视频流 - YUV,OpenCV - BGR,OMX 层输出 - RGBA。 OpenCV 只能处理 BGR 颜色格式的帧。尝试以不同颜色格式启动收集的视频时,OMX 层输出显示黑屏。
- 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)。
- 不知道如何在 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