Cámara en vivo con Vision
VisionPoseProvider (módulo KinesiaMotionVision, solo iOS) abre la cámara, corre el detector de cuerpo 2D de Vision en cada fotograma y entrega poses que ya cumplen el contrato de Pose.
import KinesiaMotionVision
let camera = VisionPoseProvider( camera: .front, // .front o .back minimumConfidence: 0.3 // puntos por debajo se descartan)Permiso
Sección titulada «Permiso»if !VisionPoseProvider.isAuthorized { let granted = await VisionPoseProvider.requestAccess() guard granted else { // Muestra cómo activar la cámara en Ajustes return }}Recuerda la clave NSCameraUsageDescription en Info.plist (Instalación).
Ciclo de vida
Sección titulada «Ciclo de vida»La cámara se enciende sola cuando alguien empieza a iterar poses() y se apaga sola cuando deja de hacerlo. Con MotionSession eso significa:
session.start(with: camera) // enciendesession.stop() // apagaNo hace falta llamar startRunning() ni stopRunning() en captureSession.
Mostrar la imagen
Sección titulada «Mostrar la imagen»captureSession es un AVCaptureSession normal: pásalo a un AVCaptureVideoPreviewLayer. El ejemplo completo de CameraPreview para SwiftUI está en el inicio rápido.
Con la cámara frontal, la capa de vista previa se ve espejada (como un espejo), pero las poses traen los lados reales del paciente. Si dibujas los puntos encima, espeja la x al dibujar, no al medir.
Qué hace por dentro
Sección titulada «Qué hace por dentro»- Resolución VGA (640×480), suficiente para el detector y liviana para la batería.
- Descarta los fotogramas atrasados: si tu código va lento, siempre recibes la pose más nueva.
- Convierte las coordenadas de Vision (normalizadas, origen abajo) a píxeles con
yhacia abajo, para una imagen vertical. - Con la cámara frontal intercambia izquierda y derecha.
- Envía también poses vacías cuando no detecta a nadie.
Los dos lados con una cámara
Sección titulada «Los dos lados con una cámara»Así lo hace la app de Kinesia: una sola cámara, una sesión por lado.
let camera = VisionPoseProvider(camera: .front)let left = MotionSession(exercise: exercise, side: .left)let right = MotionSession(exercise: exercise, side: .right)
let task = Task { @MainActor in for await pose in camera.poses() { left.process(pose) right.process(pose) }}// Para terminar: task.cancel() → la cámara se apaga