Хранить Kinect's v2.0 Motion в файл BVH

298

Я хотел бы сохранить данные захвата движения из Kinect 2 в виде файла BVH. Я нашел код, который делает это для Kinect 1, который можно найти здесь . Я просмотрел код и обнаружил несколько вещей, которые не смог понять. Например, в упомянутом коде я попытался понять, что именно представляет собой skelобъект Skeleton , найденный в нескольких местах кода. Если нет, есть ли какое-либо известное приложение, доступное для выполнения запланированного?

РЕДАКТИРОВАТЬ: Я попытался изменить Skeleton Skel на Body Skel, который я думаю, является соответствующим объектом для Kinect SDK 2.0. Однако у меня появляется ошибка при попытке определить положение тела:

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

Я получил ошибки при вызове функции Position для Body skel. Как я могу получить X, Y, Z скелета в SDK 2.0 ?? Я попытался изменить вышеупомянутые три строки на:

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

РЕДАКТИРОВАТЬ: В основном мне удалось сохранить файл bvh после объединения bodyBasicsWPF и kinect2bvh. Однако, похоже, что скелет, который я храню, неэффективен. Есть странные движения в локтях. Я пытаюсь понять, если я должен что-то изменить в файле kinectSkeletonBVH.cp . Более конкретно, каковы изменения в ориентации оси соединения для версии kinect 2. Как я могу изменить следующую строку: skel.BoneOrientations[JointType.ShoulderCenter].AbsoluteRotation.Quaternion; я пытался изменить эту строку с skel.JointOrientations[JointType.ShoulderCenter].Orientation. Я прав? Я использую следующий код для добавления соединения к объектам 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);

Я не могу понять, где внутри кода the axis for every Jointрассчитывается.

Хосе Рамон
источник
9
Однако я пропустил эту проблему. Если у вас есть какое-либо решение, хорошо бы опубликовать его здесь не только для меня, так как я заметил, что многие люди искали сохранение движений в файлах bvh.
Хосе Рамон
Я могу хранить информацию о Kinect v1 и v2 для текстового файла. Этот файл BVH - это то, что я только что прочитал, и это будет функция, которую я добавлю в наше программное обеспечение для сбора данных. Если вы заинтересованы в файлах * .txt, просто дайте мне знать. У меня пока нет правильного решения BVH.
16per9
2
проверка: pterneas.com/2014/03/13/…
Халед.К
1
У меня есть способ правильно записать потоки Kinect v1 и Kinect v2 в txt. Может быть, если вы используете его, вы можете дважды проверить файлы вашего bvh для того же эксперимента. Проверьте мою биографию для получения дополнительной информации.
16per9
1
@ Khaled.K Если ссылка, которую вы разместили, отвечает на это, не могли бы вы превратить это в ответ на этот вопрос (в соответствии с этим мета-вопросом )
Мэтт Томас,

Ответы:

2

Код, который вы использовали для Kinect 1.0 для получения файла BVH, использует информацию о соединениях для построения костных векторов, читая 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;
..

Источник: Нгуен Лен Инг - Kinect2BVH.V2

За исключением Kinect 2.0 , класс Skeleton был заменен классом Body , поэтому вам нужно изменить его, чтобы вместо этого использовать Body , и получить соединения, выполнив шаги, указанные ниже.

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

Мы также добавили список тел, в которые будут сохранены все данные, связанные с телом / скелетом. Если вы разработали для Kinect версии 1, вы заметите, что класс Skeleton был заменен классом Body. Помните MultiSourceFrameReader? Этот класс дает нам доступ к каждому потоку, включая основной поток! Нам просто нужно сообщить датчику, что нам нужна функциональность отслеживания тела, добавив дополнительный параметр при инициализации считывателя:

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

_reader.MultiSourceFrameArrived += Reader_MultiSourceFrameArrived;

Метод Reader_MultiSourceFrameArrived будет вызываться всякий раз, когда доступен новый кадр. Давайте уточним, что будет с точки зрения данных тела:

  1. Получить ссылку на рамку тела
  2. Проверьте, является ли рамка тела нулевой - это важно
  3. Инициализируйте список _bodies
  4. Вызовите метод GetAndRefreshBodyData, чтобы скопировать данные тела в список
  5. Перебирай список тел и делай классные вещи!

Всегда не забывайте проверять нулевые значения. Kinect предоставляет вам примерно 30 кадров в секунду - все может быть нулевым или отсутствующим! Вот код на данный момент:

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

Это оно! Теперь у нас есть доступ к телам, которые идентифицирует Kinect. Следующим шагом является отображение информации о скелете на экране. Каждое тело состоит из 25 суставов. Датчик предоставляет нам положение (X, Y, Z) и информацию о вращении для каждого из них. Кроме того, Kinect дает нам знать, отслеживаются ли суставы, выдвигаются гипотезы или нет. Перед выполнением любых критических функций рекомендуется проверить, отслеживается ли тело.

Следующий код иллюстрирует, как мы можем получить доступ к различным суставам тела:

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

Источник: блог Vangos Pterneas - KINECT FOR WINDOWS VERSION 2: Отслеживание тела

Khaled.K
источник