Getting images from one thread and process them in another thread

I want to get images from one thread (with 32 Frames per second) and store them in a buffer (a list, or numpy array) then process them in another thread. Then show the final output in another thread. Altogether there should be 3 threads.

thread 1 -> Capture images taken in one second and store them in a buffer
thread 2 -> Process 32 images as a batch (A function has been written for processing one image. For the moment let's say "process_image(image)"
thread 3 -> Show processed image buffer in another thread. Frame rate should also be the same as the original

This is the code that I have written so far.

import torch
from utils import get_device, get_model, plot_square, plot_image, annotate_square_corners, show_box, show_mask, show_points
import numpy as np
from matplotlib import pyplot as plt
from fastsam import FastSAM, FastSAMPrompt
from utils import get_box_coordinates, get_image_with_box_corners
import cv2
import threading
import time

# Configuration
fast_sam_checkpoint = "weights/FastSAM-x.pt"
fast_sam_s_checkpoint = "weights/FastSAM-s.pt"

# device = get_device()
device = "cpu"

# #######################################
# model_name = input("Enter the model name you want >>> ")
model_name = "fastSAM-s"

camera_index = 1
model = get_model(model_name)

# Initialize the video capture object with the index of the webcam (usually 0)
cap = cv2.VideoCapture(camera_index)

# Buffer for storing frames
frame_buffer = []

# Flag to control thread execution
running = True

# Desired frame rate
FRAME_RATE = 32

# Set the frame rate of the capture object
cap.set(cv2.CAP_PROP_FPS, FRAME_RATE)

# Function to continuously capture frames and buffer them for one second
def capture_frames():
    global frame_buffer, running
    while running:
        start_time = time.time()  # Record the start time for each loop iteration

        ret, frame = cap.read()  # Read frame from webcam
        if not ret:
            print("Error: Couldn't read frame.")
            break
        frame_buffer.append(frame)

        # Calculate the time taken to capture the frame and sleep accordingly
        elapsed_time = time.time() - start_time
        delay = max(1.0 / FRAME_RATE - elapsed_time, 0)
        time.sleep(delay)

# Function to process frames from the buffer
def process_frames():
    global frame_buffer, running
    while running:
        if frame_buffer:
            frame = frame_buffer.pop(0)  # Get the oldest frame from the buffer
            try:
                # Processing frame
                # print(frame.shape);print(len(frame_buffer))
                box_corners_dict = get_box_coordinates(frame, model, device, False, False, False)
                print(box_corners_dict)
                # annotated_frame = get_image_with_box_corners(frame, box_corners_dict)  # in RGB

                # Showing image
                # cv2.imshow("Annotated image", annotated_frame)
                show_annotated_image(frame)

                if cv2.waitKey(1) & 0xFF == ord('q'):
                    running = False  # Stop the threads if 'q' is pressed
                    break

            except ValueError:
                pass

# Function to show annotated image
def show_annotated_image(frame):
    # Dummy function to show the frame, you can replace this with your actual logic to annotate and display the frame
    cv2.imshow("Annotated image", frame)

# Start capture frames thread
capture_thread = threading.Thread(target=capture_frames)
capture_thread.daemon = True
capture_thread.start()

# Start process frames thread
process_thread = threading.Thread(target=process_frames)
process_thread.daemon = True
process_thread.start()

# Wait for threads to finish
capture_thread.join()
process_thread.join()

# Release the capture object and close the window
cap.release()
cv2.destroyAllWindows()

At the moment this only shows the first 32 frames captured in the first second at a very slow speed. How can I optimize this code for my task?

Thank you in advance for your kind assistance!

undefined identifier. MRE required.

crosspost: