c# - Almacene el movimiento v2.0 de Kinect en un archivo BVH
motion-detection (1)
Me gustaría almacenar los datos de captura de movimiento de Kinect 2 como un archivo BVH.
Encontré un código que lo hace para Kinect 1 que se puede encontrar
here
.
Revisé el código y encontré varias cosas que no pude entender.
Por ejemplo, en el código mencionado he tratado de entender qué es exactamente el objeto Skeleton
skel
, que se encuentra en varios lugares del código.
Si no, ¿hay alguna aplicación conocida disponible para lograr lo previsto?
EDITAR: Traté de cambiar Skeleton skel a Body skel, que creo que es el objeto correspondiente para kinect SDK 2.0. Sin embargo, tengo un error cuando intento obtener la posición del cuerpo:
tempMotionVektor[0] = -Math.Round( skel.Position.X * 100,2);
tempMotionVektor[1] = Math.Round( skel.Position.Y * 100,2) + 120;
tempMotionVektor[2] = 300 - Math.Round( skel.Position.Z * 100,2);
Obtuve errores al llamar a la función Posición para el skel del cuerpo. ¿Cómo puedo recuperar la X, Y, Z del esqueleto en SDK 2.0? Traté de cambiar las tres líneas anteriores a:
tempMotionVektor[0] = -Math.Round(skel.Joints[0].Position.X * 100, 2);
tempMotionVektor[1] = Math.Round(skel.Joints[0].Position.Y * 100, 2) + 120;
tempMotionVektor[2] = 300 - Math.Round(skel.Joints[0].Position.Z * 100, 2);
EDITAR: Básicamente logré almacenar un archivo bvh después de combinar bodyBasicsWPF y kinect2bvh.
Sin embargo, parece que el esqueleto que estoy almacenando no es eficiente.
Hay movimientos extraños en los codos.
Estoy tratando de entender si tengo que cambiar algo en el archivo
kinectSkeletonBVH.cp
.
Más específicamente, cuáles son los cambios en la orientación del eje de la articulación para la versión kinect 2.
¿Cómo puedo cambiar la siguiente línea:
skel.BoneOrientations[JointType.ShoulderCenter].AbsoluteRotation.Quaternion;
Traté de cambiar esa línea con
skel.JointOrientations[JointType.ShoulderCenter].Orientation
.
Estoy en lo cierto?
Estoy usando el siguiente código para agregar la unión a los objetos BVHBone:
BVHBone hipCenter = new BVHBone(null, JointType.SpineBase.ToString(), 6, TransAxis.None, true);
BVHBone hipCenter2 = new BVHBone(hipCenter, "HipCenter2", 3, TransAxis.Y, false);
BVHBone spine = new BVHBone(hipCenter2, JointType.SpineMid.ToString(), 3, TransAxis.Y, true);
BVHBone shoulderCenter = new BVHBone(spine, JointType.SpineShoulder.ToString(), 3, TransAxis.Y, true);
BVHBone collarLeft = new BVHBone(shoulderCenter, "CollarLeft", 3, TransAxis.X, false);
BVHBone shoulderLeft = new BVHBone(collarLeft, JointType.ShoulderLeft.ToString(), 3, TransAxis.X, true);
BVHBone elbowLeft = new BVHBone(shoulderLeft, JointType.ElbowLeft.ToString(), 3, TransAxis.X, true);
BVHBone wristLeft = new BVHBone(elbowLeft, JointType.WristLeft.ToString(), 3, TransAxis.X, true);
BVHBone handLeft = new BVHBone(wristLeft, JointType.HandLeft.ToString(), 0, TransAxis.X, true);
BVHBone neck = new BVHBone(shoulderCenter, "Neck", 3, TransAxis.Y, false);
BVHBone head = new BVHBone(neck, JointType.Head.ToString(), 3, TransAxis.Y, true);
BVHBone headtop = new BVHBone(head, "Headtop", 0, TransAxis.None, false);
No puedo entender en qué parte del código se calcula
the axis for every Joint
.
El código que usó para Kinect 1.0 para obtener un archivo BVH usa la información de las articulaciones para construir vectores óseos leyendo el Esqueleto .
public static double[] getBoneVectorOutofJointPosition(BVHBone bvhBone, Skeleton skel)
{
double[] boneVector = new double[3] { 0, 0, 0 };
double[] boneVectorParent = new double[3] { 0, 0, 0 };
string boneName = bvhBone.Name;
JointType Joint;
if (bvhBone.Root == true)
{
boneVector = new double[3] { 0, 0, 0 };
}
else
{
if (bvhBone.IsKinectJoint == true)
{
Joint = KinectSkeletonBVH.String2JointType(boneName);
boneVector[0] = skel.Joints[Joint].Position.X;
boneVector[1] = skel.Joints[Joint].Position.Y;
boneVector[2] = skel.Joints[Joint].Position.Z;
..
Fuente: Nguyên Lê Đặng - Kinect2BVH.V2
Excepto en Kinect 2.0 , la clase Skeleton ha sido reemplazada por la clase Body , por lo que debe cambiarla para tratar con un Body y obtener las articulaciones siguiendo los pasos que se detallan a continuación.
// Kinect namespace using Microsoft.Kinect; // ... // Kinect sensor and Kinect stream reader objects KinectSensor _sensor; MultiSourceFrameReader _reader; IList<Body> _bodies; // Kinect sensor initialization _sensor = KinectSensor.GetDefault(); if (_sensor != null) { _sensor.Open(); }
También agregamos una lista de cuerpos, donde se guardarán todos los datos relacionados con el cuerpo / esqueleto. Si se ha desarrollado para Kinect versión 1, observará que la clase Skeleton ha sido reemplazada por la clase Body. ¿Recuerdas el MultiSourceFrameReader? ¡Esta clase nos da acceso en cada transmisión, incluida la transmisión del cuerpo! Simplemente necesitamos que el sensor sepa que necesitamos la funcionalidad de seguimiento del cuerpo agregando un parámetro adicional al inicializar el lector:
_reader = _sensor.OpenMultiSourceFrameReader(FrameSourceTypes.Color | FrameSourceTypes.Depth | FrameSourceTypes.Infrared | FrameSourceTypes.Body); _reader.MultiSourceFrameArrived += Reader_MultiSourceFrameArrived;
Se llamará al método Reader_MultiSourceFrameArrived siempre que haya un nuevo marco disponible. Especifiquemos lo que sucederá en términos de los datos del cuerpo:
- Obtenga una referencia al marco del cuerpo
- Compruebe si el marco del cuerpo es nulo; esto es crucial
- Inicializar la lista _bodies
- Llame al método GetAndRefreshBodyData para copiar los datos del cuerpo en la lista
- ¡Recorre la lista de cuerpos y haz cosas increíbles!
Siempre recuerde verificar los valores nulos. Kinect le proporciona aproximadamente 30 fotogramas por segundo, ¡cualquier cosa puede ser nula o faltante! Aquí está el código hasta ahora:
void Reader_MultiSourceFrameArrived(object sender, MultiSourceFrameArrivedEventArgs e) { var reference = e.FrameReference.AcquireFrame(); // Color // ... // Depth // ... // Infrared // ... // Body using (var frame = reference.BodyFrameReference.AcquireFrame()) { if (frame != null) { _bodies = new Body[frame.BodyFrameSource.BodyCount]; frame.GetAndRefreshBodyData(_bodies); foreach (var body in _bodies) { if (body != null) { // Do something with the body... } } } } }
¡Eso es todo! Ahora tenemos acceso a los cuerpos que Kinect identifica. El siguiente paso es mostrar la información del esqueleto en la pantalla. Cada cuerpo consta de 25 articulaciones. El sensor nos proporciona la posición (X, Y, Z) y la información de rotación para cada uno de ellos. Además, Kinect nos permite saber si las articulaciones se rastrean, se hipotizan o no. Es una buena práctica verificar si se rastrea un cuerpo antes de realizar cualquier función crítica.
El siguiente código ilustra cómo podemos acceder a las diferentes articulaciones del cuerpo:
if (body != null) { if (body.IsTracked) { Joint head = body.Joints[JointType.Head]; float x = head.Position.X; float y = head.Position.Y; float z = head.Position.Z; // Draw the joints... } }
Fuente: pterneas.com/2014/03/13/…