打开CV RTSP相机缓冲滞后

Lew*_*ris 2 python opencv rtsp opencv3.0

我很难理解为什么我无法从我的网络摄像机获得“实时”反馈。

似乎存在一个缓冲区,如果不被读取,它会导致帧堆积 - 由于我的代码的每次迭代都需要一些时间,因此会出现积压,最终导致实际发生的情况几乎变慢。

我发现下面的代码会触发一个线程来循环读取相机,以尝试避免这种情况。但现在我得到了大约 5 帧的“实时”提要,然后它停止并显示另外几帧的相同图像。

##camera class - this stops the RTSP feed getting caught in the buffer 

class Camera:

    def __init__(self, rtsp_link):

        #init last ready and last frame
        self.last_frame = None
        self.last_ready = None
        self.lock = Lock()

        #set capture decive
        capture = cv2.VideoCapture(rtsp_link,apiPreference=cv2.CAP_FFMPEG)

        #set thread to clear buffer
        thread = threading.Thread(target=self.rtsp_cam_buffer, args=(capture,), name="rtsp_read_thread")
        thread.daemon = True
        thread.start()

        #delay start of next step to avoid errors
        time.sleep(2)

    def rtsp_cam_buffer(self, capture):
        #loop forever 
        while True:
            with self.lock:           
                capture.grab()
                self.last_ready, self.last_frame = capture.retrieve()


    def getFrame(self):        
        #get last frame
        if (self.last_ready is not None) and (self.last_frame is not None):
            return self.last_frame.copy())
        else:
            return None
Run Code Online (Sandbox Code Playgroud)

在这种情况下正确的做法是什么?有办法解决这个问题吗?

或者

我应该使用 gstreamer 或 ffmpeg 之类的东西来获取相机输入吗?如果是的话哪个更好,为什么?有什么建议或页面可以给我一些让它工作的 python 示例吗?我找不到对我来说有意义的内容。

谢谢

Lew*_*ris 6

在在线搜索多个资源后,出现了很多使用线程从缓冲区中删除帧的建议。尽管它似乎工作了一段时间,但由于某种我无法解决的原因,它给我带来了显示重复帧的问题。

然后,我尝试从支持 gstreamer 的源代码构建 opencv,但即使正确编译后,它似乎仍然不喜欢与 gstreamer 正确连接。

最终我认为最好的选择是回到线程方法,但再次无法让它工作。所以我尝试了多处理。

我编写了下面的类来处理相机连接:

import cv2
import time
import multiprocessing as mp

class Camera():
    
    def __init__(self,rtsp_url):        
        #load pipe for data transmittion to the process
        self.parent_conn, child_conn = mp.Pipe()
        #load process
        self.p = mp.Process(target=self.update, args=(child_conn,rtsp_url))        
        #start process
        self.p.daemon = True
        self.p.start()
        
    def end(self):
        #send closure request to process
        
        self.parent_conn.send(2)
        
    def update(self,conn,rtsp_url):
        #load cam into seperate process
        
        print("Cam Loading...")
        cap = cv2.VideoCapture(rtsp_url,cv2.CAP_FFMPEG)   
        print("Cam Loaded...")
        run = True
        
        while run:
            
            #grab frames from the buffer
            cap.grab()
            
            #recieve input data
            rec_dat = conn.recv()
            
            
            if rec_dat == 1:
                #if frame requested
                ret,frame = cap.read()
                conn.send(frame)
                
            elif rec_dat ==2:
                #if close requested
                cap.release()
                run = False
                
        print("Camera Connection Closed")        
        conn.close()
    
    def get_frame(self,resize=None):
        ###used to grab frames from the cam connection process
        
        ##[resize] param : % of size reduction or increase i.e 0.65 for 35% reduction  or 1.5 for a 50% increase
             
        #send request
        self.parent_conn.send(1)
        frame = self.parent_conn.recv()
        
        #reset request 
        self.parent_conn.send(0)
        
        #resize if needed
        if resize == None:            
            return frame
        else:
            return self.rescale_frame(frame,resize)
        
    def rescale_frame(self,frame, percent=65):
        
        return cv2.resize(frame,None,fx=percent,fy=percent) 
Run Code Online (Sandbox Code Playgroud)

显示框架可以如下完成

cam = Camera("rtsp://admin:[somepassword]@192.168.0.40/h264Preview_01_main")

print(f"Camera is alive?: {cam.p.is_alive()}")

while(1):
    frame = cam.get_frame(0.65)
    
    cv2.imshow("Feed",frame)
    
    key = cv2.waitKey(1)

    if key == 13: #13 is the Enter Key
        break

cv2.destroyAllWindows()     

cam.end()
Run Code Online (Sandbox Code Playgroud)

这个解决方案解决了我所有的缓冲区延迟和重复帧问题。#

希望它能帮助处于同样情况的其他人。