OpenCV-Python:如何从实时视频流中获取最新帧或跳过旧帧

j0pj023g  于 2023-10-24  发布在  Python
关注(0)|答案(2)|浏览(213)

我在Python中集成了一个IP摄像机和OpenCV,以便从实时流中逐帧完成视频处理。我将摄像机FPS配置为1秒,以便我可以在缓冲区中每秒处理1帧,但我的算法需要4秒来处理每帧,导致缓冲区中未处理帧的停滞,随着时间的推移而不断增长,导致指数延迟。为了解决这个问题,我已经创建了一个线程,在那里我调用cv2.grab()API来清理缓冲区,它在每次调用中将指针移动到最新帧。在主线程中,我调用retrieve()方法,它给我第一个线程抓取的最后一帧。通过这种设计,帧停滞问题得到了解决,指数延迟被消除,但是仍然无法消除12-13秒的恒定延迟。我怀疑当cv2.retrieve()被调用时它没有得到最新的帧,但是从最新的帧的第4或第5帧。OpenCV中是否有任何API或任何其他设计模式来解决这个问题,以便我可以获得最新的帧,过程

vecaoik1

vecaoik11#

如果你不介意在速度上妥协,你可以创建一个python生成器来打开相机并返回frame。

def ReadCamera(Camera):
    while True:
        cap = cv2.VideoCapture(Camera)
        (grabbed, frame) = cap.read()
        if grabbed == True:
            yield frame

现在,当你想处理帧。

for frame in ReadCamera(Camera):
      .....

这工作得很好。除了打开和关闭相机会增加时间。

qf9go6mv

qf9go6mv2#

实现这一点的最好方法是使用线程,下面是我的代码。

"""
This module contains the Streamer class, which is responsible for streaming the video from the RTSP camera.
Capture the video from the RTSP camera and store it in the queue.

NOTE:
    You can preprocess the data before flow from here
"""

import cv2
from queue import Queue
import time
from env import RESOLUTION_X, RESOLUTION_Y,FPS
from threading import Thread

class Streamer:
    def __init__(self,rtsp):
        """
        Initialize the Streamer object, which is responsible for streaming the video from the RTSP camera.
        stream (cv2.VideoCapture): The VideoCapture object.
        rtsp (str): The RTSP url.
        Q (Queue): The queue to store the frame.
        running (bool): The flag to indicate whether the Streamer is running or not.
        Args:
            rtsp (str): The RTSP url.
        """        
        print("Creating Streamer object for",rtsp)
        self.stream = cv2.VideoCapture(rtsp)
        self.rtsp = rtsp
        #bufferless VideoCapture
        # self.stream.set(cv2.CAP_PROP_BUFFERSIZE, 1)
        # self.stream.set(cv2.CAP_PROP_FPS, 10)
        self.stream.set(cv2.CAP_PROP_FRAME_WIDTH, RESOLUTION_X)
        self.stream.set(cv2.CAP_PROP_FRAME_HEIGHT, RESOLUTION_Y)
        self.Q = Queue(maxsize=2)
        self.running = True
        
        
        print("Streamer object created for",rtsp)
    
    def info(self):
        """
        Print the information of the Streamer.
        """        
        print("==============================Stream Info==============================")
        print("| Stream:",self.rtsp,"|")
        print("| Queue Size:",self.Q.qsize(),"|")
        print("| Running:",self.running,"|")
        print("======================================================================")
            
    def get_processed_frame(self):
        """
        Get the processed frame from the Streamer.

        Returns:
            dict: The dictionary containing the frame and the time.
        """        
        if self.Q.empty():
            return None
        return self.Q.queue[0]
    
    
    def release(self):
        """
        Release the Streamer.
        """        
        self.stream.release()
        
    def stop(self):
        """
        Stop the Streamer.
        """        
        print("Stopping",self.stream,"Status",self.rtsp)
        self.running = False
    
    def start(self):
        """
        Start the Streamer.
        """        
        print("Starting streamer",self.stream, "Status",self.running)
        while self.running:
            
            # FOR VIDEO CAPTURE and TESTING FRAME BY FRAME REMOVE THIS COMMENT
            # while self.Q.full():
            #     time.sleep(0.00001)
            ret, frame = self.stream.read()
            # print(frame,ret)
            if not ret:
                print("NO Frame for",self.rtsp)
                continue
            frame =cv2.resize(frame,(RESOLUTION_X,RESOLUTION_Y))
            # exit()
            if not self.Q.full():
                print("Streamer PUT",self.Q.qsize())
                self.Q.put({"frame":frame,"time":time.time()})
                print("Streamer PUT END",self.Q.qsize())
            # exit()
            # time.sleep(1/FPS)
        self.release()
        
        
if __name__ == "__main__":
    streamer = Streamer("rtsp://localhost:8554/105")
    
    thread = Thread(target=streamer.start)
    thread.start()
    
    while streamer.running:
        data = streamer.get_processed_frame()
        if data is None:
            continue
        frame = data["frame"]
        cv2.imshow("frame",frame)
        cv2.waitKey(1)

相关问题