
Visión artificial 3° A
- AGR
- Web , Programación
- 05 Jan, 2025
Link de la sesion de meet:
Link para la reunion de domingo 16 febrero 2025 actualizada https://meet.google.com/aox-anan-ttp
Índice
- Link de la sesion de meet:
- Explicación del Proyecto
- Desarrollo
- Tutorial: Detección de Dedos y Juego de Piedra, Papel o Tijera
- Electrónica
- Programación
- Desafíos
- Recursos
- Explicación detallada del código para detección de dedos con MediaPipe y OpenCV
Explicación del Proyecto
Materiales necesarios
- 1 Arduino
- 5 Servomotores
- 1 Protoboard
- 1 Fuente de alimentación
- 1 Cable USB
Herramientas
- 1 Destornillador
- 1 Pinza
- 1 Tijera
- 1 Cautín
- 1 Soldadura
- 1 Cableado
Desarrollo
Instalacion de pyton
-
Descarga la version recomendada para el proyecto python 3.12
-
Instala PowerShell aqui
-
Instala las dependencias necesaias
py -m pip install --upgrade pip
pip install mediapipe
pip install opencv-python
pip install pyserial
Tutorial: Detección de Dedos y Juego de Piedra, Papel o Tijera
Este tutorial se divide en 6 etapas, en las que se explica paso a paso cómo llegar al proyecto final. Aprenderás desde la introducción a las librerías necesarias, pasando por la detección de dedos con MediaPipe, hasta la implementación de un juego interactivo.
Etapa 1: Explicación de las Librerías
En esta etapa se presentan las librerías utilizadas:
- OpenCV (
cv2
): Biblioteca para procesamiento de imágenes y video. - MediaPipe (
mediapipe
): Framework para aplicaciones de visión por computadora en tiempo real (por ejemplo, detección de manos). - NumPy (
numpy
): Biblioteca para manejo de arrays y operaciones matemáticas.
Ejemplo de importación:
import cv2 # Manejo de imágenes y video
import mediapipe as mp # Detección y seguimiento de manos
import numpy as np # Operaciones matemáticas y manejo de arrays
Etapa 2: Introducción a Python y Ejecución de Códigos Sencillos
Python es un lenguaje de programación sencillo y poderoso. Para comenzar:
- Instalación: Descarga e instala Python desde python.org.
- Editor/IDE: Puedes usar editores como VSCode, PyCharm o incluso Jupyter Notebook.
- Ejecución: Escribe un código sencillo, guarda el archivo (por ejemplo,
hola.py
) y ejecútalo desde la terminal con:
python hola.py
Ejemplo de código simple:
# Imprime "Hola, mundo!" en la consola
print("Hola, mi nombre es:")
Etapa 3: Lectura de los Dedos de la Mano
Utilizando MediaPipe, podemos detectar la mano y sus puntos clave (landmarks). El proceso es el siguiente:
- Captura de video: Se obtiene el frame desde la cámara.
- Conversión de color: OpenCV captura en BGR; MediaPipe requiere RGB.
- Procesamiento: MediaPipe detecta la mano y devuelve los landmarks.
- Visualización: Se dibujan los puntos y conexiones en el frame.
Etapa 4: Modificaciones para Detectar tus Propias Posiciones
Puedes personalizar el sistema modificando:
- Índices de landmarks: Cada dedo tiene un conjunto de índices (por ejemplo, el pulgar usa los puntos 4 y 3).
- Condiciones de comparación: Cambia la comparación de coordenadas (
x
oy
) para ajustar la detección según la forma en que sostienes la mano.
Ejemplo:
# Compara la posición X para detectar si el pulgar está levantado
if hand_landmarks.landmark[4].x < hand_landmarks.landmark[3].x:
# Pulgar levantado
Etapa 5: Código de Detección de Dedos
A continuación, se presenta el código completo para la detección de dedos:
import cv2 # Importar OpenCV para manejo de video e imágenes
import mediapipe as mp # Importar MediaPipe para detección de manos
import numpy as np # Importar NumPy para operaciones numéricas
# Inicializar la solución de manos de MediaPipe
mp_hands = mp.solutions.hands
mp_drawing = mp.solutions.drawing_utils # Utilidad para dibujar la estructura de la mano
# Configuración de MediaPipe Hands
hands = mp_hands.Hands(
static_image_mode=False, # Modo video (detección continua)
max_num_hands=1, # Se detecta solo una mano
min_detection_confidence=0.7, # Confianza mínima para la detección inicial
min_tracking_confidence=0.7 # Confianza mínima para el seguimiento
)
# Función para contar los dedos levantados usando los landmarks
def count_fingers(hand_landmarks):
# Índices de las puntas de los dedos (thumb, index, middle, ring, pinky)
finger_tips = [4, 8, 12, 16, 20]
# Índices de las bases de cada dedo (usados para comparación)
finger_base = [3, 6, 10, 14, 18]
fingers = [] # Lista que almacenará 1 (dedo levantado) o 0 (dedo no levantado)
# Evaluar el pulgar (se compara la posición en el eje X)
if hand_landmarks.landmark[finger_tips[0]].x < hand_landmarks.landmark[finger_base[0]].x:
fingers.append(1) # Pulgar levantado
else:
fingers.append(0) # Pulgar no levantado
# Evaluar los otros dedos (comparando la posición en el eje Y)
for i in range(1, 5):
if hand_landmarks.landmark[finger_tips[i]].y < hand_landmarks.landmark[finger_base[i]].y:
fingers.append(1) # Dedo levantado
else:
fingers.append(0) # Dedo no levantado
return sum(fingers) # Retornar el número total de dedos levantados
# Inicializar la cámara web
cap = cv2.VideoCapture(0)
while cap.isOpened():
ret, frame = cap.read() # Capturar frame por frame
if not ret:
break # Salir si no se puede leer un frame
# Convertir el frame de BGR a RGB para procesarlo con MediaPipe
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# Procesar el frame para detectar manos
results = hands.process(frame_rgb)
# Si se detecta una mano, dibujar los landmarks y contar dedos
if results.multi_hand_landmarks:
for hand_landmarks in results.multi_hand_landmarks:
# Dibujar la estructura (puntos y conexiones) de la mano en el frame
mp_drawing.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS)
# Contar la cantidad de dedos levantados
fingers_up = count_fingers(hand_landmarks)
# Mostrar el número de dedos levantados en la ventana
cv2.putText(frame, f'Dedos levantados: {fingers_up}', (10, 70),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
# Mostrar el video con la detección de manos
cv2.imshow('Detección de Dedos', frame)
# Salir presionando la tecla 'q'
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# Liberar la cámara y cerrar todas las ventanas abiertas
cap.release()
cv2.destroyAllWindows()
Etapa 6: Juego de Piedra, Papel o Tijera
En esta etapa implementamos un juego interactivo usando la detección de dedos. Se asignan los siguientes gestos:
- Rock (Piedra): 0 dedos levantados (puño cerrado)
- Scissors (Tijera): 2 dedos levantados (por ejemplo, índice y medio)
- Paper (Papel): 5 dedos levantados (mano abierta)
Además, se implementa una cuenta regresiva para capturar el gesto del usuario y se genera un movimiento aleatorio para la computadora. Se compara el resultado y se muestra en pantalla.
A continuación, el código completo con comentarios:
import cv2 # Importar OpenCV para manejo de video e imágenes
import mediapipe as mp # Importar MediaPipe para detección de manos
import numpy as np # Importar NumPy para operaciones numéricas
import random # Importar random para seleccionar movimientos aleatorios
import time # Importar time para gestionar la cuenta regresiva y temporizadores
# Inicializar MediaPipe Hands y la utilidad de dibujo
mp_hands = mp.solutions.hands
mp_drawing = mp.solutions.drawing_utils
# Configuración de MediaPipe Hands para detección en tiempo real
hands = mp_hands.Hands(
static_image_mode=False, # Modo video
max_num_hands=1, # Detectar solo una mano
min_detection_confidence=0.7, # Umbral de confianza para la detección inicial
min_tracking_confidence=0.7 # Umbral de confianza para el seguimiento
)
# Función para contar los dedos levantados (igual que en la etapa anterior)
def count_fingers(hand_landmarks):
finger_tips = [4, 8, 12, 16, 20] # Índices de las puntas de cada dedo
finger_base = [3, 6, 10, 14, 18] # Índices para las bases de cada dedo
fingers = [] # Lista para almacenar 1 (levantado) o 0 (no levantado)
# Evaluar el pulgar (se compara en el eje X)
if hand_landmarks.landmark[finger_tips[0]].x < hand_landmarks.landmark[finger_base[0]].x:
fingers.append(1) # Pulgar levantado
else:
fingers.append(0) # Pulgar no levantado
# Evaluar los otros dedos (comparando en el eje Y)
for i in range(1, 5):
if hand_landmarks.landmark[finger_tips[i]].y < hand_landmarks.landmark[finger_base[i]].y:
fingers.append(1) # Dedo levantado
else:
fingers.append(0) # Dedo no levantado
return sum(fingers) # Retornar la suma de dedos levantados
# Función para mapear el número de dedos al gesto correspondiente
def get_gesture(fingers_up):
if fingers_up == 0:
return "Rock" # Puño cerrado representa 'Piedra'
elif fingers_up == 2:
return "Scissors" # Dos dedos levantados representan 'Tijera'
elif fingers_up == 5:
return "Paper" # Cinco dedos levantados representan 'Papel'
else:
return "Unknown" # Cualquier otro número no es reconocido
# Función para determinar el ganador del juego
def determine_winner(user_move, computer_move):
# Reglas del juego:
# - Rock vence a Scissors
# - Scissors vence a Paper
# - Paper vence a Rock
if user_move == computer_move:
return "Tie" # Empate
elif (user_move == "Rock" and computer_move == "Scissors") or \
(user_move == "Scissors" and computer_move == "Paper") or \
(user_move == "Paper" and computer_move == "Rock"):
return "User wins!" # Gana el usuario
else:
return "Computer wins!" # Gana la computadora
# Inicializar la cámara web
cap = cv2.VideoCapture(0)
# Variables para manejar la cuenta regresiva y el estado del juego
start_time = time.time() # Tiempo de inicio para la cuenta regresiva
game_started = False # Indica si ya se capturó el movimiento
captured_move = None # Almacena el movimiento detectado del usuario
while cap.isOpened():
ret, frame = cap.read() # Capturar un frame de la cámara
if not ret:
break
# Voltear el frame horizontalmente para un efecto de espejo
frame = cv2.flip(frame, 1)
# Convertir el frame de BGR a RGB para MediaPipe
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# Procesar el frame para detectar la mano
results = hands.process(frame_rgb)
# Variable para almacenar el gesto detectado en el frame actual
user_move = "No hand detected"
# Si se detecta una mano, dibujar landmarks y contar dedos
if results.multi_hand_landmarks:
for hand_landmarks in results.multi_hand_landmarks:
# Dibujar la estructura de la mano en el frame
mp_drawing.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS)
# Contar los dedos levantados
fingers_up = count_fingers(hand_landmarks)
# Mapear el número de dedos al gesto correspondiente
user_move = get_gesture(fingers_up)
# Mostrar el gesto detectado en el frame
cv2.putText(frame, f'Gesture: {user_move}', (10, 50),
cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
# Calcular el tiempo transcurrido para la cuenta regresiva
elapsed = time.time() - start_time
if elapsed < 3:
# Mostrar la cuenta regresiva (3, 2, 1...) en pantalla
cv2.putText(frame, f'Prepare: {int(3 - elapsed)}', (200, 50),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), 2)
else:
if not game_started:
# Al finalizar la cuenta regresiva, capturamos el movimiento del usuario
captured_move = user_move
# Seleccionar aleatoriamente el movimiento de la computadora
computer_move = random.choice(["Rock", "Paper", "Scissors"])
# Determinar el resultado del juego comparando ambos movimientos
result = determine_winner(captured_move, computer_move)
game_started = True # Indicar que el movimiento ya fue capturado
result_time = time.time() # Guardar el tiempo para mostrar el resultado
else:
# Mostrar en pantalla el movimiento del usuario, de la computadora y el resultado
cv2.putText(frame, f'Your Move: {captured_move}', (10, 100),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
cv2.putText(frame, f'Computer: {computer_move}', (10, 150),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
cv2.putText(frame, f'Result: {result}', (10, 200),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
# Reiniciar el juego después de 5 segundos para una nueva ronda
if time.time() - result_time > 5:
game_started = False
start_time = time.time() # Reiniciar la cuenta regresiva
# Mostrar el frame actualizado con el juego
cv2.imshow('Rock Paper Scissors', frame)
# Salir del juego presionando la tecla 'q'
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# Liberar la cámara y cerrar todas las ventanas
cap.release()
cv2.destroyAllWindows()
Codigo ejemplo
import cv2
import mediapipe as mp
import numpy as np
# Inicializar MediaPipe Hands
mp_hands = mp.solutions.hands
mp_drawing = mp.solutions.drawing_utils
# Configuración de MediaPipe Hands
hands = mp_hands.Hands(
static_image_mode=False,
max_num_hands=1,
min_detection_confidence=0.7,
min_tracking_confidence=0.7
)
# Función para contar dedos
def count_fingers(hand_landmarks):
# Coordenadas de los dedos basadas en los puntos clave de MediaPipe
finger_tips = [4, 8, 12, 16, 20]
finger_base = [3, 6, 10, 14, 18]
fingers = []
# Pulgar (comparar posición X)
if hand_landmarks.landmark[finger_tips[0]].x < hand_landmarks.landmark[finger_base[0]].x:
fingers.append(1)
else:
fingers.append(0)
# Otros dedos (comparar posición Y)
for i in range(1, 5):
if hand_landmarks.landmark[finger_tips[i]].y < hand_landmarks.landmark[finger_base[i]].y:
fingers.append(1)
else:
fingers.append(0)
return sum(fingers)
# Inicializar la cámara
cap = cv2.VideoCapture(0)
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
# Convertir a RGB
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# Procesar el marco
results = hands.process(frame_rgb)
# Dibujar y contar dedos
if results.multi_hand_landmarks:
for hand_landmarks in results.multi_hand_landmarks:
mp_drawing.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS)
fingers_up = count_fingers(hand_landmarks)
cv2.putText(frame, f'Dedos levantados: {fingers_up}', (10, 70), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
# Mostrar el video
cv2.imshow('Detección de Dedos', frame)
# Salir con la tecla 'q'
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# Liberar recursos
cap.release()
cv2.destroyAllWindows()
Como ejecutar el programa
- en vscode seleccionar interprete y despues run
- en powershell ir a la carpeta contenedora y usar el comando
py deteccion_manos.py
Electrónica
Programación
Desafíos
Recursos
Videos
Video de ensamble de brazo robotico
Código
Aqui el codigo para mapear
import cv2
import mediapipe as mp
import numpy as np
# Inicializar MediaPipe Hands y Drawing Utils
mp_hands = mp.solutions.hands
mp_drawing = mp.solutions.drawing_utils
# Configuración de MediaPipe Hands (se usa 1 mano, se puede ajustar según necesidad)
hands = mp_hands.Hands(
static_image_mode=False,
max_num_hands=1,
min_detection_confidence=0.7,
min_tracking_confidence=0.7
)
# Diccionario de mapeo complejo
# La clave es una tupla de 10 elementos, correspondiente a:
# (thumb_extended, thumb_curved, index_extended, index_curved,
# middle_extended, middle_curved, ring_extended, ring_curved,
# pinky_extended, pinky_curved)
#
# Los valores asociados son etiquetas que tú defines (por ejemplo, nombres de gestos o letras).
complex_gesture_mapping = {
(1, 1, 0, 0, 0, 0, 0, 0, 0, 0): 'PUNIO_CERRADO', # Puño cerrado
(0, 1, 1, 1, 1, 1, 1, 1, 1, 1): 'PALMA_ABIERTA', # Mano abierta
(0, 1, 0, 0, 0, 0, 0, 0, 0, 0): 'PULGAR_ARRIBA', # Ejemplo: solo el pulgar extendido y con curvatura (personalizable)
(1, 1, 1, 1, 0, 0, 0, 0, 0, 0): 'NUMERO_1', # NUMERO 1
# Puedes agregar más mapeos según las posiciones definidas en tu proyecto
}
def detect_complex_gesture(hand_landmarks):
"""
Genera un vector de 10 elementos (2 por cada dedo) usando varios landmarks:
- Para cada dedo, se calcula:
* "Extended": se compara la posición del tip con la base (PIP o similar)
* "Curved": se compara la posición del DIP (o el punto intermedio) con la base
La lógica puede ajustarse según las características de la seña.
"""
features = []
# Pulgar: usamos landmarks 4 (tip), 3 (IP) y 2 (MCP)
thumb_extended = 1 if hand_landmarks.landmark[4].x < hand_landmarks.landmark[3].x else 0
thumb_curved = 1 if hand_landmarks.landmark[4].y < hand_landmarks.landmark[2].y else 0
features.extend([thumb_extended, thumb_curved])
# Índice: landmarks 8 (tip), 6 (PIP) y 7 (DIP)
index_extended = 1 if hand_landmarks.landmark[8].y < hand_landmarks.landmark[6].y else 0
index_curved = 1 if hand_landmarks.landmark[7].y < hand_landmarks.landmark[6].y else 0
features.extend([index_extended, index_curved])
# Medio: landmarks 12 (tip), 10 (PIP) y 11 (DIP)
middle_extended = 1 if hand_landmarks.landmark[12].y < hand_landmarks.landmark[10].y else 0
middle_curved = 1 if hand_landmarks.landmark[11].y < hand_landmarks.landmark[10].y else 0
features.extend([middle_extended, middle_curved])
# Anular: landmarks 16 (tip), 14 (PIP) y 15 (DIP)
ring_extended = 1 if hand_landmarks.landmark[16].y < hand_landmarks.landmark[14].y else 0
ring_curved = 1 if hand_landmarks.landmark[15].y < hand_landmarks.landmark[14].y else 0
features.extend([ring_extended, ring_curved])
# Meñique: landmarks 20 (tip), 18 (PIP) y 19 (DIP)
pinky_extended = 1 if hand_landmarks.landmark[20].y < hand_landmarks.landmark[18].y else 0
pinky_curved = 1 if hand_landmarks.landmark[19].y < hand_landmarks.landmark[18].y else 0
features.extend([pinky_extended, pinky_curved])
return tuple(features)
# Mostrar en consola el diccionario de mapeo para referencia
print("Complex Gesture Mapping:")
for key, value in complex_gesture_mapping.items():
print(f"{key}: {value}")
# Inicializar la cámara
cap = cv2.VideoCapture(0)
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
# Convertir el frame a RGB para el procesamiento con MediaPipe
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results = hands.process(frame_rgb)
# Procesar cada mano detectada
if results.multi_hand_landmarks:
for hand_landmarks in results.multi_hand_landmarks:
# Dibujar landmarks de la mano
mp_drawing.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS)
# Obtener el vector complejo de características
complex_features = detect_complex_gesture(hand_landmarks)
# Consultar el mapeo; si no existe, se muestra "Desconocido"
gesture_name = complex_gesture_mapping.get(complex_features, "Desconocido")
# Mostrar en pantalla el vector y la asignación del gesto
cv2.putText(frame, f'Features: {complex_features}', (10, 40),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 2)
cv2.putText(frame, f'Gesture: {gesture_name}', (10, 80),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
# Mostrar el diccionario de mapeo en la parte inferior (opcional)
mapping_text = "Mapping: " + ", ".join([f"{k}:{v}" for k, v in complex_gesture_mapping.items()])
cv2.putText(frame, mapping_text, (10, frame.shape[0]-20),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 255), 1)
cv2.imshow("Complex Gesture Mapping", frame)
# Salir con la tecla 'q'
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
Enlaces
Enlaces a web Chareditor.
Enlaces a blog Instalacion de arduino.
Explicación detallada del código para detección de dedos con MediaPipe y OpenCV
En este documento se describe paso a paso el funcionamiento del código que utiliza la librería MediaPipe (en específico, el módulo de Hands) y OpenCV para detectar cuántos dedos de la mano están levantados. El código se compone de las siguientes secciones principales:
- Importaciones de las librerías necesarias
- Inicialización de la solución de MediaPipe Hands
- Definición de la función de conteo de dedos
- Captura y procesamiento de fotogramas de la cámara
- Dibujado de puntos clave y conteo de dedos
- Visualización y finalización de la ventana de video
A continuación, se muestra el código completo y se explica cada parte con detalle.
import cv2
import mediapipe as mp
import numpy as np
# Inicializar MediaPipe Hands
mp_hands = mp.solutions.hands
mp_drawing = mp.solutions.drawing_utils
# Configuración de MediaPipe Hands
hands = mp_hands.Hands(
static_image_mode=False,
max_num_hands=1,
min_detection_confidence=0.7,
min_tracking_confidence=0.7
)
# Función para contar dedos
def count_fingers(hand_landmarks):
# Coordenadas de los dedos basadas en los puntos clave de MediaPipe
finger_tips = [4, 8, 12, 16, 20]
finger_base = [3, 6, 10, 14, 18]
fingers = []
# Pulgar (comparar posición X)
if hand_landmarks.landmark[finger_tips[0]].x < hand_landmarks.landmark[finger_base[0]].x:
fingers.append(1)
else:
fingers.append(0)
# Otros dedos (comparar posición Y)
for i in range(1, 5):
if hand_landmarks.landmark[finger_tips[i]].y < hand_landmarks.landmark[finger_base[i]].y:
fingers.append(1)
else:
fingers.append(0)
return sum(fingers)
# Inicializar la cámara
cap = cv2.VideoCapture(0)
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
# Convertir a RGB
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# Procesar el marco
results = hands.process(frame_rgb)
# Dibujar y contar dedos
if results.multi_hand_landmarks:
for hand_landmarks in results.multi_hand_landmarks:
mp_drawing.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS)
fingers_up = count_fingers(hand_landmarks)
cv2.putText(frame, f'Dedos levantados: {fingers_up}', (10, 70), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
# Mostrar el video
cv2.imshow('Detección de Dedos', frame)
# Salir con la tecla 'q'
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# Liberar recursos
cap.release()
cv2.destroyAllWindows()
1. Importaciones de las librerías necesarias
import cv2
import mediapipe as mp
import numpy as np
- cv2: Corresponde a la librería OpenCV, la cual se encarga del procesamiento de imágenes y la captura de video.
- mediapipe as mp: Importa la librería MediaPipe. Esta librería contiene soluciones pre-entrenadas para reconocimiento de manos, rostros, posturas, etc.
- numpy as np: Se utiliza principalmente para operaciones matemáticas y de manejo de arreglos, aunque en este caso no se ve un uso destacado dentro del código.
2. Inicialización de la solución de MediaPipe Hands
mp_hands = mp.solutions.hands
mp_drawing = mp.solutions.drawing_utils
- mp_hands: Aquí hacemos referencia al módulo de MediaPipe especializado en detección y seguimiento de manos (Hands).
- mp_drawing: Este módulo provee funciones para dibujar anotaciones y conexiones (landmarks) en la imagen (específicamente,
mp.solutions.drawing_utils
).
hands = mp_hands.Hands(
static_image_mode=False,
max_num_hands=1,
min_detection_confidence=0.7,
min_tracking_confidence=0.7
)
- Hands(): Crea un objeto configurado para la detección y seguimiento de manos. Entre sus parámetros principales:
static_image_mode=False
: Indica que el programa asume que se trata de un video o secuencia de imágenes, no de una imagen estática. De esta manera se optimiza el rendimiento.max_num_hands=1
: Indica cuántas manos como máximo se van a detectar.min_detection_confidence=0.7
: Nivel mínimo de confianza (0-1) para considerar que una detección es válida.min_tracking_confidence=0.7
: Nivel mínimo de confianza para el seguimiento de la mano detectada.
3. Definición de la función de conteo de dedos
def count_fingers(hand_landmarks):
# Coordenadas de los dedos basadas en los puntos clave de MediaPipe
finger_tips = [4, 8, 12, 16, 20]
finger_base = [3, 6, 10, 14, 18]
fingers = []
- Se definen dos listas:
- finger_tips: Son los índices dentro de la lista de landmarks que corresponden a las puntas de los dedos pulgar (4), índice (8), medio (12), anular (16) y meñique (20).
- finger_base: Son los índices que corresponden a la base de los mismos dedos (3, 6, 10, 14 y 18, respectivamente).
# Pulgar (comparar posición X)
if hand_landmarks.landmark[finger_tips[0]].x < hand_landmarks.landmark[finger_base[0]].x:
fingers.append(1)
else:
fingers.append(0)
- Para el pulgar, se compara la posición en el eje X (horizontal):
- Si la punta del pulgar (finger_tips[0]) está a la izquierda (menor X) que la base del pulgar (finger_base[0]), se considera que el pulgar está “levantado” (o extendido) y se añade un
1
. - De lo contrario, se añade un
0
.
- Si la punta del pulgar (finger_tips[0]) está a la izquierda (menor X) que la base del pulgar (finger_base[0]), se considera que el pulgar está “levantado” (o extendido) y se añade un
# Otros dedos (comparar posición Y)
for i in range(1, 5):
if hand_landmarks.landmark[finger_tips[i]].y < hand_landmarks.landmark[finger_base[i]].y:
fingers.append(1)
else:
fingers.append(0)
- Para los otros cuatro dedos (índice, medio, anular y meñique), se compara la posición en el eje Y:
- Si la punta del dedo (finger_tips[i]) está por encima (menor Y) de la base del dedo (finger_base[i]), se entiende que el dedo está extendido y se añade un
1
. - De lo contrario, se añade un
0
.
- Si la punta del dedo (finger_tips[i]) está por encima (menor Y) de la base del dedo (finger_base[i]), se entiende que el dedo está extendido y se añade un
return sum(fingers)
- Finalmente, se devuelve la suma de todos los valores en
fingers
. Esta suma representa la cantidad de dedos levantados.
4. Captura y procesamiento de fotogramas de la cámara
cap = cv2.VideoCapture(0)
- Se crea un objeto
VideoCapture
que abre la cámara (normalmente la cámara principal es0
).
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
- Se entra en un bucle (loop) que funcionará mientras la cámara esté abierta.
ret, frame = cap.read()
obtiene un fotograma de la cámara:ret
es un valor booleano que indica si la lectura de la imagen fue exitosa.frame
es la imagen (matriz de pixeles) capturada.
- Si
ret
esFalse
, significa que no se pudo leer la imagen, y se finaliza el bucle.
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results = hands.process(frame_rgb)
cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
convierte la imagen de formato BGR (formato que usa OpenCV por defecto) a RGB (requerido por MediaPipe).results = hands.process(frame_rgb)
procesa la imagen y detecta los landmarks de la mano, si los hay. Este objetoresults
contendrá la información de la(s) mano(s) detectadas.
5. Dibujado de puntos clave y conteo de dedos
if results.multi_hand_landmarks:
for hand_landmarks in results.multi_hand_landmarks:
mp_drawing.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS)
fingers_up = count_fingers(hand_landmarks)
cv2.putText(frame, f'Dedos levantados: {fingers_up}', (10, 70), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
results.multi_hand_landmarks
es una lista que contiene los landmarks de todas las manos detectadas.- Se itera sobre cada mano detectada y se:
- Dibujan los landmarks y sus conexiones en el
frame
utilizandomp_drawing.draw_landmarks
.frame
es el fotograma de video en BGR.hand_landmarks
es la estructura que contiene los 21 puntos clave de la mano.mp_hands.HAND_CONNECTIONS
indica cómo conectar estos puntos (líneas entre los landmarks).
- Se llama a
count_fingers(hand_landmarks)
para obtener cuántos dedos están levantados. - Se dibuja el texto sobre el fotograma utilizando
cv2.putText
:- El texto indica el número de dedos levantados.
- La posición del texto es
(10, 70)
. - Se usa la fuente
cv2.FONT_HERSHEY_SIMPLEX
, con tamaño1
, color verde(0, 255, 0)
y grosor de línea2
.
- Dibujan los landmarks y sus conexiones en el
6. Visualización y finalización de la ventana de video
cv2.imshow('Detección de Dedos', frame)
- Se muestra el fotograma con los landmarks y el texto en una ventana llamada
"Detección de Dedos"
.
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.waitKey(1)
espera 1 milisegundo para detectar si el usuario ha presionado alguna tecla.& 0xFF
se utiliza para obtener el valor ASCII de la tecla presionada.ord('q')
es el valor ASCII de la letra ‘q’.- Si se presiona ‘q’, se rompe el bucle
while
y se cierra la ventana.
cap.release()
cv2.destroyAllWindows()
cap.release()
libera la cámara.cv2.destroyAllWindows()
cierra todas las ventanas de OpenCV abiertas.
Al presionar la tecla ‘q’, la ejecución se detiene, se libera la cámara y se cierran las ventanas de OpenCV.