1. ホーム
  2. c#

[解決済み】Kinectのv2.0モーションをBVHファイルに保存する

2022-03-30 20:37:52

質問

Kinect 2のモーションキャプチャデータをBVHファイルとして保存したいのですが、どうすればよいですか?Kinect 1でこれを実現するコードを見つけました。 こちら . そのコードを一通り読んでみて、理解できない点がいくつかありました。 例えば、このコードの中で、私は、スケルトン skel というオブジェクトがありますが、これは何でしょうか?もしそうでなければ、意図したことを達成するために利用できる既知のアプリケーションはあるのでしょうか?

EDIT: Kinect SDK 2.0の対応オブジェクトと思われるSkeleton skelをBody skelに変更しようとしました。しかし、ボディの位置を取得しようとすると、エラーが発生します。

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スケールのPosition関数を呼び出すと、エラーが発生します。sdk2.0でスケルトンのX, Y, Zを取得するにはどうしたらいいでしょうか?上記の3行を変更してみました。

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: 基本的にbodyBasicsWPFとkinect2bvhを組み合わせてbvhファイルを保存することができました。しかし、保存しているスケルトンが効率的でないようです。肘に変な動きがあります。ファイル内の何かを変更する必要があるのか、理解しようとしています。 kinectSkeletonBVH.cp . 具体的には、kinect2バージョンで関節軸の向きがどう変わるのか。以下の行はどのように変更すればよいのでしょうか。 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 が計算されます。

解決方法は?

で使用したコードは キネクト1.0 を取得することができます。 BVH ファイルを読み込んで骨ベクトルを構築するために、関節情報を使用します。 スケルトン .

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

ただし キネクト2.0 , スケルトン クラスは 本体 クラスに対応するため、変更する必要があります。 ボディ の代わりに、以下に引用する手順でジョイントを取得します。

<ブロッククオート
// 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. BODYリストを初期化する
  4. GetAndRefreshBodyDataメソッドを呼び出して、ボディデータをリストにコピーします。
  5. ボディーのリストをループして、すごいことをするんだ!

常にNULL値をチェックすることを忘れないでください。キネクトが提供する 1秒間に約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)と回転の情報を1つ1つ取得します。さらに、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(ボディトラッキング