? 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/
Si usas Linux, es posible que tengas varios problemas con el comando screenshot de pyautogui.
1. – Es posible que te de un error de librerías y que necesites instalar «scrot».
2. – Que cuando te salga la captura del screenshot, lo veas todo negro, no hay imagen.
Solución caso 1.
Por lo que parece, screenshot, usa una parte de Pillow (una librería de gráficos) y por lo que se ve, necesita un anexo, un requerimiento más, se llama scrot y hay que instalarlo.
En Debian 11 se instala con: $ sudo apt install scrot.
Con esto tendrás solucionado el problema 1.
Solución caso 2.
Este problema es un poco más «peliagudo», ya que si te pasa esto es que lo más probable estes usando el gestor de gráficos WAYLAND, y por lo que parece, este no se lleva bien con «screenshot», por lo que no tienes más remedio que cambiar WAYLAND por X11 o Xorg.
Si cierras la sesión, al volver a entrar en ella, selecciona este gestor de entre las opciones de arranque que te porporciona el icono de ajustes (rueda dentada) antes de dar siguiente al loguearte. No deberías notar nada raro, salvo que ahora la acción de screenshot te funcionara.
Para volver a Wayland, solo tienes que escogerlo en el menu de ajustes al entrar de nuevo en tu sesión.
Espero haber ayudado a quién como yo, ha tenido problemas con este asunto.
Para que sea más fácil encontrar la ubicación de las coordenadas de captura de la zona de la pantalla a definir con screenshot, les paso unas líneas que facilitaran su ubicación.
Este pequeño script, marcara constantemente la ubicación del mouse, por lo que solo se necesitará anotar las coordenadas correctas después de posicionar el mouse en el punto deseado. OJO, hay que romper el programa para salir de él.
import pyautogui
while True:
ancho, alto = pyautogui.position()
print(f’Ancho: {ancho}, Alto: {alto}’)
Un saludo.
hola, habra posibilidad que con la mano se pueda desplazar hacia arriba y abajo?