Como usar MEDIAPIPE HANDS ?️ | Python – MediaPipe – OpenCV
MediaPipe me ha sorprendido mucho con las soluciones que nos ofrece, MediaPipe Hands es una de ellas. Esta nos permite detectar manos, identificándolas como izquierda o derecha. Pero además nos proporciona 21 hand landmarks o puntos de referencia con la ubicación de cada uno de los dedos así como la palma de la mano. Estoy segura de que cuando pruebes esta solución, se te vendrán un montón de aplicaciones a la mente. ¿Quieres saber como usarla?
CONTENIDO:
- MediaPipe hands
- Modelos empleados en MediaPipe Hands
- Modelo para la detección de la palma de la mano
- Modelo para la detección de los 21 puntos de referencia en la mano
- Opciones de configuración
- STATIC_IMAGE_MODE (POR DEFECTO FALSE)
- MAX_NUM_HANDS (POR DEFECTO 2)
- MIN_DETECTION_CONFIDENCE (POR DEFECTO 0.5)
- MIN_TRACKING_CONFIDENCE (POR DEFECTO 0.5)
- ¡Ahora si, vamos con el código!
- Detección de manos y puntos claves con MediaPipe, en imágenes
- Salida: multi_handedness
- Salida: multi_hand_landmarks
- Dibujando los 21 puntos de la mano y sus conexiones con MediaPipe
- Accediendo a los puntos claves mediante su nombre asociados
- Accediendo a los puntos claves mediante su índice
- Probando nuestro programa con una imagen que no contiene manos
- Detección de manos y puntos claves con MediaPipe, en videos
- Detección de manos y puntos claves con MediaPipe, en imágenes
- Modelos empleados en MediaPipe Hands
- Referencias
NOTA: Antes de pasar al tutorial sobre el uso de MediaPipe Hands, te recuerdo que necesitas instalar este framework en Python, por lo que si aún no lo has hecho, puede seguir este post: ? Como instalar MEDIAPIPE | Python.
MediaPipe Hands
Ahora si, vamos con MediaPipe Hands. Esta es una solución que permite la detección de manos, con 21 puntos de referencias 3D. Permitiendo identificar cada uno de los dedos y palma de la mano. Para ello MediaPipe emplea Machine Learning, de donde han obtenido múltiples modelos que trabajan juntos, para obtener los resultados que podemos apreciar a continuación:

Figura 1: Ejemplo del uso de MediaPipe para manos.
Modelos empleados en MediaPipe Hands
En la documentación de Mediapipe, se nos describe el proceso que realizaron para llegar a obtener estos resultados, así que vamos a hablar un poquito sobre ello.
Modelo para la detección de la palma de la mano

Figura 2: Ilustración del proceso que realiza Palm Detection Model.
En un principio tenemos un modelo para la detección de la palma de la mano. Este es el que se aplica en toda la imagen, intentando obtener alguna detección. En cuanto este detector haya encontrado una palma, devolverá un cuadro delimitador orientado de la mano.
Modelo para la detección de los 21 puntos referencia en la mano
Una vez obtenida el área en donde se encuentra la mano, la imagen pasara por un hand landmark model, que es el modelo que permitirá ubicar los 21 puntos de referencia en la imagen dada por la detección de palma.

Figura 3: Ilustración del proceso que realiza Hand Landmark Model.
Estos 21 hands landmark tienen asociados un nombre cada uno. Ya veremos más adelante como emplear sus nombres e índices para acceder las coordenadas de estos puntos en la imagen.

Figura 4: 21 puntos de referencia y sus nombres asociados. Su documentación la puedes encontrar aquí: https://google.github.io/mediapipe/solutions/hands#hand-landmark-model
Este proceso de por si ya es muy interesante de analizar, y se puede aplicar a imágenes de entrada. Pero ¿qué pasa con los videos?. Pues bien, en ese caso han desarrollado un método en el cual se aplique la detección de palmas y el modelo hand landmark, en las primeros fotogramas.
Una vez obtenidos los 21 puntos de referencia, estos son rastreados para calcular la nueva ubicación de la mano.
De este modo no se está aplicando la detección de palmas a cada momento, sino que se realiza seguimiento o tracking del área ya encontrada en primer lugar. Invocando al detector de palmas únicamente cuando los puntos no se puedan identificar. Reduciendo así la latencia.
En si este es un resumen del proceso que nos describen en mediapipe, por lo que si quieres profundizar un poquito más estos aspectos, te recomiendo que visites su web y su repositorio.
Opciones de configuración
Antes de pasar al resto del programa, necesitaremos explorar las opciones de configuración.
STATIC_IMAGE_MODE (POR DEFECTO FALSE)
En primer lugar tenemos a static_image_mode, que puede tener valores de True o False. Cuando se le asigna False, entonces trata a las imágeness de entrada como un videostream, de tal manera que aplica el modelo de detección de palma y el modelo hand landmarks en un principio, pero luego realiza tracking para obtener la nueva ubicación de la mano, basándose en los puntos de referencia. De este modo, solo se invocará nuevamente al detector de palmas cuando no se hayan identificado los 21 puntos.
Cuando se le asigna True, entonces los detectores estarán aplicádose en cada imagen, por lo que es mejor usarla en caso de que se trate de imágenes que no tengan que ver entre sí.
MAX_NUM_HANDS (POR DEFECTO 2)
Número máximo de manos por detectar.
MIN_DETECTION_CONFIDENCE (POR DEFECTO 0.5)
Valor mínimo de confianza del modelo de detección de manos, para que la detección sea considerada como exitosa. Sus valores comprenden de 0 a 1.
MIN_TRACKING_CONFIDENCE (POR DEFECTO 0.5)
Valor mínimo de confianza del modelo de rastreo de los landmark, para que el rastreo de los 21 puntos sea considerado como exitoso. En caso de no serlo, se invocará al detector de manos en la siguiente imagen.
Este es ignorado si static_image_mode está en True.
¡Ahora si, vamos con el código!
Detección de manos y puntos claves con MediaPipe, en imágenes
Como imagen de entrada, tendremos la siguiente:

Figura 5: Imagen de entrada que usaremos a lo largo de este tutorial.
También probaremos más adelante con una imagen que no posea manos, simplemente para probar que nuestro programa actúe correctamente.
Ahora vamos a crear nuevo script llamado manos_imagen_mediapipe.py
import cv2 import mediapipe as mp mp_drawing = mp.solutions.drawing_utils mp_hands = mp.solutions.hands
Línea 1 y 2: Importamos OpenCV y MediaPipe con un alias mp
. Recuerda que la instalación de MediaPipe la vimos en el post: ? Como instalar MEDIAPIPE | Python. Y una vez que lo instalábamos, este instalaba automáticamente OpenCV.
Línea 4: Ahora vamos con mp.solutions.drawing_utils
, y lo igualamos a mp_drawing
. Este nos ayudará más adelante a dibujar los resultados de las detecciones, es decir los 21 puntos y sus conexiones.
Línea 5: Ya que vamos a emplear la solución hands, vamos a igualar mp.solutions.hands
a mp_hands
.
with mp_hands.Hands( static_image_mode=True, max_num_hands=1, min_detection_confidence=0.5) as hands:
Línea 7 a 10: Vamos con las opciones de configuración. En nuestro caso static_image_mode
será True
ya que estamos tomando como entrada una imagen. max_num_hands
1 aunque podríamos modificarlo a cualquier número entero dependiendo del número de manos que queramos que se detecte, y min_detection_confidence
0.5.
image = cv2.imread("imagen_0001.jpg") height, width, _ = image.shape image = cv2.flip(image, 1) image_rgb =cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
Línea 12 a 16: Ahora procederemos a leer la imagen de entrada con OpenCV, y a obtener el alto y ancho de ella. Además vamos a voltear la imagen horizontalmente. Necesitamos voltearla horizontalmente, ya que para que una mano sea determinada como izquierda o derecha, se asume que la imagen de entrada está reflejada. Necesitaremos también, pasar nuestra imagen de entrada de BGR a RGB, ya que las detecciones se realizan con imágenes en RGB.
results = hands.process(image_rgb)
Línea 18: Una vez que tenemos nuestra imagen lista, la pasaremos por process
, de donde podremos obtener las detecciones, mediante las salidas: multi_handedness y multi_hand_landmarks.
Salida: multi_handedness
# HANDEDNESS print('Handedness:', results.multi_handedness)
Línea 21: Imprimamos lo que tenemos en multi_handedness.

Figura 6: Impresión de la salida handedness, que obtuvimos al realizar el proceso de detección sobre la imagen de entrada, estableciendo max_num_hands=1.
Como puedes ver en la figura 6, obtenemos una colección de datos de la mano detectada. Tenemos el label o la etiqueta en donde podremos identificar si se trata de una mano derecha o izquierda, en este caso Rigth o Left. Además tenemos score
, que es la probabilidad estimada de la predicción.
Recuerda que hemos obtenido los datos de una sola mano, ya que en max_num_hands
lo habíamos establecido en 1.
Si cambiamos el valor de max_num_hands
por 2, y ejecutamos nuevamente el programa, entonces como puedes ver, obtenemos los datos de ambas manos.

Figura 7: Impresión de la salida handedness, que obtuvimos al realizar el proceso de detección sobre la imagen de entrada, estableciendo max_num_hands=2.
Hasta ahora sabemos que existe una mano derecha y una izquierda en la imagen.
Salida: multi_hand_landmarks
# HAND LANDMARKS print('Hand landmarks:', results.multi_hand_landmarks)
Línea 23: Ahora veremos multi_hand_landmarks
, que es una colección de manos rastreadas o detectadas, donde cada mano está representado como una lista de 21 puntos, en donde cada punto está compuesto por las coordenadas x, y, z.

Figura 8: Impresión de una porción de la salida multi_hand_landmarks, que obtuvimos al realizar el proceso de detección sobre la imagen de entrada.
Y como podemos en la figura 8, tenemos cada uno de los 21 puntos con sus coordenadas, que están en decimales, y no enteros, como los que hemos trabajado antes, en otros tutoriales para determinar las coordenadas en la imagen. Pero ya veremos más adelante como acceder a estos puntos como coordenadas de la imagen.
Dibujando los 21 puntos de la mano y sus conexiones con MediaPipe
Ahora vamos a ver como podemos dibujar los 21 puntos de los hand landmarks con ayuda de mediapipe, y luego veremos como acceder a las coordenadas x e y de estos puntos, ya sea por su nombre o por su índice.
if results.multi_hand_landmarks is not None: # Dibujando los puntos y las conexiones mediante mp_drawing for hand_landmarks in results.multi_hand_landmarks: mp_drawing.draw_landmarks( image, hand_landmarks, mp_hands.HAND_CONNECTIONS, mp_drawing.DrawingSpec(color=(255,255,0), thickness=4, circle_radius=5), mp_drawing.DrawingSpec(color=(255,0,255), thickness=4))
Línea 25: Para evitar cualquier problema en la ejecución del programa, cuando no hayan manos presentes en la imagen. Voy a añadir la condición de que se realice a visualización de los puntos, siempre y cuando results.multi_hand_landmarks
no sea None
.
Línea 27: Vamos a usar un for para obtener cada grupo de 21 puntos por cada mano detectada.
Línea 28 a 31: Comenzaremos dibujando los puntos y conexiones con ayuda del propio mediaPipe, para ello usaremos mp_drawing.draw_landmarks
. Allí tendremos que especificar la imagen en donde queremos que se dibujen los puntos, los 21 puntos detectados y especificamos mp_hands.HAND_CONNECTIONS
para que se dibujen las conexiones entre los puntos.
En la línea 30, podremos modificar le color, grosor de línea y radio de cada punto detectado, mientras que en la línea 31 podremos modificar el color y grosor de línea de las conexiones.
NOTA: Si no especificamos las líneas 30 y 31, MediaPie de igual forma mostrará las detecciones con los colores por defecto establecidos para esta solución, es decir con rojo y verde.
image = cv2.flip(image, 1) cv2.imshow("Image",image) cv2.waitKey(0) cv2.destroyAllWindows()
Línea 33: Luego de que realicemos todo el proceso de detección, necesitaremos voltear nuevamente la imagen, para dejarla con la orientación original. Y procedemos a visualizar la imagen hasta que una tecla sea presionada.

Figura 9: Visualizaciones de los puntos detectados y sus conexiones. Izq. Para esta imagen solo he establecido que se detecte una mano ya que he usado max_num_hands=1, y no he especificado colores para los puntos ni conexiones (no he usado las líneas 30 y 31). Der. Tenemos dos manos detectadas ya que he establecido max_num_hands=2, y los puntos y conexiones se muestran de otros colores ya que aquí si he usado las líneas 30 y 31.
Como has visto dibujamos todos los puntos y conexiones, pero esto lo hacía directamente la función de MediaPipe. Si tomaramos las coordenadas de los landmarks así como están, en decimales, no podríamos usarlos ya que necesitamos coordenadas en enteros y además que estén en la escala de la imagen.
Por ello ahora veremos como obtener las coordenadas, para usarlas en la imagen empleando los nombres de cada uno de los hand landmarks.
NOTA: Voy a usar la misma estructura del programa hasta la línea 25 para los siguientes temas, así que voy solo a describir los procesos que vienen luego de esta línea.
Accediendo a los puntos claves mediante su nombre asociado
Voy tratar de acceder a solo las puntas de cada dedo, para ello voy a estar usando los nombres establecidos por MediaPipe, es decir: THUMB_TIP, INDEX_FINGER_TIP, MIDDLE_FINGER_TIP, RING_FINGER_TIP y PINKY_TIP. Como lo tenemos en la figura 4.
if results.multi_hand_landmarks is not None: # Accediendo a los puntos de referencia, de acuerdo a su nombre for hand_landmarks in results.multi_hand_landmarks: x1 = int(hand_landmarks.landmark[mp_hands.HandLandmark.THUMB_TIP].x * width) y1 = int(hand_landmarks.landmark[mp_hands.HandLandmark.THUMB_TIP].y * height)
Línea 28: Comencemos entonces con THUMB_TIP
que corresponde al pulgar. Para ello vamos a especificar hand_landmarks.landmark
y entre corchetes digitamos mp_hands.HandLandmark
. Luego el nombre establecido para la punta del dedo pulgar, es decir THUMB_TIP
. Y para acceder a la coordenada x, tendremos que digitar .x
. Ya que estamos en la coordenada x, lo multiplicaremos por el ancho de la imagen, y todo esto debe estar dentro de int
para obtener el valor entero.
Línea 29: Para obtener la coordenada y
del pulgar, tendremos que seguir el mismo procedimiento, lo único que cambiará es que debemos pedir y
y multiplicarlo por el alto de la imagen.
x2 = int(hand_landmarks.landmark[mp_hands.HandLandmark.INDEX_FINGER_TIP].x * width) y2 = int(hand_landmarks.landmark[mp_hands.HandLandmark.INDEX_FINGER_TIP].y * height) x3 = int(hand_landmarks.landmark[mp_hands.HandLandmark.MIDDLE_FINGER_TIP].x * width) y3 = int(hand_landmarks.landmark[mp_hands.HandLandmark.MIDDLE_FINGER_TIP].y * height) x4 = int(hand_landmarks.landmark[mp_hands.HandLandmark.RING_FINGER_TIP].x * width) y4 = int(hand_landmarks.landmark[mp_hands.HandLandmark.RING_FINGER_TIP].y * height) x5 = int(hand_landmarks.landmark[mp_hands.HandLandmark.PINKY_TIP].x * width) y5 = int(hand_landmarks.landmark[mp_hands.HandLandmark.PINKY_TIP].y * height) cv2.circle(image, (x1, y1), 3,(255,0,0),3) cv2.circle(image, (x2, y2), 3,(255,0,0),3) cv2.circle(image, (x3, y3), 3,(255,0,0),3) cv2.circle(image, (x4, y4), 3,(255,0,0),3) cv2.circle(image, (x5, y5), 3,(255,0,0),3)
Línea 31 a 41: Ahora para los otros 4 dedos, seguiremos con el mismo procedimiento, solo tendríamos que cambiar el nombre del punto al cual deseamos acceder a sus coordenadas x e y.
Línea 43 a 47: Y una vez que tengamos cada una de las coordenadas, podemos dibujar un círculo por cada dedo con la ayuda de cv2.circle.
image = cv2.flip(image, 1) cv2.imshow("Image",image) cv2.waitKey(0) cv2.destroyAllWindows()
Ahora vamos a probar el programa que hemos realizado para obtener los puntos correspondientes a las puntas de los dedos:

Figura 10: Visualizaciones de los puntos a los que accedimos mediante sus nombres. En este caso se detectan los puntos en ambas manos, ya que se ha establecido max_num_hands=2.
Accediendo a los puntos claves mediante su índice
Veremos otra forma a la que podemos acceder a los puntos correspondientes a las puntas de los dedos. Para ello nos ayudaremos de los índices que ocupa cada hand landmark de nuestro interés.
if results.multi_hand_landmarks is not None: # Accediendo al valor de los puntos por su índice index = [4, 8, 12, 16, 20] for hand_landmarks in results.multi_hand_landmarks: for (i, points) in enumerate(hand_landmarks.landmark): if i in index: x = int(points.x * width) y = int(points.y * height) cv2.circle(image, (x, y), 3,(255, 0, 255), 3)
Línea 27: Creamos una lista que contendrá los índices a los que deseamos acceder es decir: 4, 8, 12, 16, 20. Entos los puedes ver en la figura 4.
Línea 28 a 33: Dentro del ciclo for voy a insertar un nuevo ciclo for, esta vez para que recorra cada uno de los 21 puntos de cada mano, y además en i
se irá incrementando en uno de acuerdo a las iteraciones. Entonces añadimos una condición. De tal forma que si i
(que irá tomando valores de de 0 a 20), está presente en la lista index
, se proceda a obtener las coordenadas x e y, y que además se dibuje un círculo con estas coordenadas.
Recuerda que para obtener las coordenadas x e y, seguimos un procedimiento bastante similar a lo que hicimos antes, cuando accedíamos por los nombres. Esto se realiza en las líneas 31 y 32.
image = cv2.flip(image, 1) cv2.imshow("Image",image) cv2.waitKey(0) cv2.destroyAllWindows()
Ejecutamos este programa para visualizar los resultados.

Figura 11: Visualización de los puntos que accedimos mediante su índice. Se visualizan los resultados en una sola mano ya que max_num_hands lo he establecido en 1.
Probando nuestro programa con una imagen que no contiene manos
Veamos los resultados al probar nuestros programas en una imagen que no contiene manos:

Figura 12: Prueba de nuestro programa con una imagen que no contiene manos. Podemos apreciar en la parte derecha tenemos None en Handedness, debido a que no existen manos en la imagen.
Detección de manos y puntos claves con MediaPipe, en videos
Finalmente, vamos a ver un ejemplo de como emplear mediapipe hands en un video stream. Para ello seguiremos un proceso similar. Solo que esta vez tendremos que especificar cv2.VideoCapture.
import cv2 import mediapipe as mp mp_drawing = mp.solutions.drawing_utils mp_hands = mp.solutions.hands cap = cv2.VideoCapture(0, cv2.CAP_DSHOW) with mp_hands.Hands( static_image_mode=False, max_num_hands=2, min_detection_confidence=0.5) as hands:
Línea 10: En este caso, ya que se trata de un video, en la opción de configuración correspondiente a static_image_mode
la especifico como False.
while True: ret, frame = cap.read() if ret == False: break height, width, _ = frame.shape frame = cv2.flip(frame, 1) 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: mp_drawing.draw_landmarks( frame, hand_landmarks, mp_hands.HAND_CONNECTIONS, mp_drawing.DrawingSpec(color=(0,255,255), thickness=3, circle_radius=5), mp_drawing.DrawingSpec(color=(255,0,255), thickness=4, circle_radius=5)) cv2.imshow('Frame',frame) if cv2.waitKey(1) & 0xFF == 27: break cap.release() cv2.destroyAllWindows()
Como puedes apreciar, el procedimiento es bastante parecido a lo que habíamos realizado para las imágenes. La diferencia es que ahora tendremos que leer un video stream.
Veamos los resultados de este programa:

Figura 13: Visualización de los 21 puntos por cada mano y sus conexiones.
Como vez en la figura 13, pudimos realizar la detección usando MediaPipe Hands en un video stream o video en vivo. Y estos se adaptan muy bien, incluso cuando muevo mis dedos para realizar una especie de corazón en la figura 13 en la sección derecha.
Sin duda alguna, esta solución que nos ofrece MediaPipe es impresionante, no solo se desempeña muy bien detectando cada uno de los puntos, sino que también la podemos usar con el CPU, y sigue trabajando muy bien. Espero puedas experimentar con MediaPipe Hands, y realices muchos proyectos aplicándolo.
Y hemos llegado al final de este post. Espero que te haya gustado y sido útil a la vez. Nos vemos en un siguiente video/tutorial, chao, chao. 😀
Referencias
- https://google.github.io/mediapipe/solutions/hands#mediapipe-hands
- https://github.com/google/mediapipe
Super interesante! Y justo lo que andaba buscando, muy bueno y excelente el contenido de tu web! Saludos.
Me alegra mucho que te guste el contenido, muchas gracias. 🙂
Wou, si que eres buena en esto! Tengo una consulta, si quiero usar la librería mp de forma comercial (integrar los algoritmos en cámaras)¿Tiene algún costo o algo así?
Tengo un problema y es que a la hora de correr el programa me marca como error el cv2 dice esto:
» ModuleNotFoundError: No module named ‘cv2’ »
y me pasa lo mismo cuando intento correr un entorno virtual el cmd dice que no se reconoce como comando interno pero ya lo reinstale varias veces ayudaplis
Hola.
Me parece genial tu trabajo, intenté ponerme en contacto a través del email de la página pero no recibí respuesta, no sé si lo revises, me gustaría ponerme en contacto contigo para ver si te interesa partiipar en un proyecto profesional.
Saludos
Hola Buena tarde
Antes que nada, tienes un blog excelente, me encanta y es bastante educativo
Tengo una duda, quiero construir un traductor de LSM en tiempo real usando la cámara de mi celular y estaba explorando algunas opciones para poder hacerlo, he aprendido mucho con tus ejemplos pero hay algo que no me queda claro, tomando en cuenta que algunas palabras en LSM utilizan movimientos muy específicos de las manos o de los dedos y esos movimiento dan el significado, que es lo que me recomendarías que aprendiera o como puedo clasificar esos movimientos para poder indicar que si una mano gira y la otra se mueve de un lado a otro significa cierta palabra, ando algo perdido y agradecería de sobremanera tu ayuda en estos
Muchas gracias!!
Hola, tus videos son geniales y me han sido de mucha ayuda pero he tenido un problema que no he podido arreglar.
El problema es al agregar la imagen de entra y la carpeta de imagenes al sistema, apenas estoy aprendiendo y al llegar a este paso no se como hacer que el programa use las imagenes de entrada que son las manos y asi.
espero puedas guiarme ):
Fenomenal explicación.
¿Cómo se podría aplicar a una app de Android?
Saludos !
hola
se pede separar la pocicion de la mano derecha y la mano izquierda