I wrote a code to make a KIOSK video booth, the video playback is faster than real time. For example, if I record a 10 second video, it will only have <1 second of video playback. What is wrong with my code?
Specification: Raspberry pi 4, camera module 3 (IMX708), HDMI output to LCD
import os
import cv2
import tkinter as tk
from tkinter import messagebox
from picamera2 import Picamera2
import time
from PIL import Image, ImageTk
class KioskApp:
def __init__(self, root):
self.root = root
self.root.title("Kiosk Camera Application")
self.root.geometry("800x600") # Set the window size
self.root.configure(bg='black')
self.picam2 = Picamera2()
self.picam2.configure(self.picam2.create_preview_configuration(main={"size": (640, 480)}))
self.picam2.start()
self.canvas = tk.Canvas(root, width=640, height=480)
self.canvas.pack(pady=20)
self.take_photo_button = tk.Button(root, text="Take Photo", command=self.take_photo)
self.take_photo_button.pack(pady=10)
self.start_record_button = tk.Button(root, text="Start Recording", command=self.start_recording)
self.start_record_button.pack(pady=10)
self.stop_record_button = tk.Button(root, text="Stop Recording", command=self.stop_recording, state=tk.DISABLED)
self.stop_record_button.pack(pady=10)
self.quit_button = tk.Button(root, text="Quit", command=self.quit_app)
self.quit_button.pack(pady=10)
self.video_writer = None
self.is_recording = False
self.output_video_file = None
self.frame_rate = 25 # Target frame rate (adjust as needed)
self.last_frame_time = time.time() # To keep track of frame timing
self.update_frame()
def get_next_filename(self, base_name, ext):
index = 1
while True:
filename = f"{base_name}_{index}.{ext}"
if not os.path.exists(filename):
return filename
index += 1
def update_frame(self):
frame = self.picam2.capture_array()
# Convert frame from RGB to BGR
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
# Convert frame to RGB for display
img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
img = cv2.resize(img, (640, 480))
self.photo = ImageTk.PhotoImage(image=self.array_to_image(img))
self.canvas.create_image(0, 0, image=self.photo, anchor=tk.NW)
# Record video if in recording mode
if self.is_recording:
current_time = time.time()
elapsed_time = current_time - self.last_frame_time
if elapsed_time >= 1 / self.frame_rate: # Maintain target frame rate
self.video_writer.write(cv2.resize(frame, (1920, 1080))) # Save video at 1080p
self.last_frame_time = current_time
self.root.after(10, self.update_frame) # 10ms delay for responsive UI
def array_to_image(self, img_array):
img = Image.fromarray(img_array)
return img
def start_recording(self):
if not self.is_recording:
video_filename = self.get_next_filename("video", "avi")
fourcc = cv2.VideoWriter_fourcc(*'XVID') # Codec for video writing
self.video_writer = cv2.VideoWriter(video_filename, fourcc, self.frame_rate, (1920, 1080)) # Set frame rate to 25 fps
self.is_recording = True
self.start_record_button.config(state=tk.DISABLED)
self.stop_record_button.config(state=tk.NORMAL)
# Store output file names
self.output_video_file = video_filename
self.last_frame_time = time.time() # Reset frame timer
def stop_recording(self):
if self.is_recording:
self.video_writer.release()
self.is_recording = False
self.start_record_button.config(state=tk.NORMAL)
self.stop_record_button.config(state=tk.DISABLED)
messagebox.showinfo("Recording Stopped", "Video has been saved.")
def take_photo(self):
frame = self.picam2.capture_array()
# Convert frame from RGB to BGR
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
filename = self.get_next_filename("photo", "jpg")
cv2.imwrite(filename, frame)
messagebox.showinfo("Photo Saved", f"Photo saved as {filename}")
def quit_app(self):
self.picam2.stop()
if self.is_recording:
self.video_writer.release() # Release video writer if recording
self.root.quit()
if __name__ == "__main__":
root = tk.Tk()
app = KioskApp(root)
root.attributes('-fullscreen', True) # Fullscreen mode
root.mainloop()