Armazene o movimento v2.0 do Kinect no arquivo BVH

298

Gostaria de armazenar os dados de captura de movimento do Kinect 2 como um arquivo BVH. Encontrei um código que o faz para o Kinect 1, que pode ser encontrado aqui . Examinei o código e encontrei várias coisas que não consegui entender. Por exemplo, no código mencionado, tentei entender o que exatamente é o skelobjeto Skeleton , encontrado em vários lugares do código. Caso contrário, existe algum aplicativo conhecido disponível para realizar o objetivo?

EDIT: Tentei mudar o Skeleton skel para Body skel, que eu acho que é o objeto correspondente do kinect SDK 2.0. No entanto, tenho um erro ao tentar obter a posição do corpo:

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);

Eu obtive erros ao chamar a função Position para o skel do corpo. Como posso recuperar o X, Y, Z do esqueleto no sdk 2.0? Tentei alterar as três linhas acima para:

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);

EDIT: Basicamente, eu consegui armazenar o arquivo a bvh depois de combinar bodyBasicsWPF e kinect2bvh. No entanto, parece que o esqueleto que estou armazenando não é eficiente. Existem movimentos estranhos nos cotovelos. Estou tentando entender se tenho que alterar alguma coisa no arquivo kinectSkeletonBVH.cp . Mais especificamente, quais são as alterações na orientação do eixo da junta para a versão do kinect 2. Como posso alterar a seguinte linha: skel.BoneOrientations[JointType.ShoulderCenter].AbsoluteRotation.Quaternion; Tentei alterar essa linha com skel.JointOrientations[JointType.ShoulderCenter].Orientation. Estou certo? Estou usando o código a seguir para adicionar a junção aos 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);

Não consigo entender onde the axis for every Jointé calculado o interior do código .

Jose Ramon
fonte
9
No entanto, ignorei esse problema. Se você tiver alguma solução, é bom publicá-lo aqui, não apenas para mim, pois notei muitas pessoas procurando armazenar movimentos em arquivos bvh.
Jose Ramon
Eu sou capaz de armazenar as informações Kinect v1 e v2 para um arquivo txt. Esse arquivo BVH é algo que acabei de ler e será um recurso que adicionarei ao nosso software de aquisição. Se você estiver interessado nos arquivos * .txt, entre em contato. Ainda não tenho uma solução BVH adequada.
16per9
2
verificar: pterneas.com/2014/03/13/...
Khaled.K
1
Eu tenho uma maneira de escrever corretamente os fluxos Kinect v1 e Kinect v2 em txt. Talvez se você usá-lo, verifique novamente os arquivos do seu bvh para o mesmo experimento. Verifique minha biografia para mais informações.
16per9 29/11
1
@ Khaled.K Se o link que você postou responde a esta, você se importaria de formação que em uma resposta a esta pergunta (por esta questão meta )
Matt Thomas

Respostas:

2

O código que você usou para Kinect 1.0 para obter um arquivo BVH usa as informações das articulações para criar vetores ósseos lendo o Skeleton .

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;
..

Fonte: Nguyên Lê Đặng - Kinect2BVH.V2

Exceto no Kinect 2.0 , a classe Skeleton foi substituída pela classe Body ; portanto, é necessário alterá-la para lidar com um Body e obter as juntas seguindo as etapas citadas abaixo.

// 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();
}

Também adicionamos uma lista de corpos, onde todos os dados relacionados ao corpo / esqueleto serão salvos. Se você desenvolveu o Kinect versão 1, percebe que a classe Skeleton foi substituída pela classe Body. Lembre-se do MultiSourceFrameReader? Esta classe nos dá acesso a todos os fluxos, incluindo o fluxo do corpo! Simplesmente precisamos informar ao sensor que precisamos da funcionalidade de rastreamento corporal adicionando um parâmetro adicional ao inicializar o leitor:

_reader = _sensor.OpenMultiSourceFrameReader(FrameSourceTypes.Color |
                                             FrameSourceTypes.Depth |
                                             FrameSourceTypes.Infrared |
                                             FrameSourceTypes.Body);

_reader.MultiSourceFrameArrived += Reader_MultiSourceFrameArrived;

O método Reader_MultiSourceFrameArrived será chamado sempre que um novo quadro estiver disponível. Vamos especificar o que acontecerá em termos de dados do corpo:

  1. Obter uma referência à estrutura do corpo
  2. Verifique se a estrutura do corpo é nula - isso é crucial
  3. Inicialize a lista _bodies
  4. Chame o método GetAndRefreshBodyData, para copiar os dados do corpo na lista
  5. Percorra a lista de corpos e faça coisas incríveis!

Lembre-se sempre de verificar se há valores nulos. O Kinect fornece aproximadamente 30 quadros por segundo - qualquer coisa pode estar nula ou faltando! Aqui está o código até agora:

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...
                }
            }
        }
    }
}

É isso! Agora temos acesso aos corpos que o Kinect identifica. O próximo passo é exibir as informações do esqueleto na tela. Cada corpo é composto por 25 articulações. O sensor nos fornece a posição (X, Y, Z) e as informações de rotação para cada um deles. Além disso, o Kinect nos permite saber se as juntas são rastreadas, hipotetizadas ou não. É uma boa prática verificar se um corpo é rastreado antes de executar quaisquer funções críticas.

O código a seguir ilustra como podemos acessar as diferentes articulações do corpo:

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...
    }
}

Fonte: Blog Vangos Pterneas - KINECT FOR WINDOWS VERSÃO 2: RASTREAMENTO CORPORAL

Khaled.K
fonte