4

I need to take snapshots of an ip camera connected to my raspberry pi 3 b+. I´m using python3 and opencv. There is a timer in the camera so I can check if the snapshot is taken in the right moment.

This script works well in my PC with Windows but does not in the raspberry. The script takes a snapshot every second, but the frame taken is not the correct, its old.

In the raspberry pi, I ran the video with VLC and omxplayer and its ran fluidly, so I think that the problem is in Opencv and my code. I have the impression that the frames are stored in a buffer, the raspberry is too slow to take all the frames from the buffer in real time, so as the time pass there is more delay between the last real frame and the frame taken.

import threading
import time
import cv2

cap = cv2.VideoCapture(‘rtsp://192.168.0.88’)
cap.set(cv2.CAP_PROP_BUFFERSIZE, 3)
counter = 0

while True:
   ret, frame = cap.read()
   if ret:
       cv2.imwrite(str(counter) + '.jpg', frame)
       counter = counter + 1
   time.sleep(1)

Anyone have an idea of how can I take only the latest frame from the camera? I want to remark that the resolution is 1920x1080 and the video format is h264. Furthermore, in the real application I need that the time between frames to be 0.1 seconds.

nathancy
  • 42,661
  • 14
  • 115
  • 137

1 Answers1

4

enter image description here

Here's a widget which saves a screenshot of the latest frame every x seconds. This idea is to create another thread just for obtaining the frames as cv2.VideoCapture.read() is a blocking operation. By putting this operation into a separate dedicated thread that focuses only on grabbing frames, we can ensure that we have the latest frame without any buffer. This will improve performance by I/O latency reduction as the main thread does not have to wait until there is a new frame. I used my own RTSP stream link and saved a screenshot every 1 second. Change it to your RTSP link and however long you want to save a screenshot

from threading import Thread
import cv2
import time

class VideoScreenshot(object):
    def __init__(self, src=0):
        # Create a VideoCapture object
        self.capture = cv2.VideoCapture(src)

        # Take screenshot every x seconds
        self.screenshot_interval = 1

        # Default resolutions of the frame are obtained (system dependent)
        self.frame_width = int(self.capture.get(3))
        self.frame_height = int(self.capture.get(4))

        # Start the thread to read frames from the video stream
        self.thread = Thread(target=self.update, args=())
        self.thread.daemon = True
        self.thread.start()

    def update(self):
        # Read the next frame from the stream in a different thread
        while True:
            if self.capture.isOpened():
                (self.status, self.frame) = self.capture.read()

    def show_frame(self):
        # Display frames in main program
        if self.status:
            cv2.imshow('frame', self.frame)

        # Press Q on keyboard to stop recording
        key = cv2.waitKey(1)
        if key == ord('q'):
            self.capture.release()
            cv2.destroyAllWindows()
            exit(1)

    def save_frame(self):
        # Save obtained frame periodically
        self.frame_count = 0
        def save_frame_thread():
            while True:
                try:
                    cv2.imwrite('frame_{}.png'.format(self.frame_count), self.frame)
                    self.frame_count += 1
                    time.sleep(self.screenshot_interval)
                except AttributeError:
                    pass
        Thread(target=save_frame_thread, args=()).start()

if __name__ == '__main__':
    rtsp_stream_link = 'your stream link!'
    video_stream_widget = VideoScreenshot(rtsp_stream_link)
    video_stream_widget.save_frame()
    while True:
        try:
            video_stream_widget.show_frame()
        except AttributeError:
            pass
nathancy
  • 42,661
  • 14
  • 115
  • 137