¡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/