打开CV RTSP相机缓冲滞后

2020-03-23 python opencv opencv3.0 rtsp

我正在努力理解为什么我无法从IP摄像机获得“实时”供稿。

似乎有一个缓冲区,如果不读取它们,则会导致帧堆积-由于我的代码的每次迭代都需要一些时间,因此积压下来,最终到实际发生的事情几乎很慢。

我发现以下代码触发一个线程在循环中读取相机,以尝试避免这种情况。但是现在我得到大约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

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

要么

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

谢谢

Answers

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

然后,我尝试使用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) 

显示框架可以如下进行

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()

该解决方案解决了我所有的缓冲滞后问题以及重复的帧问题。 #

希望它可以帮助处于相同情况的任何其他人。

Related