Jugando ✊ piedra, ✋ papel o ✌️ tijeras | Mediapipe – OpenCV – Python
¡Bienvenidos a un nuevo post lleno de tecnología y diversión! En este, exploraremos cómo crear un juego de piedra, papel o tijeras con visión por computador. Ya sea que seas un programador principiante o un entusiasta experimentado, te aseguro que te divertirás mientras aprendes a hacer tu propio juego utilizando la tecnología de visión artificial. ¡Prepárate para una aventura divertida y llena de desafíos en la que pondrás en práctica tus habilidades de programación!.
CONTENIDO
Jugando piedra, papel o tijeras con Visión Artificial
- Instalación de packages
- Imágenes que usaremos para nuestro juego
- ¡Vamos con la programación!
Jugando piedra, papel o tijeras con Visión Artificial
En esta oportunidad jugaremos con el computador, piedra, papel o tijeras. Antes de empezar con la programación es importante conocer las reglas del juego (aunque por la popularidad de este, puede que no sea necesario explicarlas, pero voy a hacerlo de todos modos, solo porsiacaso 😉).

Figura 1: Reglas de cuando podemos perder o ganar en el juego.
Entonces, ¡exploremos las reglas!. Tenemos tres opciones, piedra que sería un puño, papel que sería la mano extendida y por último, tijeras que es solo levantar los dedos índice y medio. Sabemos que si tanto nosotros como la computadora (o un contrincante humano) emitimos la misma opción, existe un empate. Es por ello que veremos en qué casos podríamos ganar o perder.
Nota: En la figura 1, las ilustraciones que se encuentran rodeadas de azul serán las opciones que podemos escoger, mientras que de verde y rosa las de nuestro contrincante.
- Si elegimos piedra, solo podremos ganar cuando la computadora elija tijeras y perder con papel.
- Si elegimos papel, solo podremos ganarle a la piedra, y perder contra tijeras.
- Por último, si elegimos tijeras, podremos ganarle al papel, pero no a la piedra.
Instalación de packages
En esta oportunidad necesitaremos instalar Mediapipe con ayuda de pip install mediapipe
. Este package a su vez instalará otros módulos como OpenCV o Numpy. Podemos listar los packages instalados usando pip freeze
.

Figura 2: Listando los packages instalados, con pip freeze.
Imágenes que usaremos para nuestro juego
Usaremos 5 imágenes, las cuales irán cambiando conforme vamos avanzando en el juego. He creado estas con un alto de 480 píxeles para que se concatenen con la altura de mi video straming, pero podrías adaptarlas a tus necesidades.
¡Vamos con la programación!
Para la realización de este programa, he tomado otro que habíamos hecho anteriormente, se trata de: ✌️ Contando dedos con visión artificial | Mediapipe – OpenCV – Python. Por lo que te recomiendo probar primero ese programa para luego añadir más líneas que nos permitirán construir el juego.
Recuerda que para una explicación más detallada del programa que veremos a continuación, por favor dirígete a este video que he preparado en mi canal, en donde explico paso a pasito cada procedimiento efectuado. ¡Anímate a verlo 😉!. Ahora sí… ¡Vamos con el código!.
import cv2 import mediapipe as mp import numpy as np from math import acos, degrees import random def palm_centroid(coordinates_list): coordinates = np.array(coordinates_list) centroid = np.mean(coordinates, axis=0) centroid = int(centroid[0]), int(centroid[1]) return centroid def fingers_up_down(hand_results, thumb_points, palm_points, fingertips_points, finger_base_points): fingers = None coordinates_thumb = [] coordinates_palm = [] coordinates_ft = [] coordinates_fb = [] for hand_landmarks in hand_results.multi_hand_landmarks: for index in thumb_points: x = int(hand_landmarks.landmark[index].x * width) y = int(hand_landmarks.landmark[index].y * height) coordinates_thumb.append([x, y]) for index in palm_points: x = int(hand_landmarks.landmark[index].x * width) y = int(hand_landmarks.landmark[index].y * height) coordinates_palm.append([x, y]) for index in fingertips_points: x = int(hand_landmarks.landmark[index].x * width) y = int(hand_landmarks.landmark[index].y * height) coordinates_ft.append([x, y]) for index in finger_base_points: x = int(hand_landmarks.landmark[index].x * width) y = int(hand_landmarks.landmark[index].y * height) coordinates_fb.append([x, y]) ########################## # Pulgar p1 = np.array(coordinates_thumb[0]) p2 = np.array(coordinates_thumb[1]) p3 = np.array(coordinates_thumb[2]) l1 = np.linalg.norm(p2 - p3) l2 = np.linalg.norm(p1 - p3) l3 = np.linalg.norm(p1 - p2) # Calcular el ángulo to_angle = (l1**2 + l3**2 - l2**2) / (2 * l1 * l3) if int(to_angle) == -1: angle = 180 else: angle = degrees(acos(to_angle)) thumb_finger = np.array(False) if angle > 150: thumb_finger = np.array(True) ################################ # Índice, medio, anular y meñique nx, ny = palm_centroid(coordinates_palm) cv2.circle(frame, (nx, ny), 3, (0, 255, 0), 2) coordinates_centroid = np.array([nx, ny]) coordinates_ft = np.array(coordinates_ft) coordinates_fb = np.array(coordinates_fb) # Distancias d_centrid_ft = np.linalg.norm(coordinates_centroid - coordinates_ft, axis=1) d_centrid_fb = np.linalg.norm(coordinates_centroid - coordinates_fb, axis=1) dif = d_centrid_ft - d_centrid_fb fingers = dif > 0 fingers = np.append(thumb_finger, fingers) mp_drawing.draw_landmarks( frame, hand_landmarks, mp_hands.HAND_CONNECTIONS, mp_drawing_styles.get_default_hand_landmarks_style(), mp_drawing_styles.get_default_hand_connections_style()) return fingers
De la línea 1 a la 80 hemos importado los packages que usaremos, pero además tenemos dos funciones: palm_centroid
que nos ayudará a determinar cuando los dedos índice, medio, anular y meñique están levantados o no, y fingers_up_down
, que nos devolverá un array de 5 elementos con True o False indicando cuando alguno de ellos está levantado o recogido.
mp_drawing = mp.solutions.drawing_utils mp_drawing_styles = mp.solutions.drawing_styles mp_hands = mp.solutions.hands cap = cv2.VideoCapture(0, cv2.CAP_DSHOW) # Pulgar thumb_points = [1, 2, 4] # Índice, medio, anular y meñique palm_points = [0, 1, 2, 5, 9, 13, 17] fingertips_points = [8, 12, 16, 20] finger_base_points =[6, 10, 14, 18] # FINGERS COMBINATIONS TO_ACTIVATE = np.array([True, False, False, False, False]) # Piedra, papel, tijeras PIEDRA = np.array([False, False, False, False, False]) PAPEL = np.array([True, True, True, True, True]) TIJERAS = np.array([False, True, True, False, False]) # REGLAS PIEDRA, PAPEL, TIJERAS (0, 1, 2) WIN_GAME = ["02", "10", "21"] pc_option = False # Si la pc ha escogido o no detect_hand = True THRESHOLD = 10 THRESHOLD_RESTART = 50 count_like = 0 count_piedra = 0 count_papel = 0 count_tijeras = 0 count_restart = 0 # Images to show image1 = cv2.imread("1.jpg") image2 = cv2.imread("2.jpg") image_winner = cv2.imread("3.jpg") image_tie = cv2.imread("4.jpg") image_loser = cv2.imread("5.jpg") # Image to concat imAux = image1 player = None
En la siguiente sección tenemos un conjunto de constantes y variables. De estas quisiera destacar WIN_GAME
. Que es la combinación que tendremos que conseguir para ganarle al computador.

Figura 3: Le ganaremos al computador con estas combinaciones. Nosotros estamos siendo representados por las ilustraciones con el aura celeste.
Recuerda que si tanto nosotros como la computadora elegimos la misma opción, será un empate. Por ello en la figura 3 tomamos en cuenta solo las combinaciones en las que podemos ganar. Tenemos en azul las opciones que podemos escoger, mientras que en verde las que escogería el computador. Si no hubiera un empate, y si lo que hemos escogido no está dentro de estas combinaciones, entonces perderíamos.
Tomemos en cuenta también que para piedra hemos asignado el número 0, papel 1, mientras que tijeras el 2. Por ello WIN_GAME
muestra dichas combinaciones en números (que han sido convertidas a strings para simplificar las comparaciones).
with mp_hands.Hands( model_complexity=1, max_num_hands=1, min_detection_confidence=0.5, min_tracking_confidence=0.5) as hands: while True: ret, frame = cap.read() if ret == False: break frame = cv2.flip(frame, 1) height, width, _ = frame.shape frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) results = hands.process(frame_rgb) if results.multi_hand_landmarks: fingers = fingers_up_down(results, thumb_points, palm_points, fingertips_points, finger_base_points) #print("fingers:", fingers) if detect_hand == True: if not False in (fingers == TO_ACTIVATE) and pc_option == False: if count_like >= THRESHOLD: pc = random.randint(0, 2) print("pc:", pc) pc_option = True imAux = image2 count_like += 1 if pc_option == True: if not False in (fingers == PIEDRA): if count_piedra >= THRESHOLD: player = 0 count_piedra += 1 elif not False in (fingers == PAPEL): if count_papel >= THRESHOLD: player = 1 count_papel += 1 elif not False in (fingers == TIJERAS): if count_tijeras >= THRESHOLD: player = 2 count_tijeras += 1 if player is not None: detect_hand = False if pc == player: imAux = image_tie else: if (str(player) + str(pc)) in WIN_GAME: imAux = image_winner else: imAux = image_loser count_restart += 1 if count_restart > THRESHOLD_RESTART: pc_option = False detect_hand = True player = None count_like = 0 count_piedra = 0 count_papel = 0 count_tijeras = 0 count_restart = 0 imAux = image1 n_image = cv2.hconcat([imAux, frame]) cv2.imshow("n_image", n_image) if cv2.waitKey(1) & 0xFF == 27: break cap.release() cv2.destroyAllWindows()
Y este es todo el programa. Por ello, el último apartado que veremos es la visualización de resultados:

Figura 4: Según lo programado, podremos empezar a jugar una vez que demos like 👍.
En la figura 4 podemos ver que lo primero que nos pide el juego para empezar a jugar, es un like. Una vez que se realice este gesto pasaremos a la siguiente immagen, en donde podremos elegir de entre piedra, papel o tijeras:

Figura 5: Listos para elegir piedra, papel o tijeras.
En la figura 5 tenemos que ya podemos elegir de entre estas tres opciones. Así que, si en esta ocasión vamos por tijeras el resultado será….

Figura 6: Resultado del juego, en esta ocasión.
Como puedes ver en la figura 6, el jugador le ha ganado al computador (esta vez). Por lo que se visualiza la imagen de un gatito muy contento con nuestro resultado.
Y bien, esto ha sido todo por el tutorial de hoy. ¡Espero que te haya gustado! 😊 Nos vemos en el siguiente… ¡Qué te vaya súper bien!.