Project 3: Real-time object detection with YOLOv8

Frontend

The frontend is built with tkinter. It is responsible to show the user the live video feed and take screenshots which are sent to the backend for processing. It also offers a simple user interface that allows to:

  • Start Video Feed: Begins capturing and displaying live video feed from the camera.
  • Stop Video Feed: Stops the video feed and replaces the display with a black frame.
  • Start Object Detection: Enables YOLOv8-based object detection, which processes frames to identify and annotate detected objects.
  • Stop Object Detection: Disables object detection while keeping the live feed running.

import tkinter as tk
from tkinter import Label, Button, Frame
from PIL import Image, ImageTk
import backend


class LiveFeedApp:
	#initialize and build the window and buttons
	def __init__(self, root):
		self.root = root
		self.root.title("Live Camera Feed")
		self.root.geometry("640x480")
		
		self.video_handler = backend.VideoStreamHandler()

		#create a frame for the buttons
		button_frame = Frame(root)
		button_frame.pack(pady=10)

		#buttons
		self.start_button = Button(button_frame, text="Start Live Feed", command=self.start_feed, font=("Arial", 12))
		self.start_button.pack(side="left", padx=5)

		self.stop_button = Button(button_frame, text="Stop Live Feed", command=self.stop_feed, font=("Arial", 12))
		self.stop_button.pack(side="left", padx=5)

		self.detect_button = Button(button_frame, text="Start Object Detection", command=self.start_detection, font=("Arial", 12))
		self.detect_button.pack(side="left", padx=5)

		self.stop_detect_button = Button(button_frame, text="Stop Object Detection", command=self.stop_detection, font=("Arial", 12))
		self.stop_detect_button.pack(side="left", padx=5)
		
		#label for video frame
		self.video_label = Label(root)
		self.video_label.pack()
		
		self.running = False

	#start the video feed
	def start_feed(self):
		if not self.running:
			self.running = True
			self.video_handler.start_stream()
			self.update_feed()

	#update the video feed
	def update_feed(self):
		if self.running:
			frame = self.video_handler.get_frame()
			if frame is not None:
				img = Image.fromarray(frame)
			else:
				img = Image.fromarray(self.video_handler.get_black_frame())

			imgtk = ImageTk.PhotoImage(image=img)
			self.video_label.imgtk = imgtk
			self.video_label.configure(image=imgtk)
			
			self.root.after(10, self.update_feed)

	#start object detection (backend call)
	def start_detection(self):
		self.video_handler.enable_detection()

	#end object detection (backend call)
	def stop_detection(self):
		self.video_handler.disable_detection()

	#stop the video feed
	def stop_feed(self):
		if self.running:
			self.running = False
			self.video_handler.disable_detection()
			self.video_handler.stop_stream()
			
			# Set a black frame
			black_frame = self.video_handler.get_black_frame()
			black_img = Image.fromarray(black_frame)
			black_imgtk = ImageTk.PhotoImage(image=black_img)
			self.video_label.imgtk = black_imgtk
			self.video_label.configure(image=black_imgtk)

	#properly close the tool
	def close(self):
		self.running = False
		self.video_handler.stop_stream()
		self.root.destroy()

#main
if __name__ == "__main__":
	root = tk.Tk()
	app = LiveFeedApp(root)
	root.protocol("WM_DELETE_WINDOW", app.close)
	root.mainloop()