OiO.lk English python How can I implement parallel threads with a GUI?
python

How can I implement parallel threads with a GUI?


With python, I want to run a slideshow (tkinter) and – in parallel – open a video feed. If there is a "thumbs up" gesture detected, the slideshow and the video feed should close.

My current implementation:

main.py

import threading
import time
from slideshow import start_slideshow
from detect_gesture import start_gesture_detection

running_flag = {'running': True}

slideshow = start_slideshow(image_files=matching_images, interval=interval)
print("Slideshow initialized and started")

gesture_thread = threading.Thread(target=start_gesture_detection, args=(slideshow, running_flag))
gesture_thread.start()
print("Started gesture detection thread")

slideshow.mainloop()

running_flag['running'] = False
gesture_thread.join()

slideshow.py

import tkinter as tk
from PIL import Image, ImageTk
import itertools
import os
from helpers import to_absolute_path

class Slideshow(tk.Tk):
    def __init__(self, image_folder, image_files, interval=1):
        super().__init__()
        self.image_files = itertools.cycle(image_files)
        self.interval = interval * 1000  # Convert to milliseconds
        self.running = True  # Track if slideshow is running
        self.current_after_id = None

        self.title("Slideshow")
        self.geometry("800x600")
        self.configure(background='black')

        self.load_next_image(image_folder)

    def load_next_image(self, image_folder):
        if not self.running:
            return

        # Get next image file
        image_file = next(self.image_files)
        image_path = os.path.join(image_folder, image_file)

        image = Image.open(image_path)
        image.thumbnail((800, 600))
        self.photo = ImageTk.PhotoImage(image)

        if hasattr(self, "image_label"):
            self.image_label.config(image=self.photo)
        else:
            self.image_label = tk.Label(self, image=self.photo)
            self.image_label.pack(expand=True, fill=tk.BOTH)

        self.current_after_id = self.after(self.interval, lambda: self.load_next_image(image_folder))

    def stop(self):
        self.running = False
        if self.current_after_id:
            self.after_cancel(self.current_after_id)
        self.destroy()

def start_slideshow(image_files, interval=3):
    image_folder = to_absolute_path("../data/images")
    slideshow = Slideshow(image_folder, image_files, interval)
    return slideshow

detect_gesture.py

import cv2
import mediapipe as mp

# MediaPipe hands setup
mp_hands = mp.solutions.hands
mp_drawing = mp.solutions.drawing_utils
hands = mp_hands.Hands(static_image_mode=False, max_num_hands=1, min_detection_confidence=0.7, min_tracking_confidence=0.5)

def is_thumbs_up(landmarks):
    thumb_tip = landmarks[4]
    index_tip = landmarks[8]
    middle_tip = landmarks[12]
    ring_tip = landmarks[16]
    pinky_tip = landmarks[20]

    return (thumb_tip[1] < index_tip[1] and
            thumb_tip[1] < middle_tip[1] and
            thumb_tip[1] < ring_tip[1] and
            thumb_tip[1] < pinky_tip[1])

def start_gesture_detection(slideshow, running_flag):
    cap = cv2.VideoCapture(0)  # Open the camera
    while running_flag['running']:
        success, frame = cap.read()
        if not success:
            break

        frame = cv2.flip(frame, 1)  # Flip the frame horizontally
        rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)  # Convert to RGB
        result = hands.process(rgb_frame)

        if result.multi_hand_landmarks:
            for hand_landmarks in result.multi_hand_landmarks:
                mp_drawing.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS)

                landmarks = [(lm.x, lm.y) for lm in hand_landmarks.landmark]
                if is_thumbs_up(landmarks):
                    print("Thumbs-Up detected!")
                    slideshow.stop()  # Stop the slideshow
                    running_flag['running'] = False  # Stop the detection loop
                    break

        cv2.imshow('Gesture Detection', frame)

        # Break the loop if the user manually closes the OpenCV window
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    # Cleanup
    cap.release()
    cv2.destroyAllWindows()  # Close all OpenCV windows

When I run main.py, at first, it works as expect: The slideshow opens as well as the video feed. When I do the thumbs up, the slideshow closes and the video feed freezes (instead of closing).

I get this output:

Slideshow initialized and started
Started gesture detection thread
c:\Users\juli\Projekte\photo-finder\.venv\Lib\site-packages\google\protobuf\symbol_database.py:55: UserWarning: SymbolDatabase.GetPrototype() is deprecated. Please use message_factory.GetMessageClass() instead. SymbolDatabase.GetPrototype() will be removed soon.
  warnings.warn('SymbolDatabase.GetPrototype() is deprecated. Please '
Thumbs-Up detected!

What could be the problem and how could I fix it?



You need to sign in to view this answers

Exit mobile version