? CONTROLA EL MOUSE CON UNA MANO Y JUEGA | Python – MediaPipe Hands – OpenCV
¡Vamos a divertirnos con Visión Artificial!. A continuación podrás encontrar la programación en donde controlaremos el mouse ?️ con una mano, para jugar sobre cierta área de la pantalla (en donde estará el juego) y daremos clic cerrando la mano/bajando el dedo índice. ¡Anímate a probarlo!.
Controla el mouse ?️ con una mano y juega ? usando visión artificial
Para la realización de este proyecto tendremos que tener instalado Python y los paquetes:
- MediaPipe
- Numpy
- OpenCV
- Pyautogui
La instalación de todos estos paquetes se encuentra en la parte 1 de este proyecto.
Esta aplicación ha sido realizada en una miniserie de 3 videos en YouTube que podrás encontrar en mi canal. En este post podrás encontrar la programación completa que se ha desarrollado en los videos.
Con ayuda de Pyautogui determinar el área sobre la pantalla

Figura 1: Izq. Juego que se visualiza en la pantalla del computador. Der. Recorte del área donde se encuentra el juego para usarlo como video de entrada.
En el primer video de la miniserie usé un programa auxiliar para poder determinar el área donde se encontraba el juego, y obtener esta como entrada de video. Esta fue la programación:
import cv2 import numpy as np import pyautogui while True: screenshot = pyautogui.screenshot(region=(150, 160, 780, 450)) screenshot = np.array(screenshot) screenshot = cv2.cvtColor(screenshot, cv2.COLOR_RGB2BGR) cv2.imshow("screenshot", screenshot) if cv2.waitKey(1) & 0xFF == 27: break cv2.destroyAllWindows()
Controlando el mouse con la mano usando MediaPipe Hands, Pyautogui y OpenCV

Figura 2: Prueba realizada sobre el proyecto desarrollado.
Para una explicación más detallada del programa que veremos a continuación, por favor dirígete a la lista de reproducción con los videos de mi canal.
import cv2 import mediapipe as mp import numpy as np import pyautogui mp_drawing = mp.solutions.drawing_utils mp_hands = mp.solutions.hands cap = cv2.VideoCapture(0, cv2.CAP_DSHOW) color_mouse_pointer = (255, 0, 255) # Puntos de la pantalla-juego SCREEN_GAME_X_INI = 150 SCREEN_GAME_Y_INI = 160 SCREEN_GAME_X_FIN = 150 + 780 SCREEN_GAME_Y_FIN = 160 + 450 aspect_ratio_screen = (SCREEN_GAME_X_FIN - SCREEN_GAME_X_INI) / (SCREEN_GAME_Y_FIN - SCREEN_GAME_Y_INI) print("aspect_ratio_screen:", aspect_ratio_screen) X_Y_INI = 100 def calculate_distance(x1, y1, x2, y2): p1 = np.array([x1, y1]) p2 = np.array([x2, y2]) return np.linalg.norm(p1 - p2) def detect_finger_down(hand_landmarks): finger_down = False color_base = (255, 0, 112) color_index = (255, 198, 82) x_base1 = int(hand_landmarks.landmark[0].x * width) y_base1 = int(hand_landmarks.landmark[0].y * height) x_base2 = int(hand_landmarks.landmark[9].x * width) y_base2 = int(hand_landmarks.landmark[9].y * height) x_index = int(hand_landmarks.landmark[8].x * width) y_index = int(hand_landmarks.landmark[8].y * height) d_base = calculate_distance(x_base1, y_base1, x_base2, y_base2) d_base_index = calculate_distance(x_base1, y_base1, x_index, y_index) if d_base_index < d_base: finger_down = True color_base = (255, 0, 255) color_index = (255, 0, 255) cv2.circle(output, (x_base1, y_base1), 5, color_base, 2) cv2.circle(output, (x_index, y_index), 5, color_index, 2) cv2.line(output, (x_base1, y_base1), (x_base2, y_base2), color_base, 3) cv2.line(output, (x_base1, y_base1), (x_index, y_index), color_index, 3) return finger_down with mp_hands.Hands( static_image_mode=False, max_num_hands=1, min_detection_confidence=0.5) as hands: while True: ret, frame = cap.read() if ret == False: break height, width, _ = frame.shape frame = cv2.flip(frame, 1) # Dibujando un área proporcional a la del juego area_width = width - X_Y_INI * 2 area_height = int(area_width / aspect_ratio_screen) aux_image = np.zeros(frame.shape, np.uint8) aux_image = cv2.rectangle(aux_image, (X_Y_INI, X_Y_INI), (X_Y_INI + area_width, X_Y_INI +area_height), (255, 0, 0), -1) output = cv2.addWeighted(frame, 1, aux_image, 0.7, 0) frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) results = hands.process(frame_rgb) if results.multi_hand_landmarks is not None: for hand_landmarks in results.multi_hand_landmarks: x = int(hand_landmarks.landmark[9].x * width) y = int(hand_landmarks.landmark[9].y * height) xm = np.interp(x, (X_Y_INI, X_Y_INI + area_width), (SCREEN_GAME_X_INI, SCREEN_GAME_X_FIN)) ym = np.interp(y, (X_Y_INI, X_Y_INI + area_height), (SCREEN_GAME_Y_INI, SCREEN_GAME_Y_FIN)) pyautogui.moveTo(int(xm), int(ym)) if detect_finger_down(hand_landmarks): pyautogui.click() cv2.circle(output, (x, y), 10, color_mouse_pointer, 3) cv2.circle(output, (x, y), 5, color_mouse_pointer, -1) #cv2.imshow('Frame', frame) cv2.imshow('output', output) if cv2.waitKey(1) & 0xFF == 27: break cap.release() cv2.destroyAllWindows()
Referencias:
- https://www.youtube.com/watch?v=8gPONnGIPgw
- https://www.pyimagesearch.com/2021/01/20/opencv-resize-image-cv2-resize/
- https://recursospython.com/guias-y-manuales/pyautogui/