将 Kinect 的 v2.0 运动存储到 BVH 文件

Posted

技术标签:

【中文标题】将 Kinect 的 v2.0 运动存储到 BVH 文件【英文标题】:Store Kinect's v2.0 Motion to BVH File 【发布时间】:2015-08-07 20:07:33 【问题描述】:

我想将 Kinect 2 中的动作捕捉数据存储为 BVH 文件。我找到了适用于 Kinect 1 的代码,可以在 here 找到。我浏览了代码,发现了一些我无法理解的东西。 例如,在上述代码中,我试图了解在代码中的多个位置找到的 Skeleton skel 对象到底是什么。如果没有,是否有任何已知的应用程序可用于实现预期目标?

编辑:我尝试将 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);

在调用 Body skel 的函数 Position 时出现错误。如何在 sdk 2.0 中检索骨架的 X、Y、Z?我尝试将以上三行更改为:

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

编辑:基本上我在组合 bodyBasicsWPF 和 kinect2bvh 后设法存储了 bvh 文件。但是,我存储的骨架似乎效率不高。肘部有奇怪的动作。我试图了解是否必须更改文件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 是在哪里计算的。

【问题讨论】:

但是我跳过了这个问题 我能够为 txt 文件存储 Kinect v1 和 v2 信息。这个 BVH 文件是我刚刚阅读的内容,它将是我将添加到我们的采集软件中的一个功能。如果您对 *.txt 文件感兴趣,请告诉我。我还没有合适的 BVH 解决方案。 检查:pterneas.com/2014/03/13/… 我有办法将 Kinect v1 和 Kinect v2 流正确写入 txt。也许如果您使用它,您可以仔细检查您的 bvh 文件以进行相同的实验。查看我的简历了解更多信息。 @Khaled.K 如果你发布的链接回答了这个问题,你介意把它变成这个问题的答案吗(每个this meta question) 【参考方案1】:

您用于 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;
..

来源:Nguyên Lê Đặng - 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 方法将在任何时候被调用 新框架可用。让我们具体说明会发生什么 身体数据:

    获取对主体框架的引用 检查body frame是否为null——这很关键 初始化 _bodies 列表 调用GetAndRefreshBodyData方法,将body数据复制到列表中 遍历身体列表并做一些很棒的事情!

永远记得检查空值。 Kinect 为您提供 大约每秒 30 帧 - 任何东西都可以是 null 或 失踪!到目前为止的代码如下:

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 Blog - KINECT FOR WINDOWS VERSION 2: BODY TRACKING

【讨论】:

以上是关于将 Kinect 的 v2.0 运动存储到 BVH 文件的主要内容,如果未能解决你的问题,请参考以下文章

Kinect v2.0原理介绍之三:骨骼跟踪的原理

Kinect for Windows SDK v2.0 开发笔记 (十五) 手势帧

C#中三个kinect 2设置之间的通信

如何使用 kinect 根据跟踪的身体运动移动骨骼

如何在Blender中导出并优化FBX文件

如何将 BVH 节点对象转换为简单数组?