Skip to content

Adri-Jk/MiProgramaa

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 

Repository files navigation

MiProgramaa

Sistema de captura de movimiento con MediaPipe y Blender para Ingeniería de Sistemas El código que graba el movimiento

import cv2 import mediapipe as mp import numpy as np import json import time

mp_pose = mp.solutions.pose mp_drawing = mp.solutions.drawing_utils

def normalize(v): norm = np.linalg.norm(v) return v / norm if norm > 1e-6 else np.array([0.0, 0.0,0.0])

def from_to_quaternion(src, dst): src = normalize(src) dst = normalize(dst) dot = np.dot(src, dst) if dot > 0.99999: return [1.0, 0.0, 0.0, 0.0] if dot < -0.99999: # Caso 180° axis = np.cross([1.0, 0.0, 0.0], src) if np.linalg.norm(axis) < 0.01: axis = np.cross([0.0, 1.0, 0.0], src) axis = normalize(axis) return [0.0, axis[0], axis[1], axis[2]] cross = np.cross(src, dst) q = np.array([1.0 + dot, cross[0], cross[1], cross[2]]) q /= np.linalg.norm(q) return [float(q[0]), float(q[1]), float(q[2]), float(q[3])] # w, x, y, z

def mp_to_blender(lm): return np.array([-lm.x, lm.z, lm.y]) # ¡Esta línea es la que normalmente funciona perfecto!

bone_definitions = { "Brazo.L2": (mp_pose.PoseLandmark.LEFT_SHOULDER, mp_pose.PoseLandmark.LEFT_ELBOW), "Antebrazo.L": (mp_pose.PoseLandmark.LEFT_ELBOW, mp_pose.PoseLandmark.LEFT_WRIST), "Femur.L": (mp_pose.PoseLandmark.LEFT_HIP, mp_pose.PoseLandmark.LEFT_KNEE), "Tibia.L": (mp_pose.PoseLandmark.LEFT_KNEE, mp_pose.PoseLandmark.LEFT_ANKLE), "Brazo.R2": (mp_pose.PoseLandmark.RIGHT_SHOULDER, mp_pose.PoseLandmark.RIGHT_ELBOW), "Antebrazo.R": (mp_pose.PoseLandmark.RIGHT_ELBOW, mp_pose.PoseLandmark.RIGHT_WRIST), "Femur.R": (mp_pose.PoseLandmark.RIGHT_HIP, mp_pose.PoseLandmark.RIGHT_KNEE), "Tibia.R": (mp_pose.PoseLandmark.RIGHT_KNEE, mp_pose.PoseLandmark.RIGHT_ANKLE), }

cap = cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)

with mp_pose.Pose(model_complexity=1, min_detection_confidence=0.7, min_tracking_confidence=0.7) as pose: rest_vectors = None recording = False frames = []

print("≈ Colócate en T-Pose perfecta y pulsa 't' para capturar referencia")
print("Pulsa 's' para empezar a grabar, 'q' para terminar")

while True:
    ret, frame = cap.read()
    if not ret:
        break
    frame = cv2.flip(frame, 1)  # espejo
    rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    results = pose.process(rgb_frame)

    if results.pose_world_landmarks:
        mp_drawing.draw_landmarks(frame, results.pose_landmarks, mp_pose.POSE_CONNECTIONS)

    if rest_vectors is None:
        cv2.putText(frame, "T-POSE + pulsa 't'", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0,255,0), 3)
    else:
        status = "GRABANDO..." if recording else "Pulsa 's' para grabar"
        cv2.putText(frame, status, (50, 100), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0,0,255), 3)

    cv2.imshow('Captura Mocap - pulsa t → s → q', frame)
    key = cv2.waitKey(1)

    # Capturar T-Pose
    if key == ord('t') and results.pose_world_landmarks:
        rest_landmarks = results.pose_world_landmarks.landmark
        rest_pos = {i: mp_to_blender(landmark) for i, landmark in enumerate(rest_landmarks)}
        rest_vectors = {}
        for bone, (p, c) in bone_definitions.items():
            p_pos = rest_pos[p.value]
            c_pos = rest_pos[c.value]
            rest_vectors[bone] = normalize(c_pos - p_pos)
        print("¡T-Pose capturada!")

    # Iniciar grabación
    if key == ord('s') and rest_vectors is not None:
        recording = True
        frames = []
        print("¡Grabando!")

    # Grabación en vivo
    if recording and results.pose_world_landmarks:
        landmarks = results.pose_world_landmarks.landmark
        current_pos = {i: mp_to_blender(landmark) for i, landmark in enumerate(landmarks) if landmark.visibility > 0.5}

        if len(current_pos) >= 28:  # necesitamos al menos los puntos necesarios
            frame_dict = {}
            all_good = True
            for bone, (p, c) in bone_definitions.items():
                if p.value not in current_pos or c.value not in current_pos:
                    all_good = False
                    break
                p_pos = current_pos[p.value]
                c_pos = current_pos[c.value]
                curr_vec = normalize(c_pos - p_pos)
                rest_vec = rest_vectors[bone]
                q = from_to_quaternion(rest_vec, curr_vec)
                frame_dict[bone] = q
            if all_good:
                frames.append(frame_dict)

    if key == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

if frames:
    data = {
        "fps": 30,
        "frames": frames
    }
    with open("C:/MisAdri/mocap_animation.json", "w") as f:   # ¡¡¡CAMBIA ESTA RUTA!!!
        json.dump(data, f)
    print(f"¡Listo! {len(frames)} frames guardados en mocap_animation.json")
else:
    print("No se grabó nada")

El Script del Personaje import bpy import json from mathutils import Quaternion

Ruta al archivo JSON generado (ajusta según sea necesario)

json_path = "C:/MisAdri/mocap_animation.json" # ¡¡¡CAMBIA ESTA RUTA SI ES NECESARIO!!!

Cargar el JSON

with open(json_path, 'r') as f: data = json.load(f)

fps = data['fps'] frames = data['frames']

Asumir que el objeto de armadura se llama 'Armature' (ajusta si tu rig tiene otro nombre)

armature_name = 'Esqueleto' arm = bpy.data.objects.get(armature_name) if not arm or arm.type != 'ARMATURE': raise ValueError(f"No se encontró la armadura '{armature_name}'. Asegúrate de que exista en la escena.")

Configurar la escena

scene = bpy.context.scene scene.frame_start = 1 scene.frame_end = len(frames) scene.render.fps = fps scene.render.fps_base = 1.0

Asumir que los nombres de los huesos en Blender coinciden exactamente con los del JSON

Si no es así, crea un mapeo aquí, por ejemplo:

bone_mapping = {

"Brazo.L2": "upper_arm.L", # Ejemplo si tus huesos tienen nombres estándar

# Agrega el resto...

}

Luego, usa bone_mapping.get(bone_name, bone_name) abajo.

Aplicar las animaciones

for frame_idx, frame_data in enumerate(frames): scene.frame_set(frame_idx + 1) # Frames comienzan en 1

for bone_name, q_list in frame_data.items():
    # Si usas mapeo: real_bone_name = bone_mapping.get(bone_name, bone_name)
    real_bone_name = bone_name  # Sin mapeo por defecto
    
    if real_bone_name in arm.pose.bones:
        bone = arm.pose.bones[real_bone_name]
        # Los cuaterniones en el JSON están en orden [w, x, y, z]
        q = Quaternion((q_list[0], q_list[1], q_list[2], q_list[3]))
        
        # Aplicar la rotación local (asumiendo que es rotación relativa al T-Pose)
        bone.rotation_quaternion = q
        
        # Insertar keyframe
        bone.keyframe_insert(data_path="rotation_quaternion", frame=frame_idx + 1)
    else:
        print(f"Advertencia: Hueso '{real_bone_name}' no encontrado en la armadura.")

Actualizar la vista

bpy.context.view_layer.update()

print(f"Animación importada: {len(frames)} frames a {fps} FPS.") print("Para una interpolación suave, ajusta las curvas en el Graph Editor si es necesario (usa Slerp para cuaterniones).")

About

Sistema de captura de movimiento con MediaPipe y Blender para Ingeniería de Sistemas

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors