跳过帧并尝试结束OpenCV中的RTSP流

时间:2018-08-07 08:33:55

标签: python opencv video-capture rtsp

我在Raspberry Pi上的OpenCV 3.4.2中捕获并处理IP摄像机RTSP流。不幸的是,处理过程要花费很多时间,每帧大约需要0.2s,并且流很快就被延迟了。

我不介意是否跳过某些帧,因此我正在寻找一种方法来捕获和处理下一帧之前寻找流的结尾。

vcap = cv2.VideoCapture("rtsp://{IPcam}/12")

while(1):
    ret, frame = vcap.read()
    time.sleep(0.2)              # <= Simulate processing time
    cv2.imshow('VIDEO', frame)
    if cv2.waitKey(1) == 27:
        break
    vcap.seek_to_end()           # <== How to do this?

我该如何vcap.seek_to_end()来赶上流,丢弃丢失的帧,并开始处理最新的帧?

谢谢!

5 个答案:

答案 0 :(得分:4)

尝试一下:

  

vcap = cv2.VideoCapture(“ rtspsrc location = rtsp:// {IPcam} / 12!decodebin!videoconvert!appsink max-buffers = 1 drop = true”)

这使用gstreamer捕获您的相机供稿,并会保留长度为1的缓冲区,并在收到新的传入帧时丢弃最旧的缓冲区。然后,每次调用vcap.read()时,您都应该获得最新的帧。

如果您发现CPU使用率很高,也可以尝试在Raspberry Pi上使用OMX解码器,因为这会在GPU上解码视频(假设是h264):! rtph264depay ! h264parse ! omxh264dec ! appsink max-buffers=1 drop=true

您可能需要重新编译OpenCV,因为默认情况下它是使用FFMPEG支持而不是gstreamer编译的。这非常简单,只需将-D WITH_GSTREAMER=ON -D WITH_FFMPEG=OFF传递给cmake命令即可​​。确保您已安装apt install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev的gstreamer开发库。

答案 1 :(得分:2)

我将Shubham的线程实现重写为一个类,以便能够传输许多摄像机:

import threading
from threading import Lock
import cv2

class Camera:
    last_frame = None
    last_ready = None
    lock = Lock()

    def __init__(self, rtsp_link):
        capture = cv2.VideoCapture(rtsp_link)
        thread = threading.Thread(target=self.rtsp_cam_buffer, args=(capture,), name="rtsp_read_thread")
        thread.daemon = True
        thread.start()

    def rtsp_cam_buffer(self, capture):
        while True:
            with self.lock:
                self.last_ready, self.last_frame = capture.read()


    def getFrame(self):
        if (self.last_ready is not None) and (self.last_frame is not None):
            return self.last_frame.copy()
        else:
            return None

然后,它可以用作:

capture = Camera('rtsp://...')

while True:
    frame = capture.getFrame()

答案 2 :(得分:1)

我通过创建一个读取线程来解决此问题,该线程将框架放入变量中,并且应用程序使用

import threading 
from threading import Lock
import cv2


rtsp_link = "rtsp://url"
vcap = cv2.VideoCapture(rtsp_link)

latest_frame = None
last_ret = None
lo = Lock()

def rtsp_cam_buffer(vcap):
    global latest_frame, lo, last_ret
    while True:
        with lo:
            last_ret, latest_frame = vcap.read()


t1 = threading.Thread(target=rtsp_cam_buffer,args=(vcap,),name="rtsp_read_thread")
t1.daemon=True
t1.start()


while True :
    if (last_ret is not None) and (latest_frame is not None):
        img = latest_frame.copy()
    else:
        print("unable to read the frame")
        time.sleep(0.2)
        continue

这不是最好的方法,但可以解决目的。

答案 3 :(得分:1)

像这样max-buffers=1 drop=true对管道添加pipeline="rtspsrc location=rtsp://camera_ip_address latency=10 ! rtph264depay ! h264parse ! avdec_h264 ! videoconvert ! appsink max-buffers=1 drop=true"对我来说有用

答案 4 :(得分:1)

线程解决方案确实可以工作,但是对于树莓派(Raspberry pi)和opencv这样的嵌入式设备,处理器也很饿,主要用于嵌入式应用程序

我用于相同的解决方案是。

import time
FPS = *rtsp fps value*
cap = cv2.VideoCapture("RTSP URL"); 
CALIBRATION = 1.5

def skipFrames(timegap):
   global FPS,cap
   latest = None
   while True :  
      for i in range(timegap*FPS/CALIBRATION) :
        _,latest = cap.read()
        if(not _):
           time.sleep(0.5)#refreshing time
           break
      else:
        break
   return latest

gap = 0.1
while cap.isOpened(): 
   current = skipFrames(gap)
   s = time.time()
   """
   My time hungry task here , may be some object detection stuff
   """
   gap = time.time()-s

根据您的需要增加或减少CALIBRATION常量,因此您将无法在此处减轻流协议延迟,但这将有助于最小化接近协议延迟的延迟

我知道我的回答是在问题提出两年后提出的,但可能会帮助将来可能会访问此问题的人