Как записывать данные о движении в Kinect SDK V1.7 (Avateering XNA)?

Я новичок в kinect SDK v1.7.

Я хочу знать, как получить данные о движении из примера.(http://msdn.microsoft.com/en-us/library/jj131041.aspx)

Итак, как я могу сделать процедуру, которая может записывать данные скелета в файл? (записывать)

затем прочитайте файл обратно в пример программы и смоделируйте его. (воспроизведение)?

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

Я могу делать то, что хочу, в другом образце программы. (http://msdn.microsoft.com/en-us/library/hh855381) , потому что пример программы рисует только линии и точки скелета.

Например ,

00001 00:00:00.0110006@353,349,354,332,358,249,353,202,310,278,286,349,269,407,266,430,401,279,425,349,445,408,453,433,332,369,301,460,276,539,269,565,372,370,379,466,387,548,389,575,

00002 00:00:00.0150008@352,349,353,332,356,249,352,202,309,278,284,349,266,406,263,430,398,279,424,349,445,408,453,433,331,369,301,461,277,541,271,566,371,371,379,466,387,548,390,575,

[номер кадра][отметка времени]@[координаты положения скелета]

в этом примере я предполагаю, что позиция скелета - это заказ Joint Id.

спасибо (простите мой плохой английский).


person Sirius Wang    schedule 15.02.2014    source источник


Ответы (2)


Вы можете использовать StreamWriter, инициализировать его по выбранному пути, затем для каждого кадра увеличивать счетчик кадров, записывать его в файл, записывать метку времени в файл, затем перебирать соединения и записывать их в файл. Я бы сделал это следующим образом:

using System.IO;

StreamWriter writer = new StreamWriter(@path);
int frames = 0;

...

void AllFramesReady(object sender, AllFramesReadyEventArgs e)
{
    frames++;
    using (SkeletonFrame sFrame = e.OpenSkeletonFrameData())
    {
        if (sFrame == null)
            return;

        skeletonFrame.CopySkeletonDataTo(skeletons);

        Skeleton skeleton = (from s in skeletons
                                where s.TrackingState == SkeletonTrackingState.Tracked
                                select s);
        if (skeleton == null)
            return;

        if (skeleton.TrackingState == SkeletonTrackingState.Tracked)
        {
            writer.Write("{0} {1}@", frames, timestamp);//I dont know how you want to do this
            foreach (Joint joint in skeleton.Joints)
            {
                writer.Write(joint.Position.X + "," + joint.Position.Y + "," joint.Position.Z + ",");
            }
            writer.Write(Environment.NewLine);
        }
    }
}

Затем, чтобы прочитать из файла:

StreamReader reader = new StreamReader(@path);
int frame = -1;
JointCollection joints;

...

string[] lines = reader.ReadAllLines();

...

void AllFramesReady(object sender, AllFramesReadyEventArgs e)
{
    canvas.Children.Clear();
    string[] coords = lines[frame].Split('@')[1].Split(',');
    int jointIndex = 0;
    for (int i = 0; i < coords.Length; i += 3)
    {
        joints[jointIndex].Position.X = int.Parse(coords[i]);
        joints[jointIndex].Position.Y = int.Parse(coords[i + 1]);
        joints[jointIndex].Position.X = int.Parse(coords[i + 2]);
        jointIndex++;
    }

    DepthImageFrame depthFrame = e.OpenDepthImageFrame();
    canvas.Children.Add(GetBodySegment(joints, brush, new JointType[] { JointType.HipCenter, JointType.Spine, JointType.ShoulderCenter, JointType.Head }, depthFrame, canvas));
    canvas.Children.Add(GetBodySegment(joints, brush, new JointType[] { JointType.ShoulderCenter, JointType.ShoulderLeft, JointType.ElbowLeft, JointType.WristLeft, JointType.HandLeft }, depthFrame, canvas));
    canvas.Children.Add(GetBodySegment(joints, brush, new JointType[] { JointType.ShoulderCenter, JointType.ShoulderRight, JointType.ElbowRight, JointType.WristRight, JointType.HandRight }, depthFrame, canvas));
    canvas.Children.Add(GetBodySegment(joints, brush, new JointType[] { JointType.HipCenter, JointType.HipLeft, JointType.KneeLeft, JointType.AnkleLeft, JointType.FootLeft }, depthFrame, canvas));
    canvas.Children.Add(GetBodySegment(joints, brush, new JointType[] { JointType.HipCenter, JointType.HipRight, JointType.KneeRight, JointType.AnkleRight, JointType.FootRight }, depthFrame, canvas));
    depthFrame.Dispose();

    frame++;
}

Point GetDisplayPosition(Joint joint, DepthImageFrame depthFrame, Canvas skeleton)
{
    float depthX, depthY;
    KinectSensor sensor = KinectSensor.KinectSensors[0];
    DepthImageFormat depthImageFormat = sensor.DepthStream.Format;
    DepthImagePoint depthPoint = sensor.CoordinateMapper.MapSkeletonPointToDepthPoint(joint.Position, depthImageFormat);

    depthX = depthPoint.X;
    depthY = depthPoint.Y;

    depthX = Math.Max(0, Math.Min(depthX * 320, 320));
    depthY = Math.Max(0, Math.Min(depthY * 240, 240));

    int colorX, colorY;
    ColorImagePoint colorPoint = sensor.CoordinateMapper.MapDepthPointToColorPoint(depthImageFormat, depthPoint, ColorImageFormat.RgbResolution640x480Fps30);
    colorX = colorPoint.X;
    colorY = colorPoint.Y;

    return new System.Windows.Point((int)(skeleton.Width * colorX / 640.0), (int)(skeleton.Height * colorY / 480));
}

Polyline GetBodySegment(Joint[] joints, Brush brush, JointType[] ids, DepthImageFrame depthFrame, Canvas canvas)
{
    PointCollection points = new PointCollection(ids.Length);
    for (int i = 0; i < ids.Length; ++i)
    {
        points.Add(GetDisplayPosition(joints[i], depthFrame, canvas));
    }
    Polyline polyline = new Polyline();
    polyline.Points = points;
    polyline.Stroke = brush;
    polyline.StrokeThickness = 5;
    return polyline;
}

Конечно, это работает только в wpf. Вам просто нужно перейти от использования кода:

    DepthImageFrame depthFrame = e.OpenDepthImageFrame();
    canvas.Children.Add(GetBodySegment(joints, brush, new JointType[] { JointType.HipCenter, JointType.Spine, JointType.ShoulderCenter, JointType.Head }, depthFrame, canvas));
    canvas.Children.Add(GetBodySegment(joints, brush, new JointType[] { JointType.ShoulderCenter, JointType.ShoulderLeft, JointType.ElbowLeft, JointType.WristLeft, JointType.HandLeft }, depthFrame, canvas));
    canvas.Children.Add(GetBodySegment(joints, brush, new JointType[] { JointType.ShoulderCenter, JointType.ShoulderRight, JointType.ElbowRight, JointType.WristRight, JointType.HandRight }, depthFrame, canvas));
    canvas.Children.Add(GetBodySegment(joints, brush, new JointType[] { JointType.HipCenter, JointType.HipLeft, JointType.KneeLeft, JointType.AnkleLeft, JointType.FootLeft }, depthFrame, canvas));
    canvas.Children.Add(GetBodySegment(joints, brush, new JointType[] { JointType.HipCenter, JointType.HipRight, JointType.KneeRight, JointType.AnkleRight, JointType.FootRight }, depthFrame, canvas));
    depthFrame.Dispose();

Чтобы узнать, как анимационный образец анимирует модель, вы можете даже создать новый Skeleton и скопировать joints в Skeleton.Joints, а затем просто передать этот скелет как «обнаруженный» скелет. Обратите внимание, что вам потребуется изменить любые другие необходимые переменные, необходимые для функций, используемых в этом примере. Я не знаком с примером, поэтому не могу назвать конкретные имена методов, но вы можете просто заменить глобальный Skeleton на тот, который вы создали в начале, и обновлять каждый кадр. Поэтому я бы рекомендовал это:

//in the game class (AvateeringXNA.cs)
StreamReader reader = new StreamReader(@path);
int frame = -1;
JointCollection joints;
Skeleton recorded = new Skeleton();

...

string[] lines = reader.ReadAllLines();

...

void Update(...)
{
    string[] coords = lines[frame].Split('@')[1].Split(',');
    int jointIndex = 0;
    for (int i = 0; i < coords.Length; i += 3)
    {
        joints[jointIndex].Position.X = int.Parse(coords[i]);
        joints[jointIndex].Position.Y = int.Parse(coords[i + 1]);
        joints[jointIndex].Position.X = int.Parse(coords[i + 2]);
        jointIndex++;
    }

    recorded.Joints = joints;

    ...

    //preform necessary methods, except with recorded skeleton instead of detected, I think it is:
    this.animator.CopySkeleton(recorded);
    this.animator.FloorClipPlane = skeletonFrame.FloorClipPlane;

    // Reset the filters if the skeleton was not seen before now
    if (this.skeletonDetected == false)
    {
        this.animator.Reset();
    }

    this.skeletonDetected = true;
    this.animator.SkeletonVisible = true;

    ...

    frame++;
}

ИЗМЕНИТЬ

Когда вы читаете начальную плоскость отсечения пола (clipPlanes[0]), она получает всю информацию о кадре до первого пробела. См. ниже, чтобы увидеть, как он будет разделяться и как я буду его читать:

var newFloorClipPlane = Tuple.Create(Single.Parse(clipPlanes[2]), Single.Parse(clipPlanes[3]), Single.Parse(clipPlanes[4]), Single.Parse(clipPlanes[5]));

Вот как вы размещаете кадры:

frame# timestam@joint1Posx,joint1posy,joint1posz,...jointNPosx,jointNposy,jointNposz floorX floorY floorZ floorW

Вот массив, созданный `.Split(' ')

["frame#", "timestam@joint1Posx,joint1posy,joint1posz,...jointNPosx,jointNposy,jointNposz", "floorX", "floorY", "floorZ", "floorW"]

Следовательно, с примером ввода:

00000002 10112@10,10,10... 11 12 13 14

С вашим кодом вы получите:

[2, 10112101010..., 11, 12]

С исправленными индексами из моего кода:

[11, 12, 13, 14]

Поместите эту строку в консольное приложение очень быстро и посмотрите, что она выводит:

Console.WriteLine(Convert.ToSingle("10,10"));

Вывод 1010 Для того, что вы пытаетесь выполнить, это создает неправильную плоскость отсечения пола. Вам нужны правильные индексы для того, чего вы пытаетесь достичь.

примечание: я изменил Convert.ToSingle на Single.Parse, потому что это лучшая практика, и в трассировке стека они оба выполняют одни и те же функции.

person Liam McInroy    schedule 15.02.2014
comment
Спасибо за ответ. Но я хочу сделать это с помощью примера программы (Avatarring). Я не могу найти информацию о кадрах в образце программы. и я хочу записать информацию о скелете и поставить ее обратно на аватарку, и играть. Но я могу найти только информацию о скелете - это объект скелета [] . Как я могу записать объект в формате txt (строка). и вернуться к модели аватара? - person Sirius Wang; 16.02.2014
comment
Я имею в виду, что я хочу изменить пример программы, которая может захватывать данные о движении. Но я не знаю, как это сделать. - person Sirius Wang; 16.02.2014
comment
Вы можете использовать тот же код для захвата движения, так как он сохраняет координаты суставов, и вы бы читали его таким же образом, вы просто вместо записи на холст конвертируете его в мировые точки и устанавливаете суставы аватара относительно него. .. Я буду редактировать очень быстро @user255 - person Liam McInroy; 17.02.2014
comment
У меня возникли проблемы при выполнении этого шага 【recorded.Joints = Joints;】 ,сообщение об ошибке показывает, что 【Свойство или индексатор «Microsoft.Kinect.Skeleton.Joints» нельзя использовать в этом контексте, поскольку метод доступа set недоступен. 】,Как я могу решить эту проблему? - person Sirius Wang; 18.02.2014
comment
@ user2553644 См. stackoverflow.com/questions/13556910/ - person Liam McInroy; 19.02.2014
comment
Я прочитал статью, но до сих пор не понимаю, как установить свойствоjointCollection в соединениях нового объекта скелета. В этой статье я не могу найти место для установки моей записанной совместной коллекции. - person Sirius Wang; 19.02.2014
comment
Я думаю, что я могу установить соединение в этом цикле【for (int i = 0; i ‹ coords.Length; i += 3)】, вот так【recorded.Joints[(JointType)jointIndex] = newdJoint;】, is метод может делать то же самое, что и исходный код? - person Sirius Wang; 19.02.2014
comment
другой вопрос заключается в том, что на этом этапе【this.animator.FloorClipPlane = каркасный кадр.FloorClipPlane;】 как я могу создать новый каркасный кадр. - person Sirius Wang; 19.02.2014
comment
@user2553644 user2553644 Цикл должен работать, и исходные методы должны продолжать работать правильно и просто сохранять старую плоскость отсечения как новую. - person Liam McInroy; 20.02.2014
comment
Я пробую код 【recorded.Joints[(JointType)jointIndex] = newdJoint;】, но получаю сообщение об ошибке 【Значение индекса JointType должно совпадать с Joint.JointType】, я ищу решение, потом увидел эту статью. Но я все еще не могу ее решить. Я понятия не имею, где код он меняет, и я до сих пор не знаю, в чем проблема. -positions/13594350#13594350" title="исключение понятно при обновлении совместных позиций kinect"> stackoverflow.com/questions/13544978/ - person Sirius Wang; 20.02.2014
comment
@user2553644 user2553644 Это означает, что вы должны передать индекс как тип JointType, где вы передаете int, попробуйте recorded.Joints[newdjoint.Item] = newdjoint; - person Liam McInroy; 21.02.2014
comment
спасибо за вашу помощь, но как я могу сохранить более старую плоскость клипа? использовать бинарный streamWriter? , существует ли способ создать новый SkeletonFrame (системное сообщение показывает, что конструктор не существует)? - person Sirius Wang; 21.02.2014
comment
@user2553644 user2553644 Вы можете записать координаты x y z w плоскости клипа пола в конец каждого кадра и добавить аналогичный метод для их обработки. Затем обновите его, прежде чем обновлять скелет - person Liam McInroy; 22.02.2014
comment
Спасибо за помощь, я уже закончил запись, но все равно не могу воспроизвести аватарку. Я не знаю почему. Вот мой код pastebin.com/r9JxB8L0 [база на вашем коде] , аватар не двигается ,и делаю ничего [tinyurl.com/kadjwdy]. - person Sirius Wang; 24.02.2014
comment
Нужно ли что-то менять в draw()? - person Sirius Wang; 24.02.2014
comment
@user2553644 user2553644 Хммм... Могу я увидеть код, в котором вы пишете floorclipplane? - person Liam McInroy; 25.02.2014
comment
вот весь мой код [AvateeringXNA.cs] --›pastebin.com/kMD2Nz2p . Я записываю 4 элемента floorclipplane в файл. и прочитайте его обратно. - person Sirius Wang; 25.02.2014
comment
Я не понимаю, что ваши правки. почему clipPlanes[0] неверен? Я записал его одновременно. [суставы: клиппланы] и клиппланы — это 4 элемента [item1~4]. когда я прочитал его обратно из записанного файла. почему clipPlanes[0] ? а в ваших редакциях...где клипплан[1]???? почему 2~5? - person Sirius Wang; 26.02.2014
comment
@user2553644 user2553644 Причина, по которой я внес эти изменения, заключается в том, что у вас есть пробелы в вашем файле данных перед фактическими плоскостями отсечения пола. Если вы прочитаете мою правку целиком, я объясню это, так как тогда сингл будет неправильно конвертирован. - person Liam McInroy; 27.02.2014
comment
Я уже нашел, что проблема в . Спасибо за вашу помощь . Я сделал повтор. Я использовал начальный элемент clipPlane 4 равным 0 . И я использую сериализацию и десериализацию для записи/воспроизведения объекта скелета в/из файла. Проблема в том, что аватару нужна не только информация о соединении скелета, но и другие свойства объекта скелета. Я действительно ценю твою помощь . Но у меня недостаточно репутации, чтобы проголосовать за ваш ответ .. извините. - person Sirius Wang; 01.03.2014
comment
@SiriusWang Отлично! Просто для моего собственного любопытства на эту тему, что еще нужно было написать? Также вы можете принять мой ответ или добавить новый и принять его. - person Liam McInroy; 01.03.2014
comment
Я принял это. Я записываю весь скелетный объект в файл с помощью сериализации и считываю его с помощью десериализации. Это может быть потеря чего-то, что нужно аватару, чего я не знаю. Я дал аватару всю информацию, а потом разгадал. - person Sirius Wang; 03.03.2014

Эй, почему бы вам не использовать метод csv для записи всех данных о суставах в виде файла Excel. Это поможет вам проанализировать их на более позднем этапе. Я настроил свой код для помещения их в формат csv, что помогло мне проанализировать данные на более позднем этапе. Вы можете написать отдельный файл в своем проекте, который будет экспортировать все данные скелета

public void CoordinatesExportToCSV(Skeleton data)
    {
        if (!TimeRecorded)
        {
            startTime = DateTime.Now;
            TimeRecorded = true;
        }
        recordedSamples[1]++;
        if (!titles)
        {
            sw1.Write("Counter,Time,Clipped Edges,");
            foreach (Joint joint in data.Joints)
            {
                sw1.Write(joint.JointType.ToString()+",");
            }
            titles = true;
        }
        else
        {
            double a = DateTime.Now.TimeOfDay.TotalSeconds - startTime.TimeOfDay.TotalSeconds;
            sw1.Write(recordedSamples[1] + "," + a + "," + data.ClippedEdges);

            foreach (Joint joint in data.Joints)
            {
                sw1.Write(joint.Position.X + "|" + joint.Position.Y + "|" + joint.Position.Z+",");
            }
        }
        sw1.WriteLine();
    }
person user2823510    schedule 22.03.2014