I’m using OpenCV 4.4 in Python 3.6.9.
Problem:
I have written a program that will take frames from 3 cameras and save to disk. The program alternates between each camera in a round robin fashion on an interval of X seconds. So every X seconds, a new image is saved to disk taken from camera (Y + 1) % 3.
This seems fine for at least 1 hour. If I use imshow, I can see that the latest frame saved is about 3-4s behind real time which is fine. However after leaving this program running over the weekend, I see that the latest images saved are old frames from 2 days ago just 4-5 hours after I started the program. I run an image diff (pixel by pixel) on the latest images and images saved 2 days ago and they appear to be the exact same frame. Given the the number of frames saved to disk over 3 days, its hard to tell when exactly this issue arises.
Code:
I use gstreamer with 3 cameras and connect to each camera by initializing 3 VideoCapture objects:
gst_str = f"""nvarguscamerasrc sensor_id={file_cap_id} !
video/x-raw(memory:NVMM), width={self.frame_width}, height={self.frame_height},
format=(string)NV12, framerate=30/1 ! nvvidconv flip-method={flip_method} !
video/x-raw, width={self.frame_width}, height={self.frame_height},
format=(string)BGRx ! videoconvert ! video/x-raw, format=(string)BGR
! appsink"""
cap = cv2.VideoCapture(gst_str, cv2.CAP_GSTREAMER)
# ... some code later
self.cameras.append(cap)
I startup a separate thread to always get the latest frames from each camera’s buffer. I do this because frames saved to disk should be on an interval of X seconds and we need these frames to be the latest:
def read_frames(self):
''' Function to read frames forever '''
while True:
num_cameras = len(self.cameras)
with self.frame_lock:
for i in range(num_cameras):
curr_cap = self.cameras[i]
ret, image = curr_cap.read()
self.frames[i] = copy.deepcopy(image)
# Show frame if enabled.
if self.args['show_frame']:
self._show_frame(self.frames[0])
# Wait key to keep real-time.
key = cv2.waitKey(1)
And I process these frames in the main thread:
def process_frames(self):
frame_idx = -1
while True:
frame_idx = (frame_idx + 1) % len(self.cameras)
with self.frame_lock:
orig_image = copy.deepcopy(self.frames[frame_idx])
if orig_image is None or len(orig_image) is 0:
continue
self.save_frame(frame_idx, orig_image)
Eg.:
def run(self):
''' Main run function '''
self._thread = Thread(target=self.read_frames)
self._thread.start()
self.process_frames()
I suspect this might have to do with trying to use 3 cameras. Best I can think up of what is happening is there is some kind of frame “drift” and the camera buffer gets too large?
Edit: I’ll update this post when I can test 1 camera. Testing for this takes awhile given the nature of the problem.