我在Raspberry Pi上的OpenCV 3.4.2中捕获并处理IP摄像机RTSP流。不幸的是,处理需要花费很多时间,每帧大约0.2秒,并且流很快就会延迟。
我不介意我是否跳过一些帧,所以我正在寻找一种方法来寻找到流的末尾,然后再捕获并处理下一帧。
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()
赶上流,丢弃丢失的帧,并开始处理最新的帧?
谢谢!
试试这个:
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
命令即可。确保你安装了gstreamer开发库apt install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev
。
我将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()
我通过创建一个读取线程来管理它,它将框架放在一个变量中并且应用程序使用它
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
它不是最好的方法,但它解决了目的。