From 94e0354c32d149951c923c3842c0ae22c8c4fbc8 Mon Sep 17 00:00:00 2001 From: JayLiuTU Date: Sat, 30 Mar 2024 23:37:49 -0400 Subject: [PATCH 01/11] exponetial moving average motion smoothing --- source/gesture inference/Mouse.py | 67 ++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/source/gesture inference/Mouse.py b/source/gesture inference/Mouse.py index d07b41be6..b2b3706f3 100644 --- a/source/gesture inference/Mouse.py +++ b/source/gesture inference/Mouse.py @@ -3,7 +3,10 @@ from Console import GestureConsole class Mouse: def __init__( - self, mouse_scale, click_threshold_time=0.2, drag_threshold_time=0.15, console=None + self, + mouse_sensitivity=2, + click_threshold_time=0.2, + drag_threshold_time=0.15, ) -> None: """Initialization of Mouse class. @@ -14,7 +17,7 @@ def __init__( """ pyautogui.FAILSAFE = False pyautogui.PAUSE = 0 - self.mouse_scale = mouse_scale + self.mouse_sensitivity = mouse_sensitivity self.click_threshold_time = click_threshold_time self.drag_threshold_time = drag_threshold_time self.left_down = False @@ -23,6 +26,12 @@ def __init__( self.last_time = time.time() self.console = GestureConsole() + # expontial moving average stuff + self.x_window = [] + self.y_window = [] + self.window_size = 4 + self.alpha = 0.2 + def control(self, x: float, y: float, mouse_button: str): """Moves the mouse to XY coordinates and can perform single clicks, or click and drags when called repeatelly @@ -32,28 +41,42 @@ def control(self, x: float, y: float, mouse_button: str): mouse_button (string): can be "", "left", "middle", or "right" """ x = int( - ((self.mouse_scale) * x - (self.mouse_scale - 1) / 2) + ((self.mouse_sensitivity) * x - (self.mouse_sensitivity - 1) / 2) * pyautogui.size().width ) y = int( - ((self.mouse_scale) * y - (self.mouse_scale - 1) / 2) + ((self.mouse_sensitivity) * y - (self.mouse_sensitivity - 1) / 2) * pyautogui.size().height ) - if mouse_button == "": - # un-click - if self.left_down: - pyautogui.mouseUp(button="left", _pause=False) - self.left_down = False - if self.middle_down: - pyautogui.mouseUp(button="middle", _pause=False) - self.middle_down = False - if self.right_down: - pyautogui.mouseUp(button="right", _pause=False) - self.right_down = False - self.move(x, y) - else: - # click or click and drag - self.click(x, y, mouse_button) + + self.x_window.append(x) + self.y_window.append(y) + + x = self.exponential_moving_average(self.x_window) + y = self.exponential_moving_average(self.y_window) + + if len(self.x_window) > self.window_size: + self.x_window.pop(0) + self.y_window.pop(0) + if mouse_button == "": + # un-click + if self.left_down: + pyautogui.mouseUp(button="left", _pause=False) + self.left_down = False + if self.middle_down: + pyautogui.mouseUp(button="middle", _pause=False) + self.middle_down = False + if self.right_down: + pyautogui.mouseUp(button="right", _pause=False) + self.right_down = False + self.move(x, y) + else: + # click or click and drag + self.click( + x, + y, + mouse_button, + ) def move(self, x, y): """Move the mouse to the specified coordinates. @@ -108,3 +131,9 @@ def click(self, x, y, mouse_button): self.right_down = True self.move(x, y) + + def exponential_moving_average(self, data): + ema = [data[0]] + for i in range(1, len(data)): + ema.append(self.alpha * data[i] + (1 - self.alpha) * ema[i - 1]) + return ema[len(data) - 1] From 722ecfc3ab58786a0023a99c7cfbce23f094e5ba Mon Sep 17 00:00:00 2001 From: JayLiuTU Date: Sun, 31 Mar 2024 00:19:26 -0400 Subject: [PATCH 02/11] mouse smoothing --- source/gesture inference/GetHands.py | 14 +++++++++++--- source/gesture inference/Mouse.py | 4 ++-- source/gesture inference/inference.py | 21 ++++++++++++++------- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/source/gesture inference/GetHands.py b/source/gesture inference/GetHands.py index 6aafacdaf..f8dea1920 100644 --- a/source/gesture inference/GetHands.py +++ b/source/gesture inference/GetHands.py @@ -49,6 +49,9 @@ def __init__( self.confidence_vectors = self.gesture_model.confidence_vector self.gestures = ['no gesture'] self.delay = 0 + + self.click = '' + self.mouse_location = [] (self.grabbed, self.frame) = self.camera.read() @@ -104,8 +107,11 @@ def results_callback( ): # this try catch block is for debugging. this code runs in a different thread and doesn't automatically raise its own exceptions try: - + + self.mouse_location = [] + self.click = '' if len(result.hand_world_landmarks) == 0: + self.render_hands( result, None, @@ -144,13 +150,15 @@ def results_callback( self.console.table(self.gesture_list, hand_confidences) - if self.flags["move_mouse_flag"] and location != []: mouse_button_text = "" hand = result.hand_world_landmarks[0] if self.is_clicking(hand[8], hand[4]): mouse_button_text = "left" - self.move_mouse(location, mouse_button_text) + + self.click = mouse_button_text + self.mouse_location = location + #self.move_mouse(location, mouse_button_text) # timestamps are in microseconds so convert to ms diff --git a/source/gesture inference/Mouse.py b/source/gesture inference/Mouse.py index b2b3706f3..a25a2654c 100644 --- a/source/gesture inference/Mouse.py +++ b/source/gesture inference/Mouse.py @@ -29,8 +29,8 @@ def __init__( # expontial moving average stuff self.x_window = [] self.y_window = [] - self.window_size = 4 - self.alpha = 0.2 + self.window_size = 10 + self.alpha = 0.3 def control(self, x: float, y: float, mouse_button: str): """Moves the mouse to XY coordinates and can perform single clicks, or click and drags when called repeatelly diff --git a/source/gesture inference/inference.py b/source/gesture inference/inference.py index e30901f7b..7618b5b93 100644 --- a/source/gesture inference/inference.py +++ b/source/gesture inference/inference.py @@ -2,6 +2,8 @@ # https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html # https://pygame-menu.readthedocs.io/en/latest/_source/add_widgets.html import pydoc +#this is the community edition of pygame +#pygame-ce import pygame import pygame_menu from GetHands import GetHands @@ -98,6 +100,7 @@ def change_hands_num(value): hands, hands_surface, menu, + mouse_controls, ) pygame.quit() @@ -129,6 +132,7 @@ def game_loop( hands: GetHands, hands_surface: pygame.Surface, menu: pygame_menu.Menu, + mouse_controls:Mouse ): """Runs the pygame event loop and renders surfaces @@ -171,9 +175,14 @@ def game_loop( if event.key == pygame.K_F1: is_webcam_fullscreen = not is_webcam_fullscreen - if event.key == pygame.K_F11: + if event.key == pygame.K_F11: is_fullscreen = not is_fullscreen pygame.display.toggle_fullscreen() + + if hands.mouse_location != []: + #print(hands.mouse_location) + location = hands.mouse_location[0] + mouse_controls.control(location[0], location[1], hands.click) # frames per second fps = font.render( @@ -192,11 +201,9 @@ def game_loop( ) img_pygame = pygame.transform.scale( img_pygame, (img_width * 0.5, img_height * 0.5) - ) - - + ) - if is_webcam_fullscreen: + if is_webcam_fullscreen: img_pygame = pygame.transform.scale( img_pygame, (window_width, window_height) ) @@ -217,12 +224,12 @@ def game_loop( window.blit(delay_AI, (0, 40)) if menu.is_enabled(): - menu.update(events) + menu.update(events) menu.draw(window) window.blit(hand_surface_copy, (0, 0)) - clock.tick(60) + clock.tick(pygame.display.get_current_refresh_rate()) pygame.display.update() From e77424f45aad48258e7681fe560c51026bf6c619 Mon Sep 17 00:00:00 2001 From: JayLiuTU Date: Sun, 31 Mar 2024 11:29:02 -0400 Subject: [PATCH 03/11] added mouse smoothing menu and fixed freezing when changing hands num --- source/gesture inference/GetHands.py | 31 ++++++++------- source/gesture inference/inference.py | 57 ++++++++++++++++++--------- 2 files changed, 55 insertions(+), 33 deletions(-) diff --git a/source/gesture inference/GetHands.py b/source/gesture inference/GetHands.py index f8dea1920..261cbe98c 100644 --- a/source/gesture inference/GetHands.py +++ b/source/gesture inference/GetHands.py @@ -14,6 +14,7 @@ dname = os.path.dirname(abspath) os.chdir(dname) + class GetHands(Thread): """ Class that continuously gets frames and extracts hand data @@ -24,13 +25,13 @@ def __init__( self, render_hands, mediapipe_model="hand_landmarker.task", - gesture_model = "simple.pth", + gesture_model="simple.pth", control_mouse=None, flags=None, keyboard=None, click_sensitinity=0.05, ): - Thread.__init__(self) + Thread.__init__(self) self.model_path = mediapipe_model self.render_hands = render_hands @@ -42,15 +43,16 @@ def __init__( self.click_sensitinity = click_sensitinity self.keyboard = keyboard self.console = GestureConsole() + self.camera = Webcam() self.gesture_model = NeuralNet(gesture_model) self.gesture_list = self.gesture_model.labels self.confidence_vectors = self.gesture_model.confidence_vector - self.gestures = ['no gesture'] + self.gestures = ["no gesture"] self.delay = 0 - - self.click = '' + + self.click = "" self.mouse_location = [] (self.grabbed, self.frame) = self.camera.read() @@ -107,11 +109,11 @@ def results_callback( ): # this try catch block is for debugging. this code runs in a different thread and doesn't automatically raise its own exceptions try: - + self.mouse_location = [] - self.click = '' + self.click = "" if len(result.hand_world_landmarks) == 0: - + self.render_hands( result, None, @@ -134,13 +136,13 @@ def results_callback( # self.keyboard.gesture_input(self.confidence_vector[0]) # serialized input - hand_confidences = [] #prepare data for console table - gestures = [] #store gesture output as text + hand_confidences = [] # prepare data for console table + gestures = [] # store gesture output as text for index, hand in enumerate(model_inputs): confidences, predicted, predicted_confidence = ( self.gesture_model.get_gesture([hand], print_table=False) - ) - gestures.append(self.gesture_list[predicted[0]]) # save gesture + ) + gestures.append(self.gesture_list[predicted[0]]) # save gesture hand_confidences.append(confidences[0]) # only take inputs from the first hand, subsequent hands can't control the keyboard @@ -155,10 +157,10 @@ def results_callback( hand = result.hand_world_landmarks[0] if self.is_clicking(hand[8], hand[4]): mouse_button_text = "left" - + self.click = mouse_button_text self.mouse_location = location - #self.move_mouse(location, mouse_button_text) + # self.move_mouse(location, mouse_button_text) # timestamps are in microseconds so convert to ms @@ -194,7 +196,6 @@ def run(self): self.stop() else: (self.grabbed, self.frame) = self.camera.read() - # Detect hand landmarks self.detect_hands(self.frame) diff --git a/source/gesture inference/inference.py b/source/gesture inference/inference.py index 7618b5b93..78b55de2d 100644 --- a/source/gesture inference/inference.py +++ b/source/gesture inference/inference.py @@ -2,8 +2,9 @@ # https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html # https://pygame-menu.readthedocs.io/en/latest/_source/add_widgets.html import pydoc -#this is the community edition of pygame -#pygame-ce + +# this is the community edition of pygame +# pygame-ce import pygame import pygame_menu from GetHands import GetHands @@ -28,6 +29,7 @@ "number_of_hands": 2, "move_mouse_flag": False, "run_model_flag": True, + "hands": None, } console = GestureConsole() @@ -71,10 +73,24 @@ def main() -> None: "Render Mode :", [("World", False), ("Normalized", True)], onchange=set_coords ) - def change_hands_num(value): + def change_mouse_smooth(value, smooth): + nonlocal mouse_controls + mouse_controls.x_window = [] + mouse_controls.y_window = [] + mouse_controls.window_size = smooth - flags["number_of_hands"] = value[1] + 1 + menu.add.selector( + "Mouse Smoothing :", + [("None", 1), ("Low", 2), ("Medium", 6), ("High", 12), ("Max", 24)], + onchange=change_mouse_smooth, + ) + + def change_hands_num(value): nonlocal hands + nonlocal mouse_controls + nonlocal keyboard + flags["number_of_hands"] = value[1] + 1 + flags["move_mouse_flag"] = False hands.stop() hands.join() hands = GetHands( @@ -83,6 +99,7 @@ def change_hands_num(value): flags=flags, keyboard=keyboard, ) + flags["hands"] = hands hands.start() menu.add.dropselect( @@ -132,7 +149,7 @@ def game_loop( hands: GetHands, hands_surface: pygame.Surface, menu: pygame_menu.Menu, - mouse_controls:Mouse + mouse_controls: Mouse, ): """Runs the pygame event loop and renders surfaces @@ -150,7 +167,11 @@ def game_loop( is_fullscreen = False while running: - # window_width, window_height = menu.get_window_size() # what? idk + + #changing GetHands parameters creates a new hands object + if flags["hands"] != None and hands != flags["hands"]: + hands = flags["hands"] + window_width, window_height = pygame.display.get_surface().get_size() window.fill((0, 0, 0)) events = pygame.event.get() @@ -175,13 +196,14 @@ def game_loop( if event.key == pygame.K_F1: is_webcam_fullscreen = not is_webcam_fullscreen - if event.key == pygame.K_F11: + if event.key == pygame.K_F11: is_fullscreen = not is_fullscreen pygame.display.toggle_fullscreen() - if hands.mouse_location != []: - #print(hands.mouse_location) - location = hands.mouse_location[0] + location = hands.mouse_location.copy() + if len(location) == 1: + # console.print(location) + location = location[0] mouse_controls.control(location[0], location[1], hands.click) # frames per second @@ -189,10 +211,8 @@ def game_loop( str(round(clock.get_fps(), 1)) + "fps", False, (255, 255, 255) ) - frame = hands.frame - img_pygame = pygame.image.frombuffer( - frame.tostring(), frame.shape[1::-1], "BGR" - ) + frame = hands.frame.copy() + img_pygame = pygame.image.frombuffer(frame.tobytes(), frame.shape[1::-1], "BGR") img_width = img_pygame.get_width() img_height = img_pygame.get_height() @@ -201,9 +221,9 @@ def game_loop( ) img_pygame = pygame.transform.scale( img_pygame, (img_width * 0.5, img_height * 0.5) - ) + ) - if is_webcam_fullscreen: + if is_webcam_fullscreen: img_pygame = pygame.transform.scale( img_pygame, (window_width, window_height) ) @@ -224,12 +244,13 @@ def game_loop( window.blit(delay_AI, (0, 40)) if menu.is_enabled(): - menu.update(events) + menu.update(events) menu.draw(window) window.blit(hand_surface_copy, (0, 0)) - clock.tick(pygame.display.get_current_refresh_rate()) + #clock.tick(pygame.display.get_current_refresh_rate()) + clock.tick(60) pygame.display.update() From a0ae6ef9a6cc47b75697ca281323fc917a41a17b Mon Sep 17 00:00:00 2001 From: JayLiuTU Date: Sun, 31 Mar 2024 12:06:01 -0400 Subject: [PATCH 04/11] can change the gesture model --- source/gesture inference/GetHands.py | 11 +++++--- source/gesture inference/inference.py | 38 +++++++++++++++++++-------- 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/source/gesture inference/GetHands.py b/source/gesture inference/GetHands.py index 261cbe98c..a1300ad26 100644 --- a/source/gesture inference/GetHands.py +++ b/source/gesture inference/GetHands.py @@ -25,7 +25,6 @@ def __init__( self, render_hands, mediapipe_model="hand_landmarker.task", - gesture_model="simple.pth", control_mouse=None, flags=None, keyboard=None, @@ -46,7 +45,8 @@ def __init__( self.camera = Webcam() - self.gesture_model = NeuralNet(gesture_model) + self.set_gesture_model(flags["gesture_model_path"]) + self.gesture_list = self.gesture_model.labels self.confidence_vectors = self.gesture_model.confidence_vector self.gestures = ["no gesture"] @@ -59,9 +59,12 @@ def __init__( self.timer = 0 - self.build_model(flags["number_of_hands"]) + self.build_mediapipe_model(flags["number_of_hands"]) + + def set_gesture_model(self, path): + self.gesture_model = NeuralNet(path) - def build_model(self, hands_num): + def build_mediapipe_model(self, hands_num): """Takes in option parameters for the Mediapipe hands model Args: diff --git a/source/gesture inference/inference.py b/source/gesture inference/inference.py index 78b55de2d..8e4226ce4 100644 --- a/source/gesture inference/inference.py +++ b/source/gesture inference/inference.py @@ -29,6 +29,7 @@ "number_of_hands": 2, "move_mouse_flag": False, "run_model_flag": True, + "gesture_model_path": "motion.pth", "hands": None, } @@ -86,11 +87,25 @@ def change_mouse_smooth(value, smooth): ) def change_hands_num(value): + flags["number_of_hands"] = value[1] + 1 + build_hands() + + menu.add.dropselect( + "Number of hands :", ["1", "2", "3", "4"], onchange=change_hands_num + ) + + models = find_files_with_ending(".pth") + + def change_gesture_model(value): + flags["gesture_model_path"] = value[0][0] #tuple within a list for some reason + build_hands() + + menu.add.dropselect("Use Gesture Model :", models, onchange=change_gesture_model) + + def build_hands(): nonlocal hands nonlocal mouse_controls nonlocal keyboard - flags["number_of_hands"] = value[1] + 1 - flags["move_mouse_flag"] = False hands.stop() hands.join() hands = GetHands( @@ -102,10 +117,6 @@ def change_hands_num(value): flags["hands"] = hands hands.start() - menu.add.dropselect( - "Number of hands :", ["1", "2", "3", "4"], onchange=change_hands_num - ) - menu.add.button("Close Menu", pygame_menu.events.CLOSE) menu.add.button("Turn On Model", action=toggle_model) menu.add.button("Turn On Mouse", action=toggle_mouse) @@ -123,6 +134,11 @@ def change_hands_num(value): pygame.quit() +def find_files_with_ending(ending: str, directory_path=os.getcwd()): + files = [(file,) for file in os.listdir(directory_path) if file.endswith(ending)] + return files + + def toggle_mouse() -> None: """Enable or disable mouse control""" console.print("toggling mouse control") @@ -167,11 +183,11 @@ def game_loop( is_fullscreen = False while running: - - #changing GetHands parameters creates a new hands object + + # changing GetHands parameters creates a new hands object if flags["hands"] != None and hands != flags["hands"]: hands = flags["hands"] - + window_width, window_height = pygame.display.get_surface().get_size() window.fill((0, 0, 0)) events = pygame.event.get() @@ -199,7 +215,7 @@ def game_loop( if event.key == pygame.K_F11: is_fullscreen = not is_fullscreen pygame.display.toggle_fullscreen() - + location = hands.mouse_location.copy() if len(location) == 1: # console.print(location) @@ -249,7 +265,7 @@ def game_loop( window.blit(hand_surface_copy, (0, 0)) - #clock.tick(pygame.display.get_current_refresh_rate()) + # clock.tick(pygame.display.get_current_refresh_rate()) clock.tick(60) pygame.display.update() From 8a6fa202ac818358f6599298ef21d25cfae59a8d Mon Sep 17 00:00:00 2001 From: JayLiuTU Date: Sun, 31 Mar 2024 17:11:49 -0400 Subject: [PATCH 05/11] added mouse control menu stuff --- source/gesture inference/GetHands.py | 18 ++------ source/gesture inference/Mouse.py | 35 ++++++++++++--- source/gesture inference/inference.py | 61 ++++++++++++++++++--------- 3 files changed, 73 insertions(+), 41 deletions(-) diff --git a/source/gesture inference/GetHands.py b/source/gesture inference/GetHands.py index a1300ad26..515ea0b4d 100644 --- a/source/gesture inference/GetHands.py +++ b/source/gesture inference/GetHands.py @@ -25,10 +25,9 @@ def __init__( self, render_hands, mediapipe_model="hand_landmarker.task", - control_mouse=None, + mouse=None, flags=None, keyboard=None, - click_sensitinity=0.05, ): Thread.__init__(self) @@ -36,10 +35,10 @@ def __init__( self.render_hands = render_hands self.confidence = 0.5 self.stopped = False - self.control_mouse = control_mouse + self.mouse = mouse self.flags = flags - self.click_sensitinity = click_sensitinity + self.click_sensitinity = flags["click_sense"] self.keyboard = keyboard self.console = GestureConsole() @@ -158,7 +157,7 @@ def results_callback( if self.flags["move_mouse_flag"] and location != []: mouse_button_text = "" hand = result.hand_world_landmarks[0] - if self.is_clicking(hand[8], hand[4]): + if self.mouse.is_clicking(hand[8], hand[4], self.flags["click_sense"]): mouse_button_text = "left" self.click = mouse_button_text @@ -182,15 +181,6 @@ def results_callback( traceback.print_exc() quit() - def is_clicking(self, tip1, tip2): - distance = math.sqrt( - (tip1.x - tip2.x) ** 2 + (tip1.y - tip2.y) ** 2 + (tip1.z - tip2.z) ** 2 - ) - if distance < self.click_sensitinity: - return True - else: - return False - def run(self): """Continuously grabs new frames from the webcam and uses Mediapipe to detect hands""" while not self.stopped: diff --git a/source/gesture inference/Mouse.py b/source/gesture inference/Mouse.py index a25a2654c..a2408a8a7 100644 --- a/source/gesture inference/Mouse.py +++ b/source/gesture inference/Mouse.py @@ -1,20 +1,32 @@ import pyautogui import time from Console import GestureConsole +import math + + class Mouse: def __init__( self, mouse_sensitivity=2, - click_threshold_time=0.2, - drag_threshold_time=0.15, + click_threshold_time=0.22, + drag_threshold_time=0.2, ) -> None: """Initialization of Mouse class. Args: mouse_scale (float): Scale factor for mouse movement. - click_threshold_time (float, optional): Threshold time for registering a click. Defaults to 0.2. - drag_threshold_time (float, optional): Threshold time for registering a drag. Defaults to 0.15. + click_threshold_time (float, optional): The click_threshold_time is the minimum time interval between two consecutive clicks to register them as separate clicks. + If you increase click_threshold_time, you will need to wait longer between two clicks for them to be considered separate clicks. + If you decrease click_threshold_time, you can click faster and still register them as separate clicks. + drag_threshold_time (float, optional): The drag_threshold_time is the maximum time interval after which a mouse movement after a click is considered a drag rather than a separate click. + If you increase drag_threshold_time, you will have more time to move the mouse after clicking without triggering a drag. + If you decrease drag_threshold_time, even a slight movement of the mouse shortly after clicking can be considered a drag rather than a separate click. """ + if click_threshold_time <= drag_threshold_time: + raise Exception( + "drag_threshold_time must be less than click_threshold_time" + ) + pyautogui.FAILSAFE = False pyautogui.PAUSE = 0 self.mouse_sensitivity = mouse_sensitivity @@ -29,8 +41,8 @@ def __init__( # expontial moving average stuff self.x_window = [] self.y_window = [] - self.window_size = 10 - self.alpha = 0.3 + self.window_size = 12 + self.alpha = 0.2 def control(self, x: float, y: float, mouse_button: str): """Moves the mouse to XY coordinates and can perform single clicks, or click and drags when called repeatelly @@ -45,7 +57,7 @@ def control(self, x: float, y: float, mouse_button: str): * pyautogui.size().width ) y = int( - ((self.mouse_sensitivity) * y - (self.mouse_sensitivity - 1) / 2) + ((self.mouse_sensitivity) * y - (self.mouse_sensitivity - 1.5) / 1.5) * pyautogui.size().height ) @@ -78,6 +90,15 @@ def control(self, x: float, y: float, mouse_button: str): mouse_button, ) + def is_clicking(self, tip1, tip2, click_sensitinity): + distance = math.sqrt( + (tip1.x - tip2.x) ** 2 + (tip1.y - tip2.y) ** 2 + (tip1.z - tip2.z) ** 2 + ) + if distance < click_sensitinity: + return True + else: + return False + def move(self, x, y): """Move the mouse to the specified coordinates. diff --git a/source/gesture inference/inference.py b/source/gesture inference/inference.py index 8e4226ce4..7791fbc7f 100644 --- a/source/gesture inference/inference.py +++ b/source/gesture inference/inference.py @@ -29,7 +29,8 @@ "number_of_hands": 2, "move_mouse_flag": False, "run_model_flag": True, - "gesture_model_path": "motion.pth", + "gesture_model_path": "simple.pth", + "click_sense": 0.06, "hands": None, } @@ -49,7 +50,7 @@ def main() -> None: myRenderHands = RenderHands(hands_surface, render_scale=3) - mouse_controls = Mouse(mouse_sensitivity=2) + mouse = Mouse(mouse_sensitivity=2) keyboard = Keyboard( threshold=0, toggle_key_threshold=0.3, toggle_mouse_func=toggle_mouse @@ -58,7 +59,7 @@ def main() -> None: # control_mouse=mouse_controls.control, hands = GetHands( myRenderHands.render_hands, - control_mouse=mouse_controls.control, + mouse=mouse, flags=flags, keyboard=keyboard, ) @@ -75,14 +76,15 @@ def main() -> None: ) def change_mouse_smooth(value, smooth): - nonlocal mouse_controls - mouse_controls.x_window = [] - mouse_controls.y_window = [] - mouse_controls.window_size = smooth + nonlocal mouse + mouse.x_window = [] + mouse.y_window = [] + mouse.window_size = smooth menu.add.selector( "Mouse Smoothing :", [("None", 1), ("Low", 2), ("Medium", 6), ("High", 12), ("Max", 24)], + default=3, onchange=change_mouse_smooth, ) @@ -97,27 +99,39 @@ def change_hands_num(value): models = find_files_with_ending(".pth") def change_gesture_model(value): - flags["gesture_model_path"] = value[0][0] #tuple within a list for some reason + flags["gesture_model_path"] = value[0][0] # tuple within a list for some reason build_hands() menu.add.dropselect("Use Gesture Model :", models, onchange=change_gesture_model) + def set_click_sense(value, **kwargs): + nonlocal hands + flags["click_sense"] = value / 100 + hands.click_sensitinity = flags["click_sense"] + + menu.add.range_slider( + "Click Sensitivity", + default=60, + range_values=(1, 100), + increment=0.01, + onchange=set_click_sense, + ) + def build_hands(): nonlocal hands - nonlocal mouse_controls + nonlocal mouse nonlocal keyboard hands.stop() hands.join() hands = GetHands( myRenderHands.render_hands, - control_mouse=mouse_controls.control, + mouse=mouse, flags=flags, keyboard=keyboard, ) flags["hands"] = hands hands.start() - menu.add.button("Close Menu", pygame_menu.events.CLOSE) menu.add.button("Turn On Model", action=toggle_model) menu.add.button("Turn On Mouse", action=toggle_mouse) menu.add.button("Quit", pygame_menu.events.EXIT) @@ -128,13 +142,15 @@ def build_hands(): hands, hands_surface, menu, - mouse_controls, + mouse, ) pygame.quit() def find_files_with_ending(ending: str, directory_path=os.getcwd()): + """returns a list of tuples of the strings found + """ files = [(file,) for file in os.listdir(directory_path) if file.endswith(ending)] return files @@ -181,8 +197,10 @@ def game_loop( is_webcam_fullscreen = False is_fullscreen = False - + counter = 0 + delay_AI = None while running: + counter += 1 # changing GetHands parameters creates a new hands object if flags["hands"] != None and hands != flags["hands"]: @@ -252,12 +270,15 @@ def game_loop( for index in range(len(hands.gestures)): gesture_text = font.render(hands.gestures[index], False, (255, 255, 255)) window.blit(gesture_text, (window_width - window_width // 5, index * 40)) - - delay_AI = font.render( - str(round(hands.delay, 1)) + "ms", False, (255, 255, 255) - ) + + if hands.delay != 0 and counter%60==0: + delay_AI = font.render( + "Webcam: "+str(round(1000/hands.delay, 1)) + "fps", False, (255, 255, 255) + ) + if delay_AI != None: + window.blit(delay_AI, (0, 40)) window.blit(fps, (0, 0)) - window.blit(delay_AI, (0, 40)) + if menu.is_enabled(): menu.update(events) @@ -265,8 +286,8 @@ def game_loop( window.blit(hand_surface_copy, (0, 0)) - # clock.tick(pygame.display.get_current_refresh_rate()) - clock.tick(60) + clock.tick(pygame.display.get_current_refresh_rate()) + # clock.tick(60) pygame.display.update() From 6c2f989275ede1639ec33451fcb91df28a90a5a1 Mon Sep 17 00:00:00 2001 From: JayLiuTU Date: Sun, 31 Mar 2024 17:19:32 -0400 Subject: [PATCH 06/11] merge with main --- HandGestureInputControl.html | 78 --- MainMenu.html | 160 ----- MiniGameSelectionScreen.html | 83 --- PlayerSelectionScreen.html | 86 --- .../gesture inference/README.md => README.md | 0 documentation.html | 20 - gui.py | 1 - gui/HandGestureInputControl.py | 46 -- gui/MainMenu.py | 59 -- gui/MiniGameSelectionScreen.py | 60 -- gui/PlayerSelectionScreen.html | 83 --- gui/PlayerSelectionScreen.py | 51 -- .../HandGestureInputControl.cpython-310.pyc | Bin 2299 -> 0 bytes gui/__pycache__/MainMenu.cpython-310.pyc | Bin 2256 -> 0 bytes gui/__pycache__/MainMenu.cpython-311.pyc | Bin 2528 -> 0 bytes .../MiniGameSelectionScreen.cpython-310.pyc | Bin 2478 -> 0 bytes .../PlayerSelectionScreen.cpython-310.pyc | Bin 2140 -> 0 bytes .../PlayerSelectionScreen.cpython-311.pyc | Bin 2363 -> 0 bytes gui/random.html | 568 ------------------ pygame.html | 43 -- pygame_class.py | 40 -- random.html | 568 ------------------ 22 files changed, 1946 deletions(-) delete mode 100644 HandGestureInputControl.html delete mode 100644 MainMenu.html delete mode 100644 MiniGameSelectionScreen.html delete mode 100644 PlayerSelectionScreen.html rename source/gesture inference/README.md => README.md (100%) delete mode 100644 documentation.html delete mode 100644 gui.py delete mode 100644 gui/HandGestureInputControl.py delete mode 100644 gui/MainMenu.py delete mode 100644 gui/MiniGameSelectionScreen.py delete mode 100644 gui/PlayerSelectionScreen.html delete mode 100644 gui/PlayerSelectionScreen.py delete mode 100644 gui/__pycache__/HandGestureInputControl.cpython-310.pyc delete mode 100644 gui/__pycache__/MainMenu.cpython-310.pyc delete mode 100644 gui/__pycache__/MainMenu.cpython-311.pyc delete mode 100644 gui/__pycache__/MiniGameSelectionScreen.cpython-310.pyc delete mode 100644 gui/__pycache__/PlayerSelectionScreen.cpython-310.pyc delete mode 100644 gui/__pycache__/PlayerSelectionScreen.cpython-311.pyc delete mode 100644 gui/random.html delete mode 100644 pygame.html delete mode 100644 pygame_class.py delete mode 100644 random.html diff --git a/HandGestureInputControl.html b/HandGestureInputControl.html deleted file mode 100644 index 160d0fdb5..000000000 --- a/HandGestureInputControl.html +++ /dev/null @@ -1,78 +0,0 @@ - -Python: module HandGestureInputControl - - - - - -
 
- 
HandGestureInputControl
index
/Users/giamaio/Desktop/College/Spring 2024/CIS 4398/project-motion/gui/HandGestureInputControl.py
-

-

- - - - - -
 
-Modules
       
pydoc
-
pygame
-

- - - - - -
 
-Classes
       
-
builtins.object -
-
-
HandGestureInputControl -
-
-
-

- - - - - - - -
 
-class HandGestureInputControl(builtins.object)
   A class to handle hand gesture inputs for controlling game actions.

-This class is designed to capture hand gestures using a camera or sensor input,
-interpret these gestures as commands, and perform actions based on the interpreted gestures.

-Attributes:
-    gesture (str): The current hand gesture recognized by the system.
 
 Methods defined here:
-
__init__(self)
Purpose: Initializes the HandGestureInputControl class with default gesture.
-Post-conditions: The HandGestureInputControl object is created with the default gesture.
- -
captureGesture(self)
Purpose: Captures and updates the current hand gesture.
-Post-conditions: The current hand gesture is updated.
- -
mapGestureToAction(self, gesture: str)
Purpose: Maps the captured hand gesture to a specific game action.
-Pre-conditions: A hand gesture must be captured.
-Post-conditions: The hand gesture is mapped to a game action.
-Parameters:
-    - gesture (str): The hand gesture to map to an action.
- -
performClickAction(self)
Purpose: Performs a click action based on the current hand gesture.
-Pre-conditions: A hand gesture must be captured and mapped to a game action.
-Post-conditions: The click action is performed based on the current hand gesture.
- -
-Data descriptors defined here:
-
__dict__
-
dictionary for instance variables (if defined)
-
-
__weakref__
-
list of weak references to the object (if defined)
-
-

- \ No newline at end of file diff --git a/MainMenu.html b/MainMenu.html deleted file mode 100644 index eb36fe4fc..000000000 --- a/MainMenu.html +++ /dev/null @@ -1,160 +0,0 @@ -<<<<<<< Updated upstream - -Python: module MainMenu - - - - - -
 
- 
MainMenu
index
/Users/giamaio/Desktop/College/Spring 2024/CIS 4398/project-motion/gui/MainMenu.py
-

-

- - - - - -
 
-Modules
       
pydoc
-
pygame
-

- - - - - -
 
-Classes
       
-
builtins.object -
-
-
MainMenu -
-
-
-

- - - - - - - -
 
-class MainMenu(builtins.object)
   MainMenu class manages the main menu of the for our program. It handles displaying menu options (mini games, settings, player selection),
-user selections, navigation to the selection screen, and displaying settings.

-Attributes:
-    menuOptions (list of str): A list containing the string labels for the menu options.
 
 Methods defined here:
-
__init__(self)
Initialize self.  See help(type(self)) for accurate signature.
- -
displayMenu(self)
Displays the main menu options to the player(s).
-No pre-conditions.
-Post-conditions: Menu options are displayed to the user.
- -
handleSelection(selection: str)
Identifies the user's choice from the main menu options.
-======= - - - - -Python: module MainMenu - - - - - -
 
MainMenu
index
/Users/zaina/Documents/GitHub/project-motion/gui/MainMenu.py
-

-

- - - - - -
 
Modules
       
pydoc
-
pygame
-

- - - - - -
 
Classes
       
-
builtins.object -
-
-
MainMenu -
-
-
-

- - - - - - - -
 
class MainMenu(builtins.object)
   Purpose: MainMenu class manages the main menu of the for our program. It handles displaying menu options (mini games, settings, player selection),
-user selections, navigation to the selection screen, and displaying settings.

-Attributes:
-    menuOptions (list of str): A list containing the string labels for the menu options.
 
 Methods defined here:
-
__init__(self)
Initialize self.  See help(type(self)) for accurate signature.
- -
displayMenu(self)
Purpose: Displays the main menu options to the player(s).
-No pre-conditions.
-Post-conditions: Menu options are displayed to the user.
- -
handleSelection(selection: str)
Purpose: Identifies the user's choice from the main menu options.
->>>>>>> Stashed changes - 
-Pre-conditions:
-    displayMenu has been called, and user input has been received.
-Post-conditions:
-    The action corresponding to the user's selection is executed.
-    
-Parameters:
-    selection (str): The user's choice from the menu options.
-    
-Returns:
-    None: The return value is the selection (str)
-    
-Raises:
-<<<<<<< Updated upstream -    ValueError: If the selection does not match any menu options.
- -
navigateToSelectionScreen(self)
Navigates the user from the main menu to the selection screen.

-No pre-conditions.
-Post-conditions: The application state changes to the selection screen.
-======= -    ValueError: If the selection does not match any menu options. - -
navigateToSelectionScreen(self)
Purpose: Navigates the user from the main menu to the selection screen.

-No pre-conditions.
-Post-conditions: The application state changes to the selection screen.
->>>>>>> Stashed changes - -
-Data descriptors defined here:
-
__dict__
-<<<<<<< Updated upstream -
dictionary for instance variables (if defined)
-
-
__weakref__
-
list of weak references to the object (if defined)
-======= -
dictionary for instance variables (if defined)
-
-
__weakref__
-
list of weak references to the object (if defined)
->>>>>>> Stashed changes -
-

- \ No newline at end of file diff --git a/MiniGameSelectionScreen.html b/MiniGameSelectionScreen.html deleted file mode 100644 index 02f964455..000000000 --- a/MiniGameSelectionScreen.html +++ /dev/null @@ -1,83 +0,0 @@ - -Python: module MiniGameSelectionScreen - - - - - -
 
- 
MiniGameSelectionScreen
index
/Users/giamaio/Desktop/College/Spring 2024/CIS 4398/project-motion/gui/MiniGameSelectionScreen.py
-

-

- - - - - -
 
-Modules
       
pydoc
-
pygame
-

- - - - - -
 
-Classes
       
-
builtins.object -
-
-
MiniGameSelectionScreen -
-
-
-

- - - - - - - -
 
-class MiniGameSelectionScreen(builtins.object)
   MiniGameSelectionScreen(menuOptions: list[str])

-Represents a screen for selecting mini-games.

-This class provides a graphical interface for the user to select one of the available mini-games to play.
 
 Methods defined here:
-
__init__(self, menuOptions: list[str])
Initializes the MiniGameSelectionScreen with a list of mini-game options.

-Args:
-    menuOptions (list[str]): A list of strings representing the names of the mini-games available for selection.
- -
displayGames(self)
Displays the available mini-games for the user to select.

-This method should be implemented to update the screen with the game options.
- -
exitGame(self)
Purpose: Exits the currently running mini-game and cleans up resources.
-Pre-conditions: A mini-game must be running.
-Post-conditions: Resources are cleaned up and the mini-game is exited.
- -
handleSelection(self, selection: str)
Purpose: Processes the user's selection of a mini-game.
-Parameters:
-    - selection (str): The name of the selected mini-game.
- -
startSelectedGame(self, game: str)
Purpose: Starts the selected mini-game.
-Pre-conditions: The game must be selected by the user.
-Post-conditions: The selected mini-game is initialized and launched.
-Parameters:
-    - game (str): The name of the game to start.
- -
-Data descriptors defined here:
-
__dict__
-
dictionary for instance variables (if defined)
-
-
__weakref__
-
list of weak references to the object (if defined)
-
-

- \ No newline at end of file diff --git a/PlayerSelectionScreen.html b/PlayerSelectionScreen.html deleted file mode 100644 index a9ea5b9cf..000000000 --- a/PlayerSelectionScreen.html +++ /dev/null @@ -1,86 +0,0 @@ - -Python: module PlayerSelectionScreen - - - - - -
 
- 
PlayerSelectionScreen
index
/Users/giamaio/Desktop/College/Spring 2024/CIS 4398/project-motion/gui/PlayerSelectionScreen.py
-

-

- - - - - -
 
-Modules
       
pydoc
-
pygame
-

- - - - - -
 
-Classes
       
-
builtins.object -
-
-
PlayerSelectionScreen -
-
-
-

- - - - - - - -
 
-class PlayerSelectionScreen(builtins.object)
   PlayerSelectionScreen(numOfPlayers: int)

-PlayerSelectionScreen class manages the player selection interface of the application.
-It displays the number of player options and handles user selection.

-Attributes:
-    numOfPlayers (int): The number of player options to display.
 
 Methods defined here:
-
__init__(self, numOfPlayers: int)
Initializes the PlayerSelectionScreen instance with the number of players.

-Parameters:
-    numOfPlayers (int): number of players being used in the game.
- -
displayOptions(self)
Displays the player options (single player or multiplayer) based on the number of players.
-No pre-conditions.
-Post-conditions: Player options are displayed to the user.
- -
handleSelection(selection: int)
Determines the game's mode (single player or multiplayer) based off of the number of players.

-Pre-conditions:
-    displayOptions has been called, and user input has been received.
-Post-conditions:
-    The action corresponding to the user's selection is executed.
-Parameters:
-    selection (int): The user's selection of the number of players.
-    
-Returns:
-    Nothing
-    
-Raises:
-    ValueError: If the selection is not within the valid range of player options.
- -
-Data descriptors defined here:
-
__dict__
-
dictionary for instance variables (if defined)
-
-
__weakref__
-
list of weak references to the object (if defined)
-
-

- \ No newline at end of file diff --git a/source/gesture inference/README.md b/README.md similarity index 100% rename from source/gesture inference/README.md rename to README.md diff --git a/documentation.html b/documentation.html deleted file mode 100644 index 67d19b513..000000000 --- a/documentation.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - -Python: package documentation - - - - - -
 
documentation
index
(built-in)
-

-

- - - - - -
 
Package Contents
       
- \ No newline at end of file diff --git a/gui.py b/gui.py deleted file mode 100644 index 8b1378917..000000000 --- a/gui.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/gui/HandGestureInputControl.py b/gui/HandGestureInputControl.py deleted file mode 100644 index bddf63d05..000000000 --- a/gui/HandGestureInputControl.py +++ /dev/null @@ -1,46 +0,0 @@ -import pygame_class -import pydoc - -class HandGestureInputControl: - """ - A class to handle hand gesture inputs for controlling game actions. - - This class is designed to capture hand gestures using a camera or sensor input, - interpret these gestures as commands, and perform actions based on the interpreted gestures. - - Attributes: - gesture (str): The current hand gesture recognized by the system. - """ - - def __init__(self): - """ - Purpose: Initializes the HandGestureInputControl class with default gesture. - Post-conditions: The HandGestureInputControl object is created with the default gesture. - """ - self.gesture = "up" - - def captureGesture(self): - """ - Purpose: Captures and updates the current hand gesture. - Post-conditions: The current hand gesture is updated. - """ - pass - - def mapGestureToAction(self, gesture: str): - """ - Purpose: Maps the captured hand gesture to a specific game action. - Pre-conditions: A hand gesture must be captured. - Post-conditions: The hand gesture is mapped to a game action. - Parameters: - - gesture (str): The hand gesture to map to an action. - """ - pass - - def performClickAction(self): - """ - Purpose: Performs a click action based on the current hand gesture. - Pre-conditions: A hand gesture must be captured and mapped to a game action. - Post-conditions: The click action is performed based on the current hand gesture. - """ - pass -pydoc.writedoc("HandGestureInputControl") diff --git a/gui/MainMenu.py b/gui/MainMenu.py deleted file mode 100644 index f6e5644a2..000000000 --- a/gui/MainMenu.py +++ /dev/null @@ -1,59 +0,0 @@ -import pygame -import pydoc -class MainMenu: - - """ - Purpose: MainMenu class manages the main menu of the for our program. It handles displaying menu options (mini games, settings, player selection), - user selections, navigation to the selection screen, and displaying settings. - - Attributes: - menuOptions (list of str): A list containing the string labels for the menu options. - """ - - def __init__(self): - self.menuOptions = [2] - - - def displayMenu(self): - """ - Purpose: Displays the main menu options to the player(s). - No pre-conditions. - Post-conditions: Menu options are displayed to the user. - """ - return self.menuOptions - - - def handleSelection(selection:str): - - """ - Purpose: Identifies the user's choice from the main menu options. - - Pre-conditions: - displayMenu has been called, and user input has been received. - Post-conditions: - The action corresponding to the user's selection is executed. - - Parameters: - selection (str): The user's choice from the menu options. - - Returns: - The return value is the selection (str) - - Raises: - ValueError: If the selection does not match any menu options. - """ - return selection - - - def navigateToSelectionScreen(self): - """ - Purpose: Navigates the user from the main menu to the selection screen. - - No pre-conditions. - Post-conditions: The application state changes to the selection screen. - """ - - return - - -pydoc.writedoc("MainMenu") diff --git a/gui/MiniGameSelectionScreen.py b/gui/MiniGameSelectionScreen.py deleted file mode 100644 index 3d8005fb9..000000000 --- a/gui/MiniGameSelectionScreen.py +++ /dev/null @@ -1,60 +0,0 @@ -import pygame_class -import pydoc -class MiniGameSelectionScreen: - """ - Represents a screen for selecting mini-games. - - This class provides a graphical interface for the user to select one of the available mini-games to play. - """ - - def __init__(self, menuOptions: list[str]): - """ - Initializes the MiniGameSelectionScreen with a list of mini-game options. - - Args: - menuOptions (list[str]): A list of strings representing the names of the mini-games available for selection. - """ - self.menuOptions = menuOptions - - def displayGames(self): - """ - Displays the available mini-games for the user to select. - - This method should be implemented to update the screen with the game options. - """ - pass - - - def handleSelection(self, selection: str): - """ - Purpose: Processes the user's selection of a mini-game. - Parameters: - - selection (str): The name of the selected mini-game. - """ - pass - - def startSelectedGame(self, game: str): - """ - Purpose: Starts the selected mini-game. - Pre-conditions: The game must be selected by the user. - Post-conditions: The selected mini-game is initialized and launched. - Parameters: - - game (str): The name of the game to start. - """ - pass - - def exitGame(self): - """ - Purpose: Exits the currently running mini-game and cleans up resources. - Pre-conditions: A mini-game must be running. - Post-conditions: Resources are cleaned up and the mini-game is exited. - """ - pygame_class.quit() - - def startSelectedGame(game:str): - return - - def exitGame(): - pygame_class.quit() - -pydoc.writedoc("MiniGameSelectionScreen") \ No newline at end of file diff --git a/gui/PlayerSelectionScreen.html b/gui/PlayerSelectionScreen.html deleted file mode 100644 index fceb64bbf..000000000 --- a/gui/PlayerSelectionScreen.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - -Python: module PlayerSelectionScreen - - - - - -
 
PlayerSelectionScreen
index
/Users/zaina/Documents/GitHub/project-motion/gui/PlayerSelectionScreen.py
-

-

- - - - - -
 
Modules
       
pydoc
-
pygame
-

- - - - - -
 
Classes
       
-
builtins.object -
-
-
PlayerSelectionScreen -
-
-
-

- - - - - - - -
 
class PlayerSelectionScreen(builtins.object)
   PlayerSelectionScreen(numOfPlayers: int)

-PlayerSelectionScreen class manages the player selection interface of the application.
-It displays the number of player options and handles user selection.

-Attributes:
-    numOfPlayers (int): The number of player options to display.
 
 Methods defined here:
-
__init__(self, numOfPlayers: int)
Initializes the PlayerSelectionScreen instance with the number of players.

-Parameters:
-    numOfPlayers (int): number of players being used in the game.
- -
displayOptions(self)
Displays the player options (single player or multiplayer) based on the number of players.
-No pre-conditions.
-Post-conditions: Player options are displayed to the user.
- -
handleSelection(selection: int)
Determines the game's mode (single player or multiplayer) based off of the number of players.

-Pre-conditions:
-    displayOptions has been called, and user input has been received.
-Post-conditions:
-    The action corresponding to the user's selection is executed.
-Parameters:
-    selection (int): The user's selection of the number of players.
-    
-Returns:
-    Nothing
-    
-Raises:
-    ValueError: If the selection is not within the valid range of player options.
- -
-Data descriptors defined here:
-
__dict__
-
dictionary for instance variables (if defined)
-
-
__weakref__
-
list of weak references to the object (if defined)
-
-

- \ No newline at end of file diff --git a/gui/PlayerSelectionScreen.py b/gui/PlayerSelectionScreen.py deleted file mode 100644 index 160295d63..000000000 --- a/gui/PlayerSelectionScreen.py +++ /dev/null @@ -1,51 +0,0 @@ -import pygame -import pydoc -class PlayerSelectionScreen: - - """ - PlayerSelectionScreen class manages the player selection interface of the application. - It displays the number of player options and handles user selection. - - Attributes: - numOfPlayers (int): The number of player options to display. - """ - - def __init__(self, numOfPlayers:int): - """ - Initializes the PlayerSelectionScreen instance with the number of players. - - Parameters: - numOfPlayers (int): number of players being used in the game. - """ - self.numOfPlayers = numOfPlayers - - def displayOptions(self): - - """ - Displays the player options (single player or multiplayer) based on the number of players. - No pre-conditions. - Post-conditions: Player options are displayed to the user. - """ - - return - - def handleSelection(selection:int): - """ - Determines the game's mode (single player or multiplayer) based off of the number of players. - - Pre-conditions: - displayOptions has been called, and user input has been received. - Post-conditions: - The action corresponding to the user's selection is executed. - Parameters: - selection (int): The user's selection of the number of players. - - Returns: - Nothing - - Raises: - ValueError: If the selection is not within the valid range of player options. - """ - return - - pydoc.writedoc("PlayerSelectionScreen") diff --git a/gui/__pycache__/HandGestureInputControl.cpython-310.pyc b/gui/__pycache__/HandGestureInputControl.cpython-310.pyc deleted file mode 100644 index 18fbb5c2d632f003737e8648c0a715f070ae7b61..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2299 zcmb7F&u`;I6dpTH;%3_-?Ey|ma{^Me4O&)cw?c?2NTr9ZDz#j4z?yg_$?V!5Gc(pI z5jQIFZ@_W?3jPW%J|S`9%xzD+H@5SGB)eiHkH=%bZ{GX9_ny_!QIEj*h6uaE5d!=dLX>@vp@2M_iKx{e)Bx|>W=h-zrljs#5k{y zCE}N`E6B*>WaM*i)T*#X0S|clfsER`BRUhGcX{{_jJo`Q_h2{Vj{y6y{OCKD@hf3$ zp~ZEU7j~#Jt5w2&@CfNq7?(6om@(8UI)iT$;cj$V*-(i_hE9~Gab=pwY)Ypr6_mwR zs?41C9MJttni>lhTo^gc1V`MM<#_%Eu%U%PAO>$!p&5k(jK~b!+>xgaQ)X7^TnkI> zOc>F4WhjHARGNar=9I!rbD_bt)#1-;Isl`H{pkOmysqhn3@YiVad`GggTZQQTCz<6$zv1gzj2T0JX zifA988ov~=rKqJA%tCAq9DUe(K;b(o}8r$y&g;pIoRX#c|I@0 zD3U-~6n%gUBh|h3VjpYg&Bt3Bp-!mLKLJdxKK;cn+v*IfjD|df)GKlhJXJF7%9Hm9 zvC9PMuVDGg`o@u|+u&KXLT+^kQ+ZsM*i}`vAHtsFAZRZ>*+<%@iN=6q40omW z3{`207?@01oOh9+gS>1b9u$5qaU&9}R zID-GH+hZ`UHM>`ruAP1i-&Wd%i<5oYZJX`Q>hUyd+tp?C_DKa^So^5bAWfdW%yc4=;rXaLUSwEK*Fyo55LBWH@Fp&&^z{z GPyPidV2rK+ diff --git a/gui/__pycache__/MainMenu.cpython-310.pyc b/gui/__pycache__/MainMenu.cpython-310.pyc deleted file mode 100644 index ce656755fbcc29e80331333057279a4e21c88da6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2256 zcmb7G&5s*36!#>v*-7@Js)`VBvbeC3wwtO{1tJ7gTZHz|uxbj2Tt?oplXaPl2ivod zXm9M5e*w{B{}29(IU#ZCjWZ|S^L%Ezi-e_d#(rWg_W?2w~ka|A$?2- zp#T}a#_UYQh9V9QAcsw1=g1k40M>fodk3Clc+4(L+*^2;Bm^eFX>=xUQ25%*cUs}V z(uWM^uZa#o`p@&xcL0eQEhK~EP@|{9{9si&I#zKk7Gg9_U0@F%JbW}dKAF--AAk1g z2+rpvzR!*CA+!ytCO_1#*dlD?G-=Hqe!%9Bg-60`8u zztyNdEhz97c}k$m^D9pNzzhq-@Hi$4C?)O#=3F|~G@?^wY)dev$X=>SlT3^1B>K`Rj!NWPg)W8c4B(L;!I%BuIQ`g zL|p`R#G7`RH0{=c!tc?_*IFw*rYA+~Y_j1BXpkri?bSx-(7aX~4YLW~QFZ8P>>Ss* zd#7l-(<;IbD*pQS*6-E)y{7cv#C6wCXZ=T==A>x7Ez;h^)myr9lSX6je^j~SS(?T& zDtf=M%nGO&mblC5=9{4LIVteEsp{V^Zxr!D)#y##Me?A=Fj#+BV|c6jWZ1_}ngDsj zFdu~BQt>Rt_uVl3F=KHl*$zXlqA=9>mqG8qly`y98k?`)#|ayKYr^KFu`A=9@9vF& z_?;jK{Qds!yG}Cn^Ip2bOEuq0S76@l=D|-|LZQL(29tU4c@g0k*vAcO1SIhGz5P%A E1qqyCYybcN diff --git a/gui/__pycache__/MainMenu.cpython-311.pyc b/gui/__pycache__/MainMenu.cpython-311.pyc deleted file mode 100644 index 74ec77bf30e2c987bf9228b30f74e6a13a0a08f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2528 zcmb7FOKTiQ5boKRMz5^=NU%f_H3`I8khOu3i!cF$gRO%%B64zA0z+%McQs;mX58JQ zM2io5&_Vw|Ifa~JOiuYB0R?mrdkW;_+Xm(2Q>uENt4AO`yEXlq>Z-54s(!V&I7gsG zKm93wYY_4m4zgBDI~Uu~IU$^I%O~CBZFQ{*c|v&Qi16w!6+(W6f6}^@3K7%1l!y$Y`%)w(mh z0W&tA0gd+9e#X4unFwO`9UM1Dp>4-93YFNT*%EbqrW75pfc1rC)Skg#_eaQwJbW77c7H}Uv;GT+ncIXBD^pi+?VW8;RzzaOuX9J?u@7-#%=A1GuR65G-Qt$Dtd; zUai_sJpDA@Z9_Qr0mTP{5OHevW3Qb>bt5_)+l~W{XvZ1e%BQobMbNKqgBX$X_dodY zv*X&Ceecx#E?|~S`Gdw7f0m$gLSB-6++rGdVhvyA_~z_-oUq~wpHl48kS1hUQ>_F< zj8G>8mWc-t2JRUm6-(Qp(xnBUa48IwNs*C3@QgD^t3rXC0h{G4hy-6b58d&6%3#zs zyqhCcn!SZzAYvmjSs+Vy&zh^J_Nv60@oY}Z>mh?8Vjx4H*i#7kRjjr+1l8+#Y4)Mb z_Z4;bLeCYnC&NL)xgsgc#6!#ql~c$Sw8u>)e;{`i-GvmQF7tiClT0!x=mk-Xxt*>{ z;R^3S@B+ijLCDX>GoC}nFq78Q4W$$+!Z2bgB`KV`mP1B8Ma2)og(NKLK6 zPn8Q0E`EzzzLYYQn{+EFu!Sxj0u6#tLlM^Q9+bGlsj^y_{~8D-F(J!bZYEWEC#$Z* zdpVykt*qdec-H}^KOsxYko$(v|HWc+PgRD$=dR}I-bt!;iNV(q_l81V_>?RDKUKhx zE{c55O|A>2nHG>fEHL-k^_NF+W=CQfyiygG(+fyE4|6nk%)K-GD97~1J$PR$EHr@b z5}9otHw?I))+|=#02u8!<2lC}ggo}Kzu-78V&bMbWMO2UN#%1347e)(#<_org}@?Kb5uWi=Xm%BSveysr`gY#`Y-Y;tVsX> diff --git a/gui/__pycache__/MiniGameSelectionScreen.cpython-310.pyc b/gui/__pycache__/MiniGameSelectionScreen.cpython-310.pyc deleted file mode 100644 index 79407a415b49cf94a6d75fac0fcb301428feac3d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2478 zcmah~O>g5w7`7cJandwh$^juRBZ0IVi8iS00V;&3x~SR%A=)gLAh4#MNiyJgyfgML ziS|Z+NcXth_&b)6kT@ZZ9FREizT^0VqybBwWIo=Hd7kHeEe{X77Chhn^(+6mWm&)B zr2aHu@)^APeHfUj^<E!L$QWDG3Fjn$P1Ay;3A>W38q)xoya_Ro)3B~U0J=S5xc4w z8N6TH3ez|L^8q@EmGxMjK31cC6EBG{xvlkk`*5urWSvb-%4nwq3e=Pb4hPQqw!G#z zRk76koQ#zWxYir}V>RB_MU~446-O(%S9p!7f^4Cfw={lIvwZ++26aCLR8YQ!dh>Jv z$daDQZI08x$#LpI*4tnmEoj8Ts%yQ2XAWRk-`|JUmPO_wNB@TvJqGZ0;hH2=K~F@c z|LY!O#ZLkmG3YMPnsN+`GL|WH5D-*pe7!1lS-~)tI@z%=O-kGdG+QjLyn`_U$dHhx zQLx~w=4>xjCZjzpnLX^wc;U*~zX|H!LC_n?3K%YNrL1 z{TyYHShw~o=n9)w@XIb!pZ_2>Lfg6RLO~5DEYyVtf=+l@V~tA@w?gBWT{Oc!iW??z2=Rs&fbM z9-1NECk5WU*8Wag93Bl0ut#Ho`hM2+{iS4Si2r-O|1729W~c4@Oa`#*;+HFHKy9lw zW`TWO9pZ3=!!Zu{aj6a1b@d^T&rObPw c5DA#x;W6_*$#eY_+nmN0=UJZJxBF-R06!9;_5c6? diff --git a/gui/__pycache__/PlayerSelectionScreen.cpython-310.pyc b/gui/__pycache__/PlayerSelectionScreen.cpython-310.pyc deleted file mode 100644 index 097168726f4899e58212a2339355701a52a2b36a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2140 zcma)7Pmdcl6!%QBn@PI6Ra?OkSqMZU(VeR8p8b$^xs1GHCu^9Dr?#hM zqu$u>z_m!d^fT}c_y}`C;>4L77kJO}H)&SF(l|5r^Lx*~_j|vn{rwSv@ypvk#NAy& z{=|>&=)uRA@R*Nb;)Ht%nU%lZ%=?CLpZ6{a@BQr0eC|!jxc?W}kx7hmcQk$;!>S-N zj}tsG>v3Q7=ir6+FZ;6{zQcDf$!wPo+-kswusRUIn;|E^dLH2;h;gm>;51faHCv2~Be2{VQ+S;`i|P;1U&uKZ%qy-skD+M za#ev;rn3PwAZ08|0jO8fo;#>Eb2QaGT|t;;O99w+?t0aI-}6JygiIF*B8RXp)&jhh z7e+6Wv8Rz;W54JF%5(Sej_4g&`zH#&1N2R}kZj4M3ZDw|qg7dWtdc}5L^#bfdcSw~ z-h=S?WJ(|0fAlcSwE6*fb!VxtnBgLq;Z_(9vx_2#A_j#Qq(^^;Jssr#k_SqAtPYWwDaw*e_=t!#1Kp+$s^#7qcpVvCE z1=%Ld=^CzWvmJR$;OY&IR2nLN5;3S#H^dcP+#c&l7G}NXvQpG7NMVNcXwrTzY_8J{ zy_hI_4rw<=c&hn$&ZOyzDQ3ZPlg`&m)t@$hDh;1+tUle&=ZzDS@d#BV1wKYmF^VFfWS-#rUKG8^SyJr` zqKK;)mV59|p$C}D5T|P}6+77lY!<;QEun}i?xcyjsIm1lsue1y*@Gz{eg7Z`h6kgA jTW)9ED|WLBYzuv(w%+EZ2)-yYe2g+?&~rcn@22-3I8jz? diff --git a/gui/__pycache__/PlayerSelectionScreen.cpython-311.pyc b/gui/__pycache__/PlayerSelectionScreen.cpython-311.pyc deleted file mode 100644 index 04280fe153e5e7a63c727f52d6907c3201ad02b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2363 zcma)8JCEB&5MEN$H@ehSOrLxPQj&elgun%I-L&5QX1}ZSM&Jho1uQ(*k}_N z-~aHtxYHoy4_p+($tS0`VRB43;g(MZ+1(mgHn~r@eMETerA^4s@Xf}+=GH#xIDg`@ z@8wU;t(GrN_h52N1Q}SI;Q2v~+rk;yymsUa>fAXZg9fjgCk=Sgw25dvS}Rm>^3no} z@XdxrcoQtP(zo|~b|}=o@P!x4FxdB$5W)1HHifZrk9t1Snod~2#zNEhK+wqOpt?{( zWe^KBVxFMk$edtN)s8$WFmrCckj#it7O=XRQL#ZbZZh~^19rUTWeWuvo0Mq&s zh#8r0l6O1LomZ`^C+2esPl;Eu8WuP=*@4o;3dFjyr@xl@xVuQYDC2EGwd)#?@k=^~ zicS(gmf5Ke9Wul$%rHBL>jHowjg+|Mg#m}$1Ba`vy->#s8@qXh(ZU0!M8QKa1*F94 zLe^I*`acm!P!pol7%NpRkm+V#Ob@cEnSQt$(zB=DK_%EC0N8D^w)MQBu(hRYWr_Va zwCoFDMujf2aw3DA>`1I@&?-VM=>G$EG%7mA3V=&9duQOS${y)^HbiJ08W=AE>M`FJ z{HEzArjN)VO5$o?2~Wr;f>%f{C#y7%X0V$u(=n+RDkXG;>4w5uNE(D*B1xsD;yd9% zpIS6=K_yo|TWDVB^%<3UZ(V^DdRUCo?S~>xRIt=D`eA$kZkLDfSLNa%lX|hO;^w!^ zPsBZ?LbXeKS#z(vg&>14HeD?5El;5LajIA_Ht&M76<1;1SL?t$AoeD5a)H=eS?}L3 zUMrgBUzD*O{*1oj~vgP4`q+-cNXbAn>KS?|2~a!%m3 zEH1U`TXRy1D{s}eUVJboa9b81lltY^y`%ogN4)}q3S z&-_EUE1%!AKFyH$OkITy#9#M7%xjiqy(SwobG;_(Gjq-D+t$rFIWPXgXMeBQFsA+m D0{)R& diff --git a/gui/random.html b/gui/random.html deleted file mode 100644 index 50c8f4f36..000000000 --- a/gui/random.html +++ /dev/null @@ -1,568 +0,0 @@ - - - - -Python: module random - - - - - -
 
random
index
/usr/local/Cellar/python@3.11/3.11.6_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/random.py
-

Random variable generators.

-    bytes
-    -----
-           uniform bytes (values between 0 and 255)

-    integers
-    --------
-           uniform within range

-    sequences
-    ---------
-           pick random element
-           pick random sample
-           pick weighted random sample
-           generate random permutation

-    distributions on the real line:
-    ------------------------------
-           uniform
-           triangular
-           normal (Gaussian)
-           lognormal
-           negative exponential
-           gamma
-           beta
-           pareto
-           Weibull

-    distributions on the circle (angles 0 to 2pi)
-    ---------------------------------------------
-           circular uniform
-           von Mises

-General notes on the underlying Mersenne Twister core generator:

-* The period is 2**19937-1.
-* It is one of the most extensively tested generators in existence.
-* The random() method is implemented in C, executes in a single Python step,
-  and is, therefore, threadsafe.

-

- - - - - -
 
Modules
       
os
-
_random
-

- - - - - -
 
Classes
       
-
_random.Random(builtins.object) -
-
-
Random -
-
-
SystemRandom -
-
-
-
-
-

- - - - - - - -
 
class Random(_random.Random)
   Random(x=None)

-Random number generator base class used by bound module functions.

-Used to instantiate instances of Random to get generators that don't
-share state.

-Class Random can also be subclassed if you want to use a different basic
-generator of your own devising: in that case, override the following
-methods:  random(), seed(), getstate(), and setstate().
-Optionally, implement a getrandbits() method so that randrange()
-can cover arbitrarily large ranges.
 
 
Method resolution order:
-
Random
-
_random.Random
-
builtins.object
-
-
-Methods defined here:
-
__getstate__(self)
Helper for pickle.
- -
__init__(self, x=None)
Initialize an instance.

-Optional argument x controls seeding, as for Random.seed().
- -
__reduce__(self)
Helper for pickle.
- -
__setstate__(self, state)
- -
betavariate(self, alpha, beta)
Beta distribution.

-Conditions on the parameters are alpha > 0 and beta > 0.
-Returned values range between 0 and 1.
- -
choice(self, seq)
Choose a random element from a non-empty sequence.
- -
choices(self, population, weights=None, *, cum_weights=None, k=1)
Return a k sized list of population elements chosen with replacement.

-If the relative weights or cumulative weights are not specified,
-the selections are made with equal probability.
- -
expovariate(self, lambd)
Exponential distribution.

-lambd is 1.0 divided by the desired mean.  It should be
-nonzero.  (The parameter would be called "lambda", but that is
-a reserved word in Python.)  Returned values range from 0 to
-positive infinity if lambd is positive, and from negative
-infinity to 0 if lambd is negative.
- -
gammavariate(self, alpha, beta)
Gamma distribution.  Not the gamma function!

-Conditions on the parameters are alpha > 0 and beta > 0.

-The probability distribution function is:

-            x ** (alpha - 1) * math.exp(-x / beta)
-  pdf(x) =  --------------------------------------
-              math.gamma(alpha) * beta ** alpha
- -
gauss(self, mu=0.0, sigma=1.0)
Gaussian distribution.

-mu is the mean, and sigma is the standard deviation.  This is
-slightly faster than the normalvariate() function.

-Not thread-safe without a lock around calls.
- -
getstate(self)
Return internal state; can be passed to setstate() later.
- -
lognormvariate(self, mu, sigma)
Log normal distribution.

-If you take the natural logarithm of this distribution, you'll get a
-normal distribution with mean mu and standard deviation sigma.
-mu can have any value, and sigma must be greater than zero.
- -
normalvariate(self, mu=0.0, sigma=1.0)
Normal distribution.

-mu is the mean, and sigma is the standard deviation.
- -
paretovariate(self, alpha)
Pareto distribution.  alpha is the shape parameter.
- -
randbytes(self, n)
Generate n random bytes.
- -
randint(self, a, b)
Return random integer in range [a, b], including both end points.
- -
randrange(self, start, stop=None, step=1)
Choose a random item from range(stop) or range(start, stop[, step]).

-Roughly equivalent to ``choice(range(start, stop, step))`` but
-supports arbitrarily large ranges and is optimized for common cases.
- -
sample(self, population, k, *, counts=None)
Chooses k unique random elements from a population sequence.

-Returns a new list containing elements from the population while
-leaving the original population unchanged.  The resulting list is
-in selection order so that all sub-slices will also be valid random
-samples.  This allows raffle winners (the sample) to be partitioned
-into grand prize and second place winners (the subslices).

-Members of the population need not be hashable or unique.  If the
-population contains repeats, then each occurrence is a possible
-selection in the sample.

-Repeated elements can be specified one at a time or with the optional
-counts parameter.  For example:

-    sample(['red', 'blue'], counts=[4, 2], k=5)

-is equivalent to:

-    sample(['red', 'red', 'red', 'red', 'blue', 'blue'], k=5)

-To choose a sample from a range of integers, use range() for the
-population argument.  This is especially fast and space efficient
-for sampling from a large population:

-    sample(range(10000000), 60)
- -
seed(self, a=None, version=2)
Initialize internal state from a seed.

-The only supported seed types are None, int, float,
-str, bytes, and bytearray.

-None or no argument seeds from current time or from an operating
-system specific randomness source if available.

-If *a* is an int, all bits are used.

-For version 2 (the default), all of the bits are used if *a* is a str,
-bytes, or bytearray.  For version 1 (provided for reproducing random
-sequences from older versions of Python), the algorithm for str and
-bytes generates a narrower range of seeds.
- -
setstate(self, state)
Restore internal state from object returned by getstate().
- -
shuffle(self, x)
Shuffle list x in place, and return None.
- -
triangular(self, low=0.0, high=1.0, mode=None)
Triangular distribution.

-Continuous distribution bounded by given lower and upper limits,
-and having a given mode value in-between.

-http://en.wikipedia.org/wiki/Triangular_distribution
- -
uniform(self, a, b)
Get a random number in the range [a, b) or [a, b] depending on rounding.
- -
vonmisesvariate(self, mu, kappa)
Circular data distribution.

-mu is the mean angle, expressed in radians between 0 and 2*pi, and
-kappa is the concentration parameter, which must be greater than or
-equal to zero.  If kappa is equal to zero, this distribution reduces
-to a uniform random angle over the range 0 to 2*pi.
- -
weibullvariate(self, alpha, beta)
Weibull distribution.

-alpha is the scale parameter and beta is the shape parameter.
- -
-Class methods defined here:
-
__init_subclass__(**kwargs) from builtins.type
Control how subclasses generate random integers.

-The algorithm a subclass can use depends on the random() and/or
-getrandbits() implementation available to it and determines
-whether it can generate random integers from arbitrarily large
-ranges.
- -
-Data descriptors defined here:
-
__dict__
-
dictionary for instance variables (if defined)
-
-
__weakref__
-
list of weak references to the object (if defined)
-
-
-Data and other attributes defined here:
-
VERSION = 3
- -
-Methods inherited from _random.Random:
-
getrandbits(self, k, /)
getrandbits(k) -> x.  Generates an int with k random bits.
- -
random(self, /)
random() -> x in the interval [0, 1).
- -
-Static methods inherited from _random.Random:
-
__new__(*args, **kwargs) from builtins.type
Create and return a new object.  See help(type) for accurate signature.
- -

- - - - - - - -
 
class SystemRandom(Random)
   SystemRandom(x=None)

-Alternate random number generator using sources provided
-by the operating system (such as /dev/urandom on Unix or
-CryptGenRandom on Windows).

- Not available on all systems (see os.urandom() for details).
 
 
Method resolution order:
-
SystemRandom
-
Random
-
_random.Random
-
builtins.object
-
-
-Methods defined here:
-
getrandbits(self, k)
getrandbits(k) -> x.  Generates an int with k random bits.
- -
getstate = _notimplemented(self, *args, **kwds)
- -
randbytes(self, n)
Generate n random bytes.
- -
random(self)
Get the next random number in the range 0.0 <= X < 1.0.
- -
seed(self, *args, **kwds)
Stub method.  Not used for a system random number generator.
- -
setstate = _notimplemented(self, *args, **kwds)
- -
-Methods inherited from Random:
-
__getstate__(self)
Helper for pickle.
- -
__init__(self, x=None)
Initialize an instance.

-Optional argument x controls seeding, as for Random.seed().
- -
__reduce__(self)
Helper for pickle.
- -
__setstate__(self, state)
- -
betavariate(self, alpha, beta)
Beta distribution.

-Conditions on the parameters are alpha > 0 and beta > 0.
-Returned values range between 0 and 1.
- -
choice(self, seq)
Choose a random element from a non-empty sequence.
- -
choices(self, population, weights=None, *, cum_weights=None, k=1)
Return a k sized list of population elements chosen with replacement.

-If the relative weights or cumulative weights are not specified,
-the selections are made with equal probability.
- -
expovariate(self, lambd)
Exponential distribution.

-lambd is 1.0 divided by the desired mean.  It should be
-nonzero.  (The parameter would be called "lambda", but that is
-a reserved word in Python.)  Returned values range from 0 to
-positive infinity if lambd is positive, and from negative
-infinity to 0 if lambd is negative.
- -
gammavariate(self, alpha, beta)
Gamma distribution.  Not the gamma function!

-Conditions on the parameters are alpha > 0 and beta > 0.

-The probability distribution function is:

-            x ** (alpha - 1) * math.exp(-x / beta)
-  pdf(x) =  --------------------------------------
-              math.gamma(alpha) * beta ** alpha
- -
gauss(self, mu=0.0, sigma=1.0)
Gaussian distribution.

-mu is the mean, and sigma is the standard deviation.  This is
-slightly faster than the normalvariate() function.

-Not thread-safe without a lock around calls.
- -
lognormvariate(self, mu, sigma)
Log normal distribution.

-If you take the natural logarithm of this distribution, you'll get a
-normal distribution with mean mu and standard deviation sigma.
-mu can have any value, and sigma must be greater than zero.
- -
normalvariate(self, mu=0.0, sigma=1.0)
Normal distribution.

-mu is the mean, and sigma is the standard deviation.
- -
paretovariate(self, alpha)
Pareto distribution.  alpha is the shape parameter.
- -
randint(self, a, b)
Return random integer in range [a, b], including both end points.
- -
randrange(self, start, stop=None, step=1)
Choose a random item from range(stop) or range(start, stop[, step]).

-Roughly equivalent to ``choice(range(start, stop, step))`` but
-supports arbitrarily large ranges and is optimized for common cases.
- -
sample(self, population, k, *, counts=None)
Chooses k unique random elements from a population sequence.

-Returns a new list containing elements from the population while
-leaving the original population unchanged.  The resulting list is
-in selection order so that all sub-slices will also be valid random
-samples.  This allows raffle winners (the sample) to be partitioned
-into grand prize and second place winners (the subslices).

-Members of the population need not be hashable or unique.  If the
-population contains repeats, then each occurrence is a possible
-selection in the sample.

-Repeated elements can be specified one at a time or with the optional
-counts parameter.  For example:

-    sample(['red', 'blue'], counts=[4, 2], k=5)

-is equivalent to:

-    sample(['red', 'red', 'red', 'red', 'blue', 'blue'], k=5)

-To choose a sample from a range of integers, use range() for the
-population argument.  This is especially fast and space efficient
-for sampling from a large population:

-    sample(range(10000000), 60)
- -
shuffle(self, x)
Shuffle list x in place, and return None.
- -
triangular(self, low=0.0, high=1.0, mode=None)
Triangular distribution.

-Continuous distribution bounded by given lower and upper limits,
-and having a given mode value in-between.

-http://en.wikipedia.org/wiki/Triangular_distribution
- -
uniform(self, a, b)
Get a random number in the range [a, b) or [a, b] depending on rounding.
- -
vonmisesvariate(self, mu, kappa)
Circular data distribution.

-mu is the mean angle, expressed in radians between 0 and 2*pi, and
-kappa is the concentration parameter, which must be greater than or
-equal to zero.  If kappa is equal to zero, this distribution reduces
-to a uniform random angle over the range 0 to 2*pi.
- -
weibullvariate(self, alpha, beta)
Weibull distribution.

-alpha is the scale parameter and beta is the shape parameter.
- -
-Class methods inherited from Random:
-
__init_subclass__(**kwargs) from builtins.type
Control how subclasses generate random integers.

-The algorithm a subclass can use depends on the random() and/or
-getrandbits() implementation available to it and determines
-whether it can generate random integers from arbitrarily large
-ranges.
- -
-Data descriptors inherited from Random:
-
__dict__
-
dictionary for instance variables (if defined)
-
-
__weakref__
-
list of weak references to the object (if defined)
-
-
-Data and other attributes inherited from Random:
-
VERSION = 3
- -
-Static methods inherited from _random.Random:
-
__new__(*args, **kwargs) from builtins.type
Create and return a new object.  See help(type) for accurate signature.
- -

- - - - - -
 
Functions
       
betavariate(alpha, beta) method of Random instance
Beta distribution.

-Conditions on the parameters are alpha > 0 and beta > 0.
-Returned values range between 0 and 1.
-
choice(seq) method of Random instance
Choose a random element from a non-empty sequence.
-
choices(population, weights=None, *, cum_weights=None, k=1) method of Random instance
Return a k sized list of population elements chosen with replacement.

-If the relative weights or cumulative weights are not specified,
-the selections are made with equal probability.
-
expovariate(lambd) method of Random instance
Exponential distribution.

-lambd is 1.0 divided by the desired mean.  It should be
-nonzero.  (The parameter would be called "lambda", but that is
-a reserved word in Python.)  Returned values range from 0 to
-positive infinity if lambd is positive, and from negative
-infinity to 0 if lambd is negative.
-
gammavariate(alpha, beta) method of Random instance
Gamma distribution.  Not the gamma function!

-Conditions on the parameters are alpha > 0 and beta > 0.

-The probability distribution function is:

-            x ** (alpha - 1) * math.exp(-x / beta)
-  pdf(x) =  --------------------------------------
-              math.gamma(alpha) * beta ** alpha
-
gauss(mu=0.0, sigma=1.0) method of Random instance
Gaussian distribution.

-mu is the mean, and sigma is the standard deviation.  This is
-slightly faster than the normalvariate() function.

-Not thread-safe without a lock around calls.
-
getrandbits(k, /) method of Random instance
getrandbits(k) -> x.  Generates an int with k random bits.
-
getstate() method of Random instance
Return internal state; can be passed to setstate() later.
-
lognormvariate(mu, sigma) method of Random instance
Log normal distribution.

-If you take the natural logarithm of this distribution, you'll get a
-normal distribution with mean mu and standard deviation sigma.
-mu can have any value, and sigma must be greater than zero.
-
normalvariate(mu=0.0, sigma=1.0) method of Random instance
Normal distribution.

-mu is the mean, and sigma is the standard deviation.
-
paretovariate(alpha) method of Random instance
Pareto distribution.  alpha is the shape parameter.
-
randbytes(n) method of Random instance
Generate n random bytes.
-
randint(a, b) method of Random instance
Return random integer in range [a, b], including both end points.
-
random() method of Random instance
random() -> x in the interval [0, 1).
-
randrange(start, stop=None, step=1) method of Random instance
Choose a random item from range(stop) or range(start, stop[, step]).

-Roughly equivalent to ``choice(range(start, stop, step))`` but
-supports arbitrarily large ranges and is optimized for common cases.
-
sample(population, k, *, counts=None) method of Random instance
Chooses k unique random elements from a population sequence.

-Returns a new list containing elements from the population while
-leaving the original population unchanged.  The resulting list is
-in selection order so that all sub-slices will also be valid random
-samples.  This allows raffle winners (the sample) to be partitioned
-into grand prize and second place winners (the subslices).

-Members of the population need not be hashable or unique.  If the
-population contains repeats, then each occurrence is a possible
-selection in the sample.

-Repeated elements can be specified one at a time or with the optional
-counts parameter.  For example:

-    sample(['red', 'blue'], counts=[4, 2], k=5)

-is equivalent to:

-    sample(['red', 'red', 'red', 'red', 'blue', 'blue'], k=5)

-To choose a sample from a range of integers, use range() for the
-population argument.  This is especially fast and space efficient
-for sampling from a large population:

-    sample(range(10000000), 60)
-
seed(a=None, version=2) method of Random instance
Initialize internal state from a seed.

-The only supported seed types are None, int, float,
-str, bytes, and bytearray.

-None or no argument seeds from current time or from an operating
-system specific randomness source if available.

-If *a* is an int, all bits are used.

-For version 2 (the default), all of the bits are used if *a* is a str,
-bytes, or bytearray.  For version 1 (provided for reproducing random
-sequences from older versions of Python), the algorithm for str and
-bytes generates a narrower range of seeds.
-
setstate(state) method of Random instance
Restore internal state from object returned by getstate().
-
shuffle(x) method of Random instance
Shuffle list x in place, and return None.
-
triangular(low=0.0, high=1.0, mode=None) method of Random instance
Triangular distribution.

-Continuous distribution bounded by given lower and upper limits,
-and having a given mode value in-between.

-http://en.wikipedia.org/wiki/Triangular_distribution
-
uniform(a, b) method of Random instance
Get a random number in the range [a, b) or [a, b] depending on rounding.
-
vonmisesvariate(mu, kappa) method of Random instance
Circular data distribution.

-mu is the mean angle, expressed in radians between 0 and 2*pi, and
-kappa is the concentration parameter, which must be greater than or
-equal to zero.  If kappa is equal to zero, this distribution reduces
-to a uniform random angle over the range 0 to 2*pi.
-
weibullvariate(alpha, beta) method of Random instance
Weibull distribution.

-alpha is the scale parameter and beta is the shape parameter.
-

- - - - - -
 
Data
       __all__ = ['Random', 'SystemRandom', 'betavariate', 'choice', 'choices', 'expovariate', 'gammavariate', 'gauss', 'getrandbits', 'getstate', 'lognormvariate', 'normalvariate', 'paretovariate', 'randbytes', 'randint', 'random', 'randrange', 'sample', 'seed', 'setstate', ...]
- \ No newline at end of file diff --git a/pygame.html b/pygame.html deleted file mode 100644 index 6aa49a6c6..000000000 --- a/pygame.html +++ /dev/null @@ -1,43 +0,0 @@ - -Python: class pygame - - -

- - - - - - - -
 
-class pygame(builtins.object)
   The pygame class is where the mini-game(s) is initialized, launched/run, and terminated.
-Each component of the class is designed to operate via their respecitve functions.

-Attributes:
-None

-Methods:
-init(): void
-startGameLoop(): void
-quit(): void
 
 Methods defined here:
-
init()
The respective pygame mini-game(s) is initialized, and the method is void returning no value.
- -
quit()
This ends or terminates the game bringing the user back to the GUI or menu screen, and the method is void returning no value.
-Pre-condition: startGameLoop() is actively running.
-Post-condition: brings user back to menu screen.
- -
startGameLoop()
Launches/runs the specified pygame mini-game, and the method is void returning no value.
-Pre-condition: init() has been called to initalize the game state.
-Post-condition: The game is currently being run.
- -
-Data descriptors defined here:
-
__dict__
-
dictionary for instance variables (if defined)
-
-
__weakref__
-
list of weak references to the object (if defined)
-
-
- \ No newline at end of file diff --git a/pygame_class.py b/pygame_class.py deleted file mode 100644 index bf67f5bb6..000000000 --- a/pygame_class.py +++ /dev/null @@ -1,40 +0,0 @@ -import pygame_class -import pydoc - -class pygame_class: - """ - The pygame class is where the mini-game(s) is initialized, launched/run, and terminated. - Each component of the class is designed to operate via their respecitve functions. - - Attributes: - None - - Methods: - init(): void - startGameLoop(): void - quit(): void - """ - - def init(): - """ - The respective pygame mini-game(s) is initialized, and the method is void returning no value. - """ - return - - def startGameLoop(): - """ - Launches/runs the specified pygame mini-game, and the method is void returning no value. - Pre-condition: init() has been called to initalize the game state. - Post-condition: The game is currently being run. - """ - return - - def quit(): - """ - This ends or terminates the game bringing the user back to the GUI or menu screen, and the method is void returning no value. - Pre-condition: startGameLoop() is actively running. - Post-condition: brings user back to menu screen. - """ - return - -pydoc.writedoc("pygame_class.py") \ No newline at end of file diff --git a/random.html b/random.html deleted file mode 100644 index 50c8f4f36..000000000 --- a/random.html +++ /dev/null @@ -1,568 +0,0 @@ - - - - -Python: module random - - - - - -
 
random
index
/usr/local/Cellar/python@3.11/3.11.6_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/random.py
-

Random variable generators.

-    bytes
-    -----
-           uniform bytes (values between 0 and 255)

-    integers
-    --------
-           uniform within range

-    sequences
-    ---------
-           pick random element
-           pick random sample
-           pick weighted random sample
-           generate random permutation

-    distributions on the real line:
-    ------------------------------
-           uniform
-           triangular
-           normal (Gaussian)
-           lognormal
-           negative exponential
-           gamma
-           beta
-           pareto
-           Weibull

-    distributions on the circle (angles 0 to 2pi)
-    ---------------------------------------------
-           circular uniform
-           von Mises

-General notes on the underlying Mersenne Twister core generator:

-* The period is 2**19937-1.
-* It is one of the most extensively tested generators in existence.
-* The random() method is implemented in C, executes in a single Python step,
-  and is, therefore, threadsafe.

-

- - - - - -
 
Modules
       
os
-
_random
-

- - - - - -
 
Classes
       
-
_random.Random(builtins.object) -
-
-
Random -
-
-
SystemRandom -
-
-
-
-
-

- - - - - - - -
 
class Random(_random.Random)
   Random(x=None)

-Random number generator base class used by bound module functions.

-Used to instantiate instances of Random to get generators that don't
-share state.

-Class Random can also be subclassed if you want to use a different basic
-generator of your own devising: in that case, override the following
-methods:  random(), seed(), getstate(), and setstate().
-Optionally, implement a getrandbits() method so that randrange()
-can cover arbitrarily large ranges.
 
 
Method resolution order:
-
Random
-
_random.Random
-
builtins.object
-
-
-Methods defined here:
-
__getstate__(self)
Helper for pickle.
- -
__init__(self, x=None)
Initialize an instance.

-Optional argument x controls seeding, as for Random.seed().
- -
__reduce__(self)
Helper for pickle.
- -
__setstate__(self, state)
- -
betavariate(self, alpha, beta)
Beta distribution.

-Conditions on the parameters are alpha > 0 and beta > 0.
-Returned values range between 0 and 1.
- -
choice(self, seq)
Choose a random element from a non-empty sequence.
- -
choices(self, population, weights=None, *, cum_weights=None, k=1)
Return a k sized list of population elements chosen with replacement.

-If the relative weights or cumulative weights are not specified,
-the selections are made with equal probability.
- -
expovariate(self, lambd)
Exponential distribution.

-lambd is 1.0 divided by the desired mean.  It should be
-nonzero.  (The parameter would be called "lambda", but that is
-a reserved word in Python.)  Returned values range from 0 to
-positive infinity if lambd is positive, and from negative
-infinity to 0 if lambd is negative.
- -
gammavariate(self, alpha, beta)
Gamma distribution.  Not the gamma function!

-Conditions on the parameters are alpha > 0 and beta > 0.

-The probability distribution function is:

-            x ** (alpha - 1) * math.exp(-x / beta)
-  pdf(x) =  --------------------------------------
-              math.gamma(alpha) * beta ** alpha
- -
gauss(self, mu=0.0, sigma=1.0)
Gaussian distribution.

-mu is the mean, and sigma is the standard deviation.  This is
-slightly faster than the normalvariate() function.

-Not thread-safe without a lock around calls.
- -
getstate(self)
Return internal state; can be passed to setstate() later.
- -
lognormvariate(self, mu, sigma)
Log normal distribution.

-If you take the natural logarithm of this distribution, you'll get a
-normal distribution with mean mu and standard deviation sigma.
-mu can have any value, and sigma must be greater than zero.
- -
normalvariate(self, mu=0.0, sigma=1.0)
Normal distribution.

-mu is the mean, and sigma is the standard deviation.
- -
paretovariate(self, alpha)
Pareto distribution.  alpha is the shape parameter.
- -
randbytes(self, n)
Generate n random bytes.
- -
randint(self, a, b)
Return random integer in range [a, b], including both end points.
- -
randrange(self, start, stop=None, step=1)
Choose a random item from range(stop) or range(start, stop[, step]).

-Roughly equivalent to ``choice(range(start, stop, step))`` but
-supports arbitrarily large ranges and is optimized for common cases.
- -
sample(self, population, k, *, counts=None)
Chooses k unique random elements from a population sequence.

-Returns a new list containing elements from the population while
-leaving the original population unchanged.  The resulting list is
-in selection order so that all sub-slices will also be valid random
-samples.  This allows raffle winners (the sample) to be partitioned
-into grand prize and second place winners (the subslices).

-Members of the population need not be hashable or unique.  If the
-population contains repeats, then each occurrence is a possible
-selection in the sample.

-Repeated elements can be specified one at a time or with the optional
-counts parameter.  For example:

-    sample(['red', 'blue'], counts=[4, 2], k=5)

-is equivalent to:

-    sample(['red', 'red', 'red', 'red', 'blue', 'blue'], k=5)

-To choose a sample from a range of integers, use range() for the
-population argument.  This is especially fast and space efficient
-for sampling from a large population:

-    sample(range(10000000), 60)
- -
seed(self, a=None, version=2)
Initialize internal state from a seed.

-The only supported seed types are None, int, float,
-str, bytes, and bytearray.

-None or no argument seeds from current time or from an operating
-system specific randomness source if available.

-If *a* is an int, all bits are used.

-For version 2 (the default), all of the bits are used if *a* is a str,
-bytes, or bytearray.  For version 1 (provided for reproducing random
-sequences from older versions of Python), the algorithm for str and
-bytes generates a narrower range of seeds.
- -
setstate(self, state)
Restore internal state from object returned by getstate().
- -
shuffle(self, x)
Shuffle list x in place, and return None.
- -
triangular(self, low=0.0, high=1.0, mode=None)
Triangular distribution.

-Continuous distribution bounded by given lower and upper limits,
-and having a given mode value in-between.

-http://en.wikipedia.org/wiki/Triangular_distribution
- -
uniform(self, a, b)
Get a random number in the range [a, b) or [a, b] depending on rounding.
- -
vonmisesvariate(self, mu, kappa)
Circular data distribution.

-mu is the mean angle, expressed in radians between 0 and 2*pi, and
-kappa is the concentration parameter, which must be greater than or
-equal to zero.  If kappa is equal to zero, this distribution reduces
-to a uniform random angle over the range 0 to 2*pi.
- -
weibullvariate(self, alpha, beta)
Weibull distribution.

-alpha is the scale parameter and beta is the shape parameter.
- -
-Class methods defined here:
-
__init_subclass__(**kwargs) from builtins.type
Control how subclasses generate random integers.

-The algorithm a subclass can use depends on the random() and/or
-getrandbits() implementation available to it and determines
-whether it can generate random integers from arbitrarily large
-ranges.
- -
-Data descriptors defined here:
-
__dict__
-
dictionary for instance variables (if defined)
-
-
__weakref__
-
list of weak references to the object (if defined)
-
-
-Data and other attributes defined here:
-
VERSION = 3
- -
-Methods inherited from _random.Random:
-
getrandbits(self, k, /)
getrandbits(k) -> x.  Generates an int with k random bits.
- -
random(self, /)
random() -> x in the interval [0, 1).
- -
-Static methods inherited from _random.Random:
-
__new__(*args, **kwargs) from builtins.type
Create and return a new object.  See help(type) for accurate signature.
- -

- - - - - - - -
 
class SystemRandom(Random)
   SystemRandom(x=None)

-Alternate random number generator using sources provided
-by the operating system (such as /dev/urandom on Unix or
-CryptGenRandom on Windows).

- Not available on all systems (see os.urandom() for details).
 
 
Method resolution order:
-
SystemRandom
-
Random
-
_random.Random
-
builtins.object
-
-
-Methods defined here:
-
getrandbits(self, k)
getrandbits(k) -> x.  Generates an int with k random bits.
- -
getstate = _notimplemented(self, *args, **kwds)
- -
randbytes(self, n)
Generate n random bytes.
- -
random(self)
Get the next random number in the range 0.0 <= X < 1.0.
- -
seed(self, *args, **kwds)
Stub method.  Not used for a system random number generator.
- -
setstate = _notimplemented(self, *args, **kwds)
- -
-Methods inherited from Random:
-
__getstate__(self)
Helper for pickle.
- -
__init__(self, x=None)
Initialize an instance.

-Optional argument x controls seeding, as for Random.seed().
- -
__reduce__(self)
Helper for pickle.
- -
__setstate__(self, state)
- -
betavariate(self, alpha, beta)
Beta distribution.

-Conditions on the parameters are alpha > 0 and beta > 0.
-Returned values range between 0 and 1.
- -
choice(self, seq)
Choose a random element from a non-empty sequence.
- -
choices(self, population, weights=None, *, cum_weights=None, k=1)
Return a k sized list of population elements chosen with replacement.

-If the relative weights or cumulative weights are not specified,
-the selections are made with equal probability.
- -
expovariate(self, lambd)
Exponential distribution.

-lambd is 1.0 divided by the desired mean.  It should be
-nonzero.  (The parameter would be called "lambda", but that is
-a reserved word in Python.)  Returned values range from 0 to
-positive infinity if lambd is positive, and from negative
-infinity to 0 if lambd is negative.
- -
gammavariate(self, alpha, beta)
Gamma distribution.  Not the gamma function!

-Conditions on the parameters are alpha > 0 and beta > 0.

-The probability distribution function is:

-            x ** (alpha - 1) * math.exp(-x / beta)
-  pdf(x) =  --------------------------------------
-              math.gamma(alpha) * beta ** alpha
- -
gauss(self, mu=0.0, sigma=1.0)
Gaussian distribution.

-mu is the mean, and sigma is the standard deviation.  This is
-slightly faster than the normalvariate() function.

-Not thread-safe without a lock around calls.
- -
lognormvariate(self, mu, sigma)
Log normal distribution.

-If you take the natural logarithm of this distribution, you'll get a
-normal distribution with mean mu and standard deviation sigma.
-mu can have any value, and sigma must be greater than zero.
- -
normalvariate(self, mu=0.0, sigma=1.0)
Normal distribution.

-mu is the mean, and sigma is the standard deviation.
- -
paretovariate(self, alpha)
Pareto distribution.  alpha is the shape parameter.
- -
randint(self, a, b)
Return random integer in range [a, b], including both end points.
- -
randrange(self, start, stop=None, step=1)
Choose a random item from range(stop) or range(start, stop[, step]).

-Roughly equivalent to ``choice(range(start, stop, step))`` but
-supports arbitrarily large ranges and is optimized for common cases.
- -
sample(self, population, k, *, counts=None)
Chooses k unique random elements from a population sequence.

-Returns a new list containing elements from the population while
-leaving the original population unchanged.  The resulting list is
-in selection order so that all sub-slices will also be valid random
-samples.  This allows raffle winners (the sample) to be partitioned
-into grand prize and second place winners (the subslices).

-Members of the population need not be hashable or unique.  If the
-population contains repeats, then each occurrence is a possible
-selection in the sample.

-Repeated elements can be specified one at a time or with the optional
-counts parameter.  For example:

-    sample(['red', 'blue'], counts=[4, 2], k=5)

-is equivalent to:

-    sample(['red', 'red', 'red', 'red', 'blue', 'blue'], k=5)

-To choose a sample from a range of integers, use range() for the
-population argument.  This is especially fast and space efficient
-for sampling from a large population:

-    sample(range(10000000), 60)
- -
shuffle(self, x)
Shuffle list x in place, and return None.
- -
triangular(self, low=0.0, high=1.0, mode=None)
Triangular distribution.

-Continuous distribution bounded by given lower and upper limits,
-and having a given mode value in-between.

-http://en.wikipedia.org/wiki/Triangular_distribution
- -
uniform(self, a, b)
Get a random number in the range [a, b) or [a, b] depending on rounding.
- -
vonmisesvariate(self, mu, kappa)
Circular data distribution.

-mu is the mean angle, expressed in radians between 0 and 2*pi, and
-kappa is the concentration parameter, which must be greater than or
-equal to zero.  If kappa is equal to zero, this distribution reduces
-to a uniform random angle over the range 0 to 2*pi.
- -
weibullvariate(self, alpha, beta)
Weibull distribution.

-alpha is the scale parameter and beta is the shape parameter.
- -
-Class methods inherited from Random:
-
__init_subclass__(**kwargs) from builtins.type
Control how subclasses generate random integers.

-The algorithm a subclass can use depends on the random() and/or
-getrandbits() implementation available to it and determines
-whether it can generate random integers from arbitrarily large
-ranges.
- -
-Data descriptors inherited from Random:
-
__dict__
-
dictionary for instance variables (if defined)
-
-
__weakref__
-
list of weak references to the object (if defined)
-
-
-Data and other attributes inherited from Random:
-
VERSION = 3
- -
-Static methods inherited from _random.Random:
-
__new__(*args, **kwargs) from builtins.type
Create and return a new object.  See help(type) for accurate signature.
- -

- - - - - -
 
Functions
       
betavariate(alpha, beta) method of Random instance
Beta distribution.

-Conditions on the parameters are alpha > 0 and beta > 0.
-Returned values range between 0 and 1.
-
choice(seq) method of Random instance
Choose a random element from a non-empty sequence.
-
choices(population, weights=None, *, cum_weights=None, k=1) method of Random instance
Return a k sized list of population elements chosen with replacement.

-If the relative weights or cumulative weights are not specified,
-the selections are made with equal probability.
-
expovariate(lambd) method of Random instance
Exponential distribution.

-lambd is 1.0 divided by the desired mean.  It should be
-nonzero.  (The parameter would be called "lambda", but that is
-a reserved word in Python.)  Returned values range from 0 to
-positive infinity if lambd is positive, and from negative
-infinity to 0 if lambd is negative.
-
gammavariate(alpha, beta) method of Random instance
Gamma distribution.  Not the gamma function!

-Conditions on the parameters are alpha > 0 and beta > 0.

-The probability distribution function is:

-            x ** (alpha - 1) * math.exp(-x / beta)
-  pdf(x) =  --------------------------------------
-              math.gamma(alpha) * beta ** alpha
-
gauss(mu=0.0, sigma=1.0) method of Random instance
Gaussian distribution.

-mu is the mean, and sigma is the standard deviation.  This is
-slightly faster than the normalvariate() function.

-Not thread-safe without a lock around calls.
-
getrandbits(k, /) method of Random instance
getrandbits(k) -> x.  Generates an int with k random bits.
-
getstate() method of Random instance
Return internal state; can be passed to setstate() later.
-
lognormvariate(mu, sigma) method of Random instance
Log normal distribution.

-If you take the natural logarithm of this distribution, you'll get a
-normal distribution with mean mu and standard deviation sigma.
-mu can have any value, and sigma must be greater than zero.
-
normalvariate(mu=0.0, sigma=1.0) method of Random instance
Normal distribution.

-mu is the mean, and sigma is the standard deviation.
-
paretovariate(alpha) method of Random instance
Pareto distribution.  alpha is the shape parameter.
-
randbytes(n) method of Random instance
Generate n random bytes.
-
randint(a, b) method of Random instance
Return random integer in range [a, b], including both end points.
-
random() method of Random instance
random() -> x in the interval [0, 1).
-
randrange(start, stop=None, step=1) method of Random instance
Choose a random item from range(stop) or range(start, stop[, step]).

-Roughly equivalent to ``choice(range(start, stop, step))`` but
-supports arbitrarily large ranges and is optimized for common cases.
-
sample(population, k, *, counts=None) method of Random instance
Chooses k unique random elements from a population sequence.

-Returns a new list containing elements from the population while
-leaving the original population unchanged.  The resulting list is
-in selection order so that all sub-slices will also be valid random
-samples.  This allows raffle winners (the sample) to be partitioned
-into grand prize and second place winners (the subslices).

-Members of the population need not be hashable or unique.  If the
-population contains repeats, then each occurrence is a possible
-selection in the sample.

-Repeated elements can be specified one at a time or with the optional
-counts parameter.  For example:

-    sample(['red', 'blue'], counts=[4, 2], k=5)

-is equivalent to:

-    sample(['red', 'red', 'red', 'red', 'blue', 'blue'], k=5)

-To choose a sample from a range of integers, use range() for the
-population argument.  This is especially fast and space efficient
-for sampling from a large population:

-    sample(range(10000000), 60)
-
seed(a=None, version=2) method of Random instance
Initialize internal state from a seed.

-The only supported seed types are None, int, float,
-str, bytes, and bytearray.

-None or no argument seeds from current time or from an operating
-system specific randomness source if available.

-If *a* is an int, all bits are used.

-For version 2 (the default), all of the bits are used if *a* is a str,
-bytes, or bytearray.  For version 1 (provided for reproducing random
-sequences from older versions of Python), the algorithm for str and
-bytes generates a narrower range of seeds.
-
setstate(state) method of Random instance
Restore internal state from object returned by getstate().
-
shuffle(x) method of Random instance
Shuffle list x in place, and return None.
-
triangular(low=0.0, high=1.0, mode=None) method of Random instance
Triangular distribution.

-Continuous distribution bounded by given lower and upper limits,
-and having a given mode value in-between.

-http://en.wikipedia.org/wiki/Triangular_distribution
-
uniform(a, b) method of Random instance
Get a random number in the range [a, b) or [a, b] depending on rounding.
-
vonmisesvariate(mu, kappa) method of Random instance
Circular data distribution.

-mu is the mean angle, expressed in radians between 0 and 2*pi, and
-kappa is the concentration parameter, which must be greater than or
-equal to zero.  If kappa is equal to zero, this distribution reduces
-to a uniform random angle over the range 0 to 2*pi.
-
weibullvariate(alpha, beta) method of Random instance
Weibull distribution.

-alpha is the scale parameter and beta is the shape parameter.
-

- - - - - -
 
Data
       __all__ = ['Random', 'SystemRandom', 'betavariate', 'choice', 'choices', 'expovariate', 'gammavariate', 'gauss', 'getrandbits', 'getstate', 'lognormvariate', 'normalvariate', 'paretovariate', 'randbytes', 'randint', 'random', 'randrange', 'sample', 'seed', 'setstate', ...]
- \ No newline at end of file From 231a4a8b28806166dbf341ac67304202b324830d Mon Sep 17 00:00:00 2001 From: JayLiuTU Date: Sun, 31 Mar 2024 20:04:07 -0400 Subject: [PATCH 07/11] mouse improvements and menu options --- source/gesture inference/GetHands.py | 7 +- source/gesture inference/Keyboard.py | 38 ++++----- source/gesture inference/Mouse.py | 34 ++++++-- source/gesture inference/RenderHands.py | 9 +- source/gesture inference/inference.py | 108 +++++++++++++++--------- 5 files changed, 124 insertions(+), 72 deletions(-) diff --git a/source/gesture inference/GetHands.py b/source/gesture inference/GetHands.py index 515ea0b4d..0e3a92ac2 100644 --- a/source/gesture inference/GetHands.py +++ b/source/gesture inference/GetHands.py @@ -33,12 +33,11 @@ def __init__( self.model_path = mediapipe_model self.render_hands = render_hands - self.confidence = 0.5 + self.confidence = 0.8 self.stopped = False self.mouse = mouse self.flags = flags - self.click_sensitinity = flags["click_sense"] self.keyboard = keyboard self.console = GestureConsole() @@ -79,7 +78,7 @@ def build_mediapipe_model(self, hands_num): num_hands=hands_num, min_hand_detection_confidence=self.confidence, min_hand_presence_confidence=self.confidence, - min_tracking_confidence=self.confidence, + min_tracking_confidence=0.5, running_mode=self.VisionRunningMode.LIVE_STREAM, result_callback=self.results_callback, ) @@ -150,6 +149,7 @@ def results_callback( self.gestures = gestures self.confidence_vectors = hand_confidences + self.keyboard.gesture_input(self.confidence_vectors[0]) self.console.table(self.gesture_list, hand_confidences) @@ -162,7 +162,6 @@ def results_callback( self.click = mouse_button_text self.mouse_location = location - # self.move_mouse(location, mouse_button_text) # timestamps are in microseconds so convert to ms diff --git a/source/gesture inference/Keyboard.py b/source/gesture inference/Keyboard.py index 64227798e..1b2aaf9d6 100644 --- a/source/gesture inference/Keyboard.py +++ b/source/gesture inference/Keyboard.py @@ -4,7 +4,7 @@ import numpy as np class Keyboard: def __init__( - self, threshold=0.0, toggle_key_threshold=0.15, toggle_key_toggle_time=1, toggle_mouse_func=None, console=None + self, threshold=0.0, toggle_key_threshold=0.15, toggle_key_toggle_time=1, toggle_mouse_func=None, flags=None, toggle_key='' ) -> None: """_summary_ @@ -28,6 +28,8 @@ def __init__( self.toggle_mouse_func = toggle_mouse_func self.toggle_key_toggle_time = toggle_key_toggle_time self.console = GestureConsole() + self.flags = flags + self.toggle_key = toggle_key def gesture_input(self, confidences): @@ -38,35 +40,33 @@ def gesture_input(self, confidences): elif max_index == 1: self.press("none") elif max_index == 2: - self.press("toggle") + self.press(self.toggle_key) def press(self, key: str): - current_time = time.time() # if it has been longer than threshold time + current_time = time.time() - # if its a new key set state to not pressed if key != self.last_key: - self.key_presed = False + self.key_pressed = False self.toggle_key_pressed = False self.last_key = key - # start timers if key == "none": return - if key == "toggle": + if key == self.toggle_key: self.last_time_toggle_key = current_time else: self.last_time = current_time - # if the toggle key has been requested for longer than the threashold - if key == "toggle": - if not self.toggle_key_pressed or current_time - self.last_time_toggle_key > self.toggle_key_toggle_time: - if current_time - self.last_time_toggle_key > self.toggle_key_threshold: - if self.toggle_mouse_func != None: - self.toggle_mouse_func() - self.toggle_key_pressed = True - self.last_time_toggle_key = current_time - - # if the non toggle key has been requested for longer than the normal threashold - elif current_time - self.last_time > self.threshold and self.key_presed == False: - self.key_presed = True + if key == self.toggle_key: + self.handle_toggle_key(current_time) + elif current_time - self.last_time > self.threshold and not self.key_pressed: + self.key_pressed = True self.console.print(f"pressing key: {key}") pyautogui.press(key, _pause=False) + + def handle_toggle_key(self, current_time): + if not self.toggle_key_pressed or current_time - self.last_time_toggle_key > self.toggle_key_toggle_time: + if current_time - self.last_time_toggle_key > self.toggle_key_threshold: + if self.toggle_mouse_func is not None: + self.toggle_mouse_func() + self.toggle_key_pressed = True + self.last_time_toggle_key = current_time diff --git a/source/gesture inference/Mouse.py b/source/gesture inference/Mouse.py index a2408a8a7..36313241c 100644 --- a/source/gesture inference/Mouse.py +++ b/source/gesture inference/Mouse.py @@ -7,9 +7,13 @@ class Mouse: def __init__( self, - mouse_sensitivity=2, + mouse_sensitivity=1, click_threshold_time=0.22, drag_threshold_time=0.2, + x_scale=1.3, + y_scale=1.5, + alpha=0.15, + deadzone=15, ) -> None: """Initialization of Mouse class. @@ -29,7 +33,11 @@ def __init__( pyautogui.FAILSAFE = False pyautogui.PAUSE = 0 - self.mouse_sensitivity = mouse_sensitivity + self.mouse_sensitivity = float(mouse_sensitivity) + self.x_scale = float(x_scale) + self.y_scale = float(y_scale) + self.deadzone = deadzone + self.click_threshold_time = click_threshold_time self.drag_threshold_time = drag_threshold_time self.left_down = False @@ -42,7 +50,7 @@ def __init__( self.x_window = [] self.y_window = [] self.window_size = 12 - self.alpha = 0.2 + self.alpha = alpha def control(self, x: float, y: float, mouse_button: str): """Moves the mouse to XY coordinates and can perform single clicks, or click and drags when called repeatelly @@ -53,14 +61,27 @@ def control(self, x: float, y: float, mouse_button: str): mouse_button (string): can be "", "left", "middle", or "right" """ x = int( - ((self.mouse_sensitivity) * x - (self.mouse_sensitivity - 1) / 2) + ( + (self.x_scale * self.mouse_sensitivity) * x + - (self.x_scale * self.mouse_sensitivity - 1) / 2 + ) * pyautogui.size().width ) y = int( - ((self.mouse_sensitivity) * y - (self.mouse_sensitivity - 1.5) / 1.5) + ( + (self.y_scale * self.mouse_sensitivity) * y + - (self.y_scale * self.mouse_sensitivity - 1) / 2 + ) * pyautogui.size().height ) + # Check if the movement is smaller than the specified radius + last_x, last_y = pyautogui.position() + distance = math.sqrt((x - last_x) ** 2 + (y - last_y) ** 2) + + # Specify the radius distance (you can adjust this value) + ignore_small_movement = distance <= self.deadzone + self.x_window.append(x) self.y_window.append(y) @@ -81,7 +102,8 @@ def control(self, x: float, y: float, mouse_button: str): if self.right_down: pyautogui.mouseUp(button="right", _pause=False) self.right_down = False - self.move(x, y) + if not ignore_small_movement: + self.move(x, y) else: # click or click and drag self.click( diff --git a/source/gesture inference/RenderHands.py b/source/gesture inference/RenderHands.py index 4f1d3af86..165542b32 100644 --- a/source/gesture inference/RenderHands.py +++ b/source/gesture inference/RenderHands.py @@ -15,6 +15,7 @@ def __init__(self, surface, render_scale=3): self.hand_scale = render_scale self.font = pygame.font.Font("freesansbold.ttf", 30) self.last_velocity = [(0.5, 0.5)] + self.thickness = 15 def set_render_scale(self, scale:float): self.hand_scale = scale @@ -85,7 +86,7 @@ def render_line(self, start, end): start (int): line start position end (int): line end position """ - pygame.draw.line(self.surface, (255, 255, 255), start, end, 5) + pygame.draw.line(self.surface, (255, 255, 255), start, end, self.thickness) def render_hands( self, result, mode, origins, velocity @@ -98,13 +99,13 @@ def render_hands( if result.handedness != []: if mode: hand_points = result.hand_world_landmarks - pygame.draw.circle(self.surface, (255, 0, 255), (0.5 * w, 0.5 * h), 5) + pygame.draw.circle(self.surface, (255, 0, 255), (0.5 * w, 0.5 * h), 10) pygame.draw.line( self.surface, (255, 255, 0), ((velocity[0][0] + 0.5) * w, (velocity[0][1] + 0.5) * h), ((0.5) * w, (0.5) * h), - 3, + 10, ) self.last_velocity = velocity @@ -155,5 +156,5 @@ def __render_hands_pygame(self, color, x, y, mode): x += 0.5 y += 0.5 - pygame.draw.circle(self.surface, color, (x * w, y * h), 5) + pygame.draw.circle(self.surface, color, (x * w, y * h), self.thickness//2) diff --git a/source/gesture inference/inference.py b/source/gesture inference/inference.py index 7791fbc7f..b67d04ba3 100644 --- a/source/gesture inference/inference.py +++ b/source/gesture inference/inference.py @@ -13,6 +13,7 @@ from Keyboard import Keyboard import os from Console import GestureConsole +import textwrap abspath = os.path.abspath(__file__) dname = os.path.dirname(abspath) @@ -24,13 +25,13 @@ clock = pygame.time.Clock() flags = { - "render_hands_mode": False, + "render_hands_mode": True, "gesture_vector": [], "number_of_hands": 2, "move_mouse_flag": False, "run_model_flag": True, "gesture_model_path": "simple.pth", - "click_sense": 0.06, + "click_sense": 0.05, "hands": None, } @@ -50,7 +51,7 @@ def main() -> None: myRenderHands = RenderHands(hands_surface, render_scale=3) - mouse = Mouse(mouse_sensitivity=2) + mouse = Mouse() keyboard = Keyboard( threshold=0, toggle_key_threshold=0.3, toggle_mouse_func=toggle_mouse @@ -72,7 +73,7 @@ def main() -> None: ) menu.add.selector( - "Render Mode :", [("World", False), ("Normalized", True)], onchange=set_coords + "Render Mode :", [("Normalized", True),("World", False)], onchange=set_coords ) def change_mouse_smooth(value, smooth): @@ -106,19 +107,19 @@ def change_gesture_model(value): def set_click_sense(value, **kwargs): nonlocal hands - flags["click_sense"] = value / 100 - hands.click_sensitinity = flags["click_sense"] + print(value) + flags["click_sense"] = value / 1000 - menu.add.range_slider( + menu.add.range_slider( "Click Sensitivity", - default=60, - range_values=(1, 100), - increment=0.01, + default=70, + range_values=(1, 150), + increment=1, onchange=set_click_sense, ) def build_hands(): - nonlocal hands + nonlocal hands nonlocal mouse nonlocal keyboard hands.stop() @@ -143,14 +144,14 @@ def build_hands(): hands_surface, menu, mouse, + keyboard, ) pygame.quit() def find_files_with_ending(ending: str, directory_path=os.getcwd()): - """returns a list of tuples of the strings found - """ + """returns a list of tuples of the strings found""" files = [(file,) for file in os.listdir(directory_path) if file.endswith(ending)] return files @@ -181,7 +182,8 @@ def game_loop( hands: GetHands, hands_surface: pygame.Surface, menu: pygame_menu.Menu, - mouse_controls: Mouse, + mouse: Mouse, + keyboard: Keyboard ): """Runs the pygame event loop and renders surfaces @@ -194,11 +196,16 @@ def game_loop( hands.start() running = True is_menu_showing = True - is_webcam_fullscreen = False - + webcam_mode = 0 + show_debug_text = True is_fullscreen = False counter = 0 delay_AI = None + + wrapper = textwrap.TextWrapper(width=20) + instructions = "F1 to change webcam place. F2 to hide this text. F3 to change hand render mode. 'M' to toggle mouse control. 'G' to toggle gesture model." + instructions = wrapper.wrap(text=instructions) + while running: counter += 1 @@ -228,17 +235,29 @@ def game_loop( menu.enable() if event.key == pygame.K_F1: - is_webcam_fullscreen = not is_webcam_fullscreen + webcam_mode += 1 + + if event.key == pygame.K_F2: + show_debug_text = not show_debug_text + + if event.key == pygame.K_F3: + flags["render_hands_mode"] = not flags["render_hands_mode"] if event.key == pygame.K_F11: is_fullscreen = not is_fullscreen pygame.display.toggle_fullscreen() + + if event.key == pygame.K_m: + keyboard.press('m') + + if event.key == pygame.K_g: + flags["run_model_flag"] = not flags["run_model_flag"] location = hands.mouse_location.copy() - if len(location) == 1: + if len(location) > 0: # console.print(location) location = location[0] - mouse_controls.control(location[0], location[1], hands.click) + mouse.control(location[0], location[1], hands.click) # frames per second fps = font.render( @@ -253,37 +272,48 @@ def game_loop( hand_surface_copy = pygame.transform.scale( hands_surface.copy(), (img_width * 0.5, img_height * 0.5) ) - img_pygame = pygame.transform.scale( - img_pygame, (img_width * 0.5, img_height * 0.5) - ) - if is_webcam_fullscreen: + #fullscreen webcam + if webcam_mode%3==0: img_pygame = pygame.transform.scale( img_pygame, (window_width, window_height) ) hand_surface_copy = pygame.transform.scale( hands_surface.copy(), (window_width, window_height) ) - - window.blit(img_pygame, (0, 0)) - - for index in range(len(hands.gestures)): - gesture_text = font.render(hands.gestures[index], False, (255, 255, 255)) - window.blit(gesture_text, (window_width - window_width // 5, index * 40)) - - if hands.delay != 0 and counter%60==0: - delay_AI = font.render( - "Webcam: "+str(round(1000/hands.delay, 1)) + "fps", False, (255, 255, 255) + window.blit(img_pygame, (0, 0)) + #window + elif webcam_mode%3==1: + img_pygame = pygame.transform.scale( + img_pygame, (img_width * 0.5, img_height * 0.5) ) - if delay_AI != None: - window.blit(delay_AI, (0, 40)) - window.blit(fps, (0, 0)) - + window.blit(img_pygame, (0, 0)) + #no webcam + elif webcam_mode%3==2: + pass + + if show_debug_text: + for index in range(len(hands.gestures)): + gesture_text = font.render(hands.gestures[index], False, (255, 255, 255)) + window.blit(gesture_text, (0, index * 40 + 80)) + + if hands.delay != 0 and counter % 60 == 0: + delay_AI = font.render( + "Webcam: " + str(round(1000 / hands.delay, 1)) + "fps", + False, + (255, 255, 255), + ) + if delay_AI != None: + window.blit(delay_AI, (0, 40)) + window.blit(fps, (0, 0)) + + for index, instruc in enumerate(instructions): + instructoins_text = font.render(instruc, False, (255, 255, 255)) + window.blit(instructoins_text, (0, 400+index * 40)) if menu.is_enabled(): - menu.update(events) + menu.update(events) menu.draw(window) - window.blit(hand_surface_copy, (0, 0)) clock.tick(pygame.display.get_current_refresh_rate()) From 8c6c121113a5c6052759e50ce5e3d7dd8cc64fbf Mon Sep 17 00:00:00 2001 From: JayLiuTU Date: Sun, 31 Mar 2024 22:44:42 -0400 Subject: [PATCH 08/11] refactoring, render improvements, render hand in corners --- source/gesture inference/GetHands.py | 68 +++------- source/gesture inference/RenderHands.py | 147 ++++++++++------------ source/gesture inference/inference.py | 158 ++++++++++++++---------- 3 files changed, 175 insertions(+), 198 deletions(-) diff --git a/source/gesture inference/GetHands.py b/source/gesture inference/GetHands.py index 0e3a92ac2..7cfef3522 100644 --- a/source/gesture inference/GetHands.py +++ b/source/gesture inference/GetHands.py @@ -23,42 +23,38 @@ class GetHands(Thread): def __init__( self, - render_hands, mediapipe_model="hand_landmarker.task", - mouse=None, flags=None, - keyboard=None, ): Thread.__init__(self) self.model_path = mediapipe_model - self.render_hands = render_hands self.confidence = 0.8 self.stopped = False - self.mouse = mouse self.flags = flags - self.keyboard = keyboard self.console = GestureConsole() - self.camera = Webcam() self.set_gesture_model(flags["gesture_model_path"]) - + self.gesture_list = self.gesture_model.labels self.confidence_vectors = self.gesture_model.confidence_vector self.gestures = ["no gesture"] self.delay = 0 + self.result = None self.click = "" - self.mouse_location = [] + self.location = [] + self.velocity = [] + self.num_hands_deteced = 0 (self.grabbed, self.frame) = self.camera.read() self.timer = 0 self.build_mediapipe_model(flags["number_of_hands"]) - + def set_gesture_model(self, path): self.gesture_model = NeuralNet(path) @@ -86,22 +82,6 @@ def build_mediapipe_model(self, hands_num): # build hands model self.hands_detector = self.HandLandmarker.create_from_options(self.options) - def move_mouse(self, location, button: str): - """Wrapper method to control the mouse - - Args: - hands_location_on_screen (origins): The origins result from find_velocity_and_location() - mouse_button_text (str): Type of click - """ - if callable(self.control_mouse): - if location != []: - # (0,0) is the top left corner - self.control_mouse( - location[0][0], - location[0][1], - button, - ) - def results_callback( self, result: mp.tasks.vision.HandLandmarkerResult, @@ -111,19 +91,19 @@ def results_callback( # this try catch block is for debugging. this code runs in a different thread and doesn't automatically raise its own exceptions try: - self.mouse_location = [] + self.location = [] self.click = "" - if len(result.hand_world_landmarks) == 0: - - self.render_hands( - result, - None, - None, - None, - ) + self.velocity = [] + self.num_hands_deteced = len(result.hand_world_landmarks) + if self.num_hands_deteced == 0: + self.result = [] return + self.result = result + location, velocity = self.gesture_model.find_velocity_and_location(result) + self.location = location + self.velocity = velocity if self.flags["run_model_flag"]: @@ -150,32 +130,14 @@ def results_callback( self.gestures = gestures self.confidence_vectors = hand_confidences - self.keyboard.gesture_input(self.confidence_vectors[0]) - self.console.table(self.gesture_list, hand_confidences) - if self.flags["move_mouse_flag"] and location != []: - mouse_button_text = "" - hand = result.hand_world_landmarks[0] - if self.mouse.is_clicking(hand[8], hand[4], self.flags["click_sense"]): - mouse_button_text = "left" - - self.click = mouse_button_text - self.mouse_location = location - # timestamps are in microseconds so convert to ms current_time = time.time() self.delay = (current_time - self.timer) * 1000 self.timer = current_time - self.render_hands( - result, - self.flags["render_hands_mode"], - location, - velocity, - ) - except Exception as e: traceback.print_exc() quit() diff --git a/source/gesture inference/RenderHands.py b/source/gesture inference/RenderHands.py index 165542b32..f09daf17c 100644 --- a/source/gesture inference/RenderHands.py +++ b/source/gesture inference/RenderHands.py @@ -4,23 +4,23 @@ class RenderHands: """Given the Mediapipe hands output data, renders the hands in a normilzed view or camera perspective view on a pygame surface""" - def __init__(self, surface, render_scale=3): + def __init__(self, render_scale=3): """Create Render Hand object using a pygame surface and a scaling factor Args: surface (pygame.surface): pygame surface to render a hand on hand_scale (float): multiplier to change the size at which the hand is rendered at """ - self.surface = surface self.hand_scale = render_scale self.font = pygame.font.Font("freesansbold.ttf", 30) self.last_velocity = [(0.5, 0.5)] self.thickness = 15 + self.colors = [(0, 0, 255), (0, 255, 0), (255, 0, 0), (255, 255, 255)] - def set_render_scale(self, scale:float): + def set_render_scale(self, scale: float): self.hand_scale = scale - def connections(self, landmarks, mode): + def connections(self, landmarks, mode, surface): """Renders lines between hand joints Args: @@ -30,9 +30,9 @@ def connections(self, landmarks, mode): xy = [] - w, h = self.surface.get_size() + w, h = surface.get_size() - for index, hand in enumerate(landmarks): + for index, hand in enumerate([landmarks]): xy.append([]) for point in hand: if mode: @@ -52,91 +52,77 @@ def connections(self, landmarks, mode): for hand in range(len(xy)): # thumb - self.render_line(xy[hand][0], xy[hand][1]) - self.render_line(xy[hand][1], xy[hand][2]) - self.render_line(xy[hand][2], xy[hand][3]) - self.render_line(xy[hand][3], xy[hand][4]) + self.render_line(xy[hand][0], xy[hand][1], surface) + self.render_line(xy[hand][1], xy[hand][2], surface) + self.render_line(xy[hand][2], xy[hand][3], surface) + self.render_line(xy[hand][3], xy[hand][4], surface) # index - self.render_line(xy[hand][0], xy[hand][5]) - self.render_line(xy[hand][5], xy[hand][6]) - self.render_line(xy[hand][6], xy[hand][7]) - self.render_line(xy[hand][7], xy[hand][8]) + self.render_line(xy[hand][0], xy[hand][5], surface) + self.render_line(xy[hand][5], xy[hand][6], surface) + self.render_line(xy[hand][6], xy[hand][7], surface) + self.render_line(xy[hand][7], xy[hand][8], surface) # middle - self.render_line(xy[hand][9], xy[hand][10]) - self.render_line(xy[hand][10], xy[hand][11]) - self.render_line(xy[hand][11], xy[hand][12]) + self.render_line(xy[hand][9], xy[hand][10], surface) + self.render_line(xy[hand][10], xy[hand][11], surface) + self.render_line(xy[hand][11], xy[hand][12], surface) # ring - self.render_line(xy[hand][13], xy[hand][14]) - self.render_line(xy[hand][14], xy[hand][15]) - self.render_line(xy[hand][15], xy[hand][16]) + self.render_line(xy[hand][13], xy[hand][14], surface) + self.render_line(xy[hand][14], xy[hand][15], surface) + self.render_line(xy[hand][15], xy[hand][16], surface) # pinky - self.render_line(xy[hand][0], xy[hand][17]) - self.render_line(xy[hand][17], xy[hand][18]) - self.render_line(xy[hand][18], xy[hand][19]) - self.render_line(xy[hand][19], xy[hand][20]) + self.render_line(xy[hand][0], xy[hand][17], surface) + self.render_line(xy[hand][17], xy[hand][18], surface) + self.render_line(xy[hand][18], xy[hand][19], surface) + self.render_line(xy[hand][19], xy[hand][20], surface) # knuckle - self.render_line(xy[hand][5], xy[hand][9]) - self.render_line(xy[hand][9], xy[hand][13]) - self.render_line(xy[hand][13], xy[hand][17]) + self.render_line(xy[hand][5], xy[hand][9], surface) + self.render_line(xy[hand][9], xy[hand][13], surface) + self.render_line(xy[hand][13], xy[hand][17], surface) - def render_line(self, start, end): + def render_line(self, start, end, surface): """Wrapper function for pygame's render line. Will render a white line with width=5 Args: start (int): line start position end (int): line end position """ - pygame.draw.line(self.surface, (255, 255, 255), start, end, self.thickness) - - def render_hands( - self, result, mode, origins, velocity - ): - - self.surface.fill((0, 0, 0)) - # Render hand landmarks - - w, h = self.surface.get_size() - if result.handedness != []: - if mode: - hand_points = result.hand_world_landmarks - pygame.draw.circle(self.surface, (255, 0, 255), (0.5 * w, 0.5 * h), 10) - pygame.draw.line( - self.surface, - (255, 255, 0), - ((velocity[0][0] + 0.5) * w, (velocity[0][1] + 0.5) * h), - ((0.5) * w, (0.5) * h), - 10, - ) - self.last_velocity = velocity - - else: - hand_points = result.hand_landmarks - - self.connections(hand_points, mode) - if hand_points: - # define colors for different hands - - hand_color = 0 - colors = [(0, 0, 255), (0, 255, 0), (255, 0, 0), (255, 255, 255)] - # get every hand detected - for index, hand in enumerate(hand_points): - # each hand has 21 landmarks - pygame.draw.circle( - self.surface, - (255, 0, 255), - (origins[index][0] * w, origins[index][1] * h), - 5, - ) - for landmark in hand: - self.__render_hands_pygame( - colors[hand_color], - landmark.x, - landmark.y, - mode, - ) - hand_color += 1 + pygame.draw.line(surface, (255, 255, 255), start, end, self.thickness) + + def render_hands(self, landmarks, mode, origins, velocity, surface, hand_color=0): - def __render_hands_pygame(self, color, x, y, mode): + surface.fill((0, 0, 0)) + + w, h = surface.get_size() + + if mode: + pygame.draw.line( + surface, + (255, 255, 0), + ((velocity[0][0] + 0.5) * w, (velocity[0][1] + 0.5) * h), + ((0.5) * w, (0.5) * h), + self.thickness, + ) + self.last_velocity = velocity + + self.connections(landmarks, mode, surface) + + # pygame.draw.circle( + # surface, + # (255, 0, 255), + # (origins[index][0] * w, origins[index][1] * h), + # 5, + # ) + for landmark in landmarks: + self.__render_hands_pygame( + self.colors[hand_color], + landmark.x, + landmark.y, + mode, + surface + ) + + + def __render_hands_pygame(self, color, x, y, mode, surface): """Renders a single landmark of a hand in pygame and scales the hand. Args: @@ -148,7 +134,7 @@ def __render_hands_pygame(self, color, x, y, mode): mode (bool): True to render in normalized mode. False for world coordinates """ - w, h = self.surface.get_size() + w, h = surface.get_size() if mode: x *= self.hand_scale @@ -156,5 +142,4 @@ def __render_hands_pygame(self, color, x, y, mode): x += 0.5 y += 0.5 - pygame.draw.circle(self.surface, color, (x * w, y * h), self.thickness//2) - + pygame.draw.circle(surface, color, (x * w, y * h), self.thickness // 2) diff --git a/source/gesture inference/inference.py b/source/gesture inference/inference.py index b67d04ba3..92a24177e 100644 --- a/source/gesture inference/inference.py +++ b/source/gesture inference/inference.py @@ -46,10 +46,7 @@ def main() -> None: window = pygame.display.set_mode((window_width, window_height), pygame.RESIZABLE) pygame.display.set_caption("Test Hand Tracking Multithreaded") - hands_surface = pygame.Surface((window_width, window_height)) - hands_surface.set_colorkey((0, 0, 0)) - - myRenderHands = RenderHands(hands_surface, render_scale=3) + renderHands = RenderHands(render_scale=3) mouse = Mouse() @@ -59,10 +56,7 @@ def main() -> None: # control_mouse=mouse_controls.control, hands = GetHands( - myRenderHands.render_hands, - mouse=mouse, flags=flags, - keyboard=keyboard, ) menu = pygame_menu.Menu( @@ -73,7 +67,7 @@ def main() -> None: ) menu.add.selector( - "Render Mode :", [("Normalized", True),("World", False)], onchange=set_coords + "Render Mode :", [("Normalized", True), ("World", False)], onchange=set_coords ) def change_mouse_smooth(value, smooth): @@ -110,7 +104,7 @@ def set_click_sense(value, **kwargs): print(value) flags["click_sense"] = value / 1000 - menu.add.range_slider( + menu.add.range_slider( "Click Sensitivity", default=70, range_values=(1, 150), @@ -119,16 +113,13 @@ def set_click_sense(value, **kwargs): ) def build_hands(): - nonlocal hands + nonlocal hands nonlocal mouse nonlocal keyboard hands.stop() hands.join() hands = GetHands( - myRenderHands.render_hands, - mouse=mouse, flags=flags, - keyboard=keyboard, ) flags["hands"] = hands hands.start() @@ -138,14 +129,7 @@ def build_hands(): menu.add.button("Quit", pygame_menu.events.EXIT) menu.enable() - game_loop( - window, - hands, - hands_surface, - menu, - mouse, - keyboard, - ) + game_loop(window, hands, menu, mouse, keyboard, renderHands) pygame.quit() @@ -180,32 +164,31 @@ def set_coords(value, mode) -> None: def game_loop( window: pygame.display, hands: GetHands, - hands_surface: pygame.Surface, menu: pygame_menu.Menu, mouse: Mouse, - keyboard: Keyboard + keyboard: Keyboard, + renderHands: RenderHands, ): - """Runs the pygame event loop and renders surfaces - - Args: - window (_type_): The main pygame window - hands (_type_): The GetHands class - hands_surface (_type_): The surface that the hands are rendered on - menu (_type_): the main menu - """ + """Runs the pygame event loop and renders surfaces""" hands.start() running = True is_menu_showing = True - webcam_mode = 0 + webcam_mode = 1 show_debug_text = True is_fullscreen = False counter = 0 delay_AI = None - + window_width, window_height = pygame.display.get_surface().get_size() + + hand_surfaces = [] + for i in range(4): + hand_surfaces.append(pygame.Surface((window_width, window_height))) + hand_surfaces[i].set_colorkey((0, 0, 0)) + wrapper = textwrap.TextWrapper(width=20) - instructions = "F1 to change webcam place. F2 to hide this text. F3 to change hand render mode. 'M' to toggle mouse control. 'G' to toggle gesture model." + instructions = "F1 to change webcam place. F2 to hide this text. F3 to change hand render mode. 'M' to toggle mouse control. 'G' to toggle gesture model." instructions = wrapper.wrap(text=instructions) - + while running: counter += 1 @@ -214,6 +197,7 @@ def game_loop( hands = flags["hands"] window_width, window_height = pygame.display.get_surface().get_size() + window.fill((0, 0, 0)) events = pygame.event.get() for event in events: @@ -236,28 +220,37 @@ def game_loop( if event.key == pygame.K_F1: webcam_mode += 1 - + if event.key == pygame.K_F2: show_debug_text = not show_debug_text - + if event.key == pygame.K_F3: flags["render_hands_mode"] = not flags["render_hands_mode"] if event.key == pygame.K_F11: is_fullscreen = not is_fullscreen pygame.display.toggle_fullscreen() - + if event.key == pygame.K_m: - keyboard.press('m') - + keyboard.press("m") + if event.key == pygame.K_g: flags["run_model_flag"] = not flags["run_model_flag"] - location = hands.mouse_location.copy() - if len(location) > 0: - # console.print(location) + location = hands.location.copy() + + if flags["move_mouse_flag"] and location != []: + mouse_button_text = "" + hand = hands.result.hand_world_landmarks[0] + if mouse.is_clicking(hand[8], hand[4], flags["click_sense"]): + mouse_button_text = "left" location = location[0] - mouse.control(location[0], location[1], hands.click) + mouse.control(location[0], location[1], mouse_button_text) + + if flags["run_model_flag"] and len(hands.confidence_vectors) > 0: + console.print(hands.confidence_vectors) + #send only the first hand confidence vector the gesture model output + keyboard.gesture_input(hands.confidence_vectors[0]) # frames per second fps = font.render( @@ -269,32 +262,60 @@ def game_loop( img_width = img_pygame.get_width() img_height = img_pygame.get_height() - hand_surface_copy = pygame.transform.scale( - hands_surface.copy(), (img_width * 0.5, img_height * 0.5) - ) + for i in range(4): + hand_surfaces[i] = pygame.transform.scale( + hand_surfaces[i], (img_width * 0.5, img_height * 0.5) + ) - #fullscreen webcam - if webcam_mode%3==0: + # fullscreen webcam + if webcam_mode % 3 == 0: + renderHands.thickness = 15 img_pygame = pygame.transform.scale( img_pygame, (window_width, window_height) ) - hand_surface_copy = pygame.transform.scale( - hands_surface.copy(), (window_width, window_height) - ) + for i in range(4): + hand_surfaces[i] = pygame.transform.scale( + hand_surfaces[i], (window_width, window_height) + ) window.blit(img_pygame, (0, 0)) - #window - elif webcam_mode%3==1: + # windowed webcam + elif webcam_mode % 3 == 1: + renderHands.thickness = 5 img_pygame = pygame.transform.scale( - img_pygame, (img_width * 0.5, img_height * 0.5) + img_pygame, (img_width * 0.5, img_height * 0.5) ) window.blit(img_pygame, (0, 0)) - #no webcam - elif webcam_mode%3==2: + # no webcam + elif webcam_mode % 3 == 2: pass + # use this again for putting hands in the corners + img_width = img_pygame.get_width() + img_height = img_pygame.get_height() + + if hands.location != []: + for index in range(hands.num_hands_deteced): + if flags["render_hands_mode"]: + landmarks = hands.result.hand_world_landmarks + else: + landmarks = hands.result.hand_landmarks + for i in range(hands.num_hands_deteced): + renderHands.render_hands( + landmarks[i], + flags["render_hands_mode"], + hands.location, + hands.velocity, + hand_surfaces[i], + i, + ) + else: + for i in range(4): + hand_surfaces[i].fill((0, 0, 0)) if show_debug_text: for index in range(len(hands.gestures)): - gesture_text = font.render(hands.gestures[index], False, (255, 255, 255)) + gesture_text = font.render( + hands.gestures[index], False, (255, 255, 255) + ) window.blit(gesture_text, (0, index * 40 + 80)) if hands.delay != 0 and counter % 60 == 0: @@ -306,18 +327,27 @@ def game_loop( if delay_AI != None: window.blit(delay_AI, (0, 40)) window.blit(fps, (0, 0)) - + for index, instruc in enumerate(instructions): instructoins_text = font.render(instruc, False, (255, 255, 255)) - window.blit(instructoins_text, (0, 400+index * 40)) + window.blit(instructoins_text, (0, 400 + index * 40)) if menu.is_enabled(): - menu.update(events) + menu.update(events) menu.draw(window) - window.blit(hand_surface_copy, (0, 0)) - clock.tick(pygame.display.get_current_refresh_rate()) - # clock.tick(60) + corners = [ + (0, 0), + (window_width - img_width, 0), + (0, window_height - img_height), + (window_width - img_width, window_height - img_height), + ] + + for i in range(hands.num_hands_deteced): + window.blit(hand_surfaces[i], corners[i]) + + # clock.tick(pygame.display.get_current_refresh_rate()) + clock.tick(60) pygame.display.update() From 5ca397a0814579c3c1faa7f3b188116e59ba944e Mon Sep 17 00:00:00 2001 From: JayLiuTU Date: Sun, 31 Mar 2024 23:39:12 -0400 Subject: [PATCH 09/11] fixed webcams in corner --- source/gesture inference/GetHands.py | 4 ++-- source/gesture inference/inference.py | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/source/gesture inference/GetHands.py b/source/gesture inference/GetHands.py index 7cfef3522..0d4e6fa18 100644 --- a/source/gesture inference/GetHands.py +++ b/source/gesture inference/GetHands.py @@ -29,7 +29,7 @@ def __init__( Thread.__init__(self) self.model_path = mediapipe_model - self.confidence = 0.8 + self.confidence = 0.5 self.stopped = False self.flags = flags @@ -74,7 +74,7 @@ def build_mediapipe_model(self, hands_num): num_hands=hands_num, min_hand_detection_confidence=self.confidence, min_hand_presence_confidence=self.confidence, - min_tracking_confidence=0.5, + min_tracking_confidence=self.confidence, running_mode=self.VisionRunningMode.LIVE_STREAM, result_callback=self.results_callback, ) diff --git a/source/gesture inference/inference.py b/source/gesture inference/inference.py index 92a24177e..d26bb9666 100644 --- a/source/gesture inference/inference.py +++ b/source/gesture inference/inference.py @@ -101,7 +101,6 @@ def change_gesture_model(value): def set_click_sense(value, **kwargs): nonlocal hands - print(value) flags["click_sense"] = value / 1000 menu.add.range_slider( @@ -248,8 +247,7 @@ def game_loop( mouse.control(location[0], location[1], mouse_button_text) if flags["run_model_flag"] and len(hands.confidence_vectors) > 0: - console.print(hands.confidence_vectors) - #send only the first hand confidence vector the gesture model output + # send only the first hand confidence vector the gesture model output keyboard.gesture_input(hands.confidence_vectors[0]) # frames per second @@ -289,8 +287,8 @@ def game_loop( elif webcam_mode % 3 == 2: pass # use this again for putting hands in the corners - img_width = img_pygame.get_width() - img_height = img_pygame.get_height() + img_width = hand_surfaces[0].get_width() + img_height = hand_surfaces[0].get_height() if hands.location != []: for index in range(hands.num_hands_deteced): From e7afaaf882faf859521dff5b3cfcf3d94fe5da27 Mon Sep 17 00:00:00 2001 From: JayLiuTU Date: Mon, 1 Apr 2024 10:09:17 -0400 Subject: [PATCH 10/11] keyboard uses key down and up now --- source/gesture inference/Keyboard.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/source/gesture inference/Keyboard.py b/source/gesture inference/Keyboard.py index 1b2aaf9d6..f7a15e0fb 100644 --- a/source/gesture inference/Keyboard.py +++ b/source/gesture inference/Keyboard.py @@ -2,9 +2,17 @@ import time from Console import GestureConsole import numpy as np + + class Keyboard: def __init__( - self, threshold=0.0, toggle_key_threshold=0.15, toggle_key_toggle_time=1, toggle_mouse_func=None, flags=None, toggle_key='' + self, + threshold=0.0, + toggle_key_threshold=0.15, + toggle_key_toggle_time=1, + toggle_mouse_func=None, + flags=None, + toggle_key="", ) -> None: """_summary_ @@ -24,15 +32,18 @@ def __init__( self.last_time_toggle_key = time.time() self.last_key = "" self.toggle_key_pressed = False - self.key_presed = False + self.key_pressed = False self.toggle_mouse_func = toggle_mouse_func self.toggle_key_toggle_time = toggle_key_toggle_time self.console = GestureConsole() self.flags = flags self.toggle_key = toggle_key - def gesture_input(self, confidences): + def release(self): + if self.key_pressed == True: + pyautogui.keyUp(self.last_key) + def gesture_input(self, confidences): max_value = np.max(confidences) max_index = np.argmax(confidences) if max_index == 0: @@ -50,6 +61,7 @@ def press(self, key: str): self.toggle_key_pressed = False self.last_key = key if key == "none": + pyautogui.keyUp(self.last_key) # Release the last key return if key == self.toggle_key: self.last_time_toggle_key = current_time @@ -61,10 +73,13 @@ def press(self, key: str): elif current_time - self.last_time > self.threshold and not self.key_pressed: self.key_pressed = True self.console.print(f"pressing key: {key}") - pyautogui.press(key, _pause=False) + pyautogui.keyDown(key) def handle_toggle_key(self, current_time): - if not self.toggle_key_pressed or current_time - self.last_time_toggle_key > self.toggle_key_toggle_time: + if ( + not self.toggle_key_pressed + or current_time - self.last_time_toggle_key > self.toggle_key_toggle_time + ): if current_time - self.last_time_toggle_key > self.toggle_key_threshold: if self.toggle_mouse_func is not None: self.toggle_mouse_func() From 584d5d9cfc93c296ed53415cd6e29e6d14364079 Mon Sep 17 00:00:00 2001 From: JayLiuTU Date: Mon, 1 Apr 2024 11:53:09 -0400 Subject: [PATCH 11/11] made keyboard inputs work with pygame --- source/gesture inference/Console.py | 33 ++++++++++++++++++++------- source/gesture inference/GetHands.py | 6 +++-- source/gesture inference/Keyboard.py | 31 +++++++++++++++---------- source/gesture inference/inference.py | 14 +++++++++--- 4 files changed, 59 insertions(+), 25 deletions(-) diff --git a/source/gesture inference/Console.py b/source/gesture inference/Console.py index 1a152a307..e6c3ee992 100644 --- a/source/gesture inference/Console.py +++ b/source/gesture inference/Console.py @@ -3,8 +3,11 @@ from rich.layout import Layout from rich.console import Console from rich.panel import Panel +from rich.columns import Columns + import os + class GestureConsole: # make this class a singleton _initialized = False @@ -14,7 +17,7 @@ def __new__(cls): cls.instance = super(GestureConsole, cls).__new__(cls) return cls.instance - def __init__(self) -> None: + def __init__(self, max_tables=5) -> None: if not self._initialized: self._initialized = True self.console = ConsolePanel() @@ -22,29 +25,43 @@ def __init__(self) -> None: self.layout.split_column(Layout(name="upper"), Layout(name="lower")) self.live = Live(self.layout, auto_refresh=False) self.live.start() + self.tables = [] + for i in range(max_tables): + self.tables.append(Table()) + + def table(self, headers, rows, table_number=0): + table = self.tables[table_number] + table.columns.clear() # Clear existing columns + table.rows.clear() # Clear existing rows - def table(self, headers, rows): - table = Table() for header in headers: table.add_column(header) for row in rows: table_row = [] for item in row: - table_row.append(str(f"{float(item):.3f}")) - table.add_row(*table_row) + if isinstance(item, float): + table_row.append(str(f"{float(item):.3f}")) + else: + table_row.append(str(item)) + table.add_row(*table_row) - self.layout["upper"].update(Panel(table)) - self.update() + self.layout["upper"].update( + Panel.fit( + Columns(self.tables), + ) + ) + self.update() def print(self, string: str): self.console.print(string) self.layout["lower"].update(Panel(self.console)) self.update() - + def update(self): self.live.update(self.layout, refresh=True) + # https://stackoverflow.com/questions/71077706/redirect-print-and-or-logging-to-panel class ConsolePanel(Console): def __init__(self, *args, **kwargs): diff --git a/source/gesture inference/GetHands.py b/source/gesture inference/GetHands.py index 0d4e6fa18..99e7a7813 100644 --- a/source/gesture inference/GetHands.py +++ b/source/gesture inference/GetHands.py @@ -92,11 +92,13 @@ def results_callback( try: self.location = [] - self.click = "" + self.click = "" self.velocity = [] self.num_hands_deteced = len(result.hand_world_landmarks) if self.num_hands_deteced == 0: self.result = [] + self.confidence_vectors=[] + self.console.table(self.gesture_list, self.confidence_vectors) #clear table return self.result = result @@ -130,7 +132,7 @@ def results_callback( self.gestures = gestures self.confidence_vectors = hand_confidences - self.console.table(self.gesture_list, hand_confidences) + self.console.table(self.gesture_list, self.confidence_vectors) # timestamps are in microseconds so convert to ms diff --git a/source/gesture inference/Keyboard.py b/source/gesture inference/Keyboard.py index f7a15e0fb..6a5cd7b61 100644 --- a/source/gesture inference/Keyboard.py +++ b/source/gesture inference/Keyboard.py @@ -1,4 +1,4 @@ -import pyautogui +import pydirectinput import time from Console import GestureConsole import numpy as np @@ -24,8 +24,8 @@ def __init__( Key press options: ['\t', '\n', '\r', ' ', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', 'accept', 'add', 'alt', 'altleft', 'altright', 'apps', 'backspace', 'browserback', 'browserfavorites', 'browserforward', 'browserhome', 'browserrefresh', 'browsersearch', 'browserstop', 'capslock', 'clear', 'convert', 'ctrl', 'ctrlleft', 'ctrlright', 'decimal', 'del', 'delete', 'divide', 'down', 'end', 'enter', 'esc', 'escape', 'execute', 'f1', 'f10', 'f11', 'f12', 'f13', 'f14', 'f15', 'f16', 'f17', 'f18', 'f19', 'f2', 'f20', 'f21', 'f22', 'f23', 'f24', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'final', 'fn', 'hanguel', 'hangul', 'hanja', 'help', 'home', 'insert', 'junja', 'kana', 'kanji', 'launchapp1', 'launchapp2', 'launchmail', 'launchmediaselect', 'left', 'modechange', 'multiply', 'nexttrack', 'nonconvert', 'num0', 'num1', 'num2', 'num3', 'num4', 'num5', 'num6', 'num7', 'num8', 'num9', 'numlock', 'pagedown', 'pageup', 'pause', 'pgdn', 'pgup', 'playpause', 'prevtrack', 'print', 'printscreen', 'prntscrn', 'prtsc', 'prtscr', 'return', 'right', 'scrolllock', 'select', 'separator', 'shift', 'shiftleft', 'shiftright', 'sleep', 'space', 'stop', 'subtract', 'tab', 'up', 'volumedown', 'volumemute', 'volumeup', 'win', 'winleft', 'winright', 'yen', 'command', 'option', 'optionleft', 'optionright'] """ - pyautogui.FAILSAFE = False - pyautogui.PAUSE = 0 + pydirectinput.FAILSAFE = False + pydirectinput.PAUSE = 0 self.threshold = threshold self.toggle_key_threshold = toggle_key_threshold self.last_time = time.time() @@ -40,8 +40,11 @@ def __init__( self.toggle_key = toggle_key def release(self): - if self.key_pressed == True: - pyautogui.keyUp(self.last_key) + if self.key_pressed: + pydirectinput.keyUp(self.last_key) + self.key_pressed = False + if self.toggle_key_pressed: + self.toggle_key_pressed = False def gesture_input(self, confidences): max_value = np.max(confidences) @@ -54,15 +57,17 @@ def gesture_input(self, confidences): self.press(self.toggle_key) def press(self, key: str): - current_time = time.time() - + + current_time = time.time() + if key == "none": + self.key_pressed = False + pydirectinput.keyUp(self.last_key) # Release the last key + return if key != self.last_key: self.key_pressed = False self.toggle_key_pressed = False self.last_key = key - if key == "none": - pyautogui.keyUp(self.last_key) # Release the last key - return + if key == self.toggle_key: self.last_time_toggle_key = current_time else: @@ -72,8 +77,10 @@ def press(self, key: str): self.handle_toggle_key(current_time) elif current_time - self.last_time > self.threshold and not self.key_pressed: self.key_pressed = True - self.console.print(f"pressing key: {key}") - pyautogui.keyDown(key) + #self.console.print(f"pressing key: {key}") + pydirectinput.keyDown(key) + # else: + # self.console.print(f"key {key} already pressed") def handle_toggle_key(self, current_time): if ( diff --git a/source/gesture inference/inference.py b/source/gesture inference/inference.py index d26bb9666..3dc996ac9 100644 --- a/source/gesture inference/inference.py +++ b/source/gesture inference/inference.py @@ -113,8 +113,6 @@ def set_click_sense(value, **kwargs): def build_hands(): nonlocal hands - nonlocal mouse - nonlocal keyboard hands.stop() hands.join() hands = GetHands( @@ -195,9 +193,17 @@ def game_loop( if flags["hands"] != None and hands != flags["hands"]: hands = flags["hands"] + window_width, window_height = pygame.display.get_surface().get_size() window.fill((0, 0, 0)) + + keys = pygame.key.get_pressed() + if keys[pygame.K_SPACE]: + console.table(["key pressed"], [["space"]], table_number=1) + else: + console.table(["key pressed"], [[""]], table_number=1) + events = pygame.event.get() for event in events: if event.type == pygame.QUIT: @@ -232,7 +238,7 @@ def game_loop( if event.key == pygame.K_m: keyboard.press("m") - + if event.key == pygame.K_g: flags["run_model_flag"] = not flags["run_model_flag"] @@ -249,6 +255,8 @@ def game_loop( if flags["run_model_flag"] and len(hands.confidence_vectors) > 0: # send only the first hand confidence vector the gesture model output keyboard.gesture_input(hands.confidence_vectors[0]) + else: + keyboard.release() # frames per second fps = font.render(