6
votes

I am using cv2.VideoCapture to read the frames of an RTSP video link in a python script. The .read() function is in a while loop which runs once every second, However, I do not get the most current frame from the stream. I get older frames and in this way my lag builds up. Is there anyway that I can get the most current frame and not older frames which have piped into the VideoCapture object?

3
Look at the grab method. This should let you skip frames and then use the retrieve command on the frame you want to process and return.ditkin
@ditkin I did, it doesn't really seem to help it still gets me older frames. Thank you for the help though.user3916798
@user3916798 did you ever solve this? Having a similar problem...Aerophilic

3 Answers

1
votes

I also faced the same problem. Seems that once the VideoCapture object is initialized it keeps storing the frames in some buffer of sort and returns a frame from that for every read operation. What I did is I initialized the VideoCapture object every time I wanted to read a frame and then released the stream. Following code captures 10 images at an interval of 10 seconds and stores them. Same can be done using while(True) in a loop.

for x in range(0,10):
    cap = cv2.VideoCapture(0)
    ret, frame = cap.read()
    cv2.imwrite('test'+str(x)+'.png',frame)
    cap.release()
    time.sleep(10)
1
votes

I've encountered the same problem and found a git repository of Azure samples for their computer vision service. The relevant part is the Camera Capture module, specifically the Video Stream class.

You can see they've implemented a Queue that is being updated to keep only the latest frame:

def update(self):
    try:
        while True:
            if self.stopped:
                return

            if not self.Q.full():
                (grabbed, frame) = self.stream.read()

                # if the `grabbed` boolean is `False`, then we have
                # reached the end of the video file
                if not grabbed:
                    self.stop()
                    return

                self.Q.put(frame)

                # Clean the queue to keep only the latest frame
                while self.Q.qsize() > 1:
                    self.Q.get()
0
votes

I'm working with a friend in a hack doing the same. We don't want to use all the frames. So far we found that very same thing: grab() (or read) tries to get you all the frames, and I guess with rtp: it will maintain a buffer and drop if you're not responsive enough.

Instead of read you can also use grab() and receive(). First one ask for the frame. Receives reads it into memory. So if you call grab several times it will effectively skip those.

We got away with doing this:

#show some initial image
while True:
    cv2.grab()
    if cv2.waitKey(10):
       im = cv2.receive()
       # process
       cv2.imshow...

Not production code but...