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

Python 如何在OpenCV中优化视频流的帧抓取?,python,opencv,raspberry-pi3,gstreamer,video-capture,Python,Opencv,Raspberry Pi3,Gstreamer,Video Capture,我在OpenCV中遇到了帧捕获效率低的问题 硬件和软件 Raspberry Pi 3(1.2 GHz四核ARM),带HDMI显示器 IP摄像机:局域网连接,RTSP,H264编解码器,1280x720分辨率,20 fps,1 GOP,2500 kB/s VBR比特率(参数可以更改) 拉斯比拉伸 Python 3.5 OpenCV 4.1 Gstreamer 1.0 任务 从IP摄像头获取视频流,识别图像并显示生成的视频(带有标记和消息)。 重要特点:实时处理,高清分辨率(1280x720),

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

  • 硬件和软件

    • Raspberry Pi 3(1.2 GHz四核ARM),带HDMI显示器
    • IP摄像机:局域网连接,RTSP,H264编解码器,1280x720分辨率,20 fps,1 GOP,2500 kB/s VBR比特率(参数可以更改)
    • 拉斯比拉伸
    • Python 3.5
    • OpenCV 4.1
    • Gstreamer 1.0
  • 任务

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

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

  • 我的解决方案
  • 通用算法:源视频流->解码和帧抓取->在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%无数据流输出。写入(帧)-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优化库-使用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)

  • 问题
  • 据我所知,VideoCaputre/VideoWriter方法的效率非常低。也许这在个人电脑上并不明显,但它对覆盆子皮3至关重要

    • 是否有可能提高VideoCaputre的性能 (录像机)
    • 是否有其他方法可以从中捕获帧 视频到OpenCV
    提前感谢您的回答

    更新1

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

  • 在使用VideoCapture和VideoCapture+Gstreamer时,对CPU使用情况进行优化。视频捕获(src)+视频编写器(gstreamer\u piplene\u out)-50-60%,视频捕获(gstreamer\u pipline\u in)+视频编写器(gstreamer\u piplene\u out)-40-50%
  • 我的程序的不同部分使用的Сcolor格式。H264视频流-YUV,OpenCV-BGR,OMX层输出-RGBA。OpenCV只能处理BGR颜色格式的帧。OMX层输出尝试以不同的颜色格式启动采集的视频时,会显示一个黑屏
  • Gstremaer管线中的С颜色格式转换使用视频转换进行。在某些情况下,该方法可以自动工作(无需指定参数),也可以强制指定颜色格式。我不知道它在“纯”视频捕获(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进行颜色格式转换
  • Rapberry工程师和图形编程专家在thread 6by9中写道,“IL视频编码组件支持OMX颜色格式24BitBGR888,我似乎能回忆起OpenCV的RGB映射”


    有什么想法吗?

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

    您应该知道您正在使用哪些内存空间。您的第一条管道是最有效的:您解码图形卡上的视频,并告诉图形卡显示它。如果要在解码和显示之间执行CPU处理,则需要将图像数据下载到CPU主机内存,执行处理并将其上载回图形卡内存。这是昂贵的,尤其是对于像Pi这样的嵌入式设备。理想情况下,您可以直接在GPU上对OpenGL纹理进行处理,避免复制周围的图像数据。谢谢您的回答!我正在寻找一种使用GPU在Gstreamer中转换颜色格式的方法。如果我找不到解决办法,我就用你提出的方法。分离流进行识别和输出的主要缺点是无法标记已识别的对象。