[C#] Kinect의 v2.0 Motion을 BVH 파일로 저장

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

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가 계산 되는 위치를 이해할 수 없습니다 .



답변

BVH 파일 을 얻기 위해 Kinect 1.0 에 사용한 코드 는 관절 정보를 사용하여 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

를 제외하고 키 넥트 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. 바디 프레임이 null인지 확인 – 이것이 중요합니다
  3. _bodies 목록을 초기화하십시오.
  4. 본문 데이터를 목록에 복사하기 위해 GetAndRefreshBodyData 메소드를 호출하십시오.
  5. 시체 목록을 반복하고 멋진 일을하십시오!

항상 null 값을 확인해야합니다. 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 블로그-WINDOWS 버전 2를위한 KINECT : BODY TRACKING


답변