LoginSignup
2
1

More than 3 years have passed since last update.

【Kinect V2】JointTypeのpositionをスムーズに取得する

Posted at

昔作った資産をまたサルベージした

BodyFrameのPositionをColorFrameに変換して画像とかを動かす時に
Positionがガタガタになる問題を解決するために実装した。

ガタガタするのはなぜか

もはやかなりうろ覚えだがKinectV2はToF方式で計測されており
対象へ赤外線を照射し、それが反射してKinectに戻ってくる時間を元に位置情報を取得している。

このとき対象物に動きがあった場合、射出した赤外線がデバイスに戻ってこないことがあり
それが測定不能値としてPositionが欠損するためにガタガタしてしまう(だった気がする)

どうやって解消したか

生の値を使用すると欠損があった場合にPosition.x,y,zはNULLないし0となってしまうので
ここを補完する必要がある

なので位置情報のバッファを取っておいて前後の値で穴埋めすれば解決するはず、
という結論に達した。

以下ソース。
Queueを使用して位置データを保持するDictionaryに、指定した数の履歴を追加しておき
Dictionary内に保持されたPositionを平滑化する(平均値で動かす)
Smoothing関数にJointTypeとそのフレームにおけるPositionを渡せば
平滑化されたPositionが返却される。
今気づいたがz軸が考慮されてねぇ。

using System;
using System.Windows;
using System.Collections.Generic;
using Microsoft.Kinect;

namespace Microsoft.Samples.Kinect.BodyBasics
{
    class SmoothingPoint
    {
        private static Dictionary<JointType, Queue<Point>> pointBufferS = new Dictionary<JointType, Queue<Point>>();
        private static Dictionary<JointType, Queue<Point>> pointBufferE = new Dictionary<JointType, Queue<Point>>();

        public SmoothingPoint()
        {
            foreach (JointType jt in Enum.GetValues(typeof(JointType)))
            {
                pointBufferS.Add(jt, new Queue<Point>());
                pointBufferE.Add(jt, new Queue<Point>());
            }
        }

        public Point Smoothing(JointType jType, Point p)
        {
            return DoubleMovingAverage(jType, p);
        }

        private Point SimpleAverageFilter(JointType jt, Point newPoint, int parameter)
        {
            pointBufferS[jt].Enqueue(newPoint);
            if (pointBufferS[jt].Count <= parameter)
            {
                return newPoint;
            }
            pointBufferS[jt].Dequeue();
            Point[] list = pointBufferS[jt].ToArray();
            Point point = new Point();
            double x = 0;
            double y = 0;

            int n = pointBufferS[jt].Count;
            for (int i = 0; i < pointBufferS[jt].Count; i++)
            {
                Point p = list[i];
                x += p.X;
                y += p.Y;
            }
            point.X = x / n;
            point.Y = y / n;

            return point;
        }

        private Point DoubleMovingAverage(JointType jt, Point newPoint, int parameter = 5)
        {
            Point newSimpleAverage = SimpleAverageFilter(jt, newPoint, parameter);
            pointBufferE[jt].Enqueue(newSimpleAverage);
            if (pointBufferE[jt].Count <= parameter)
            {
                return newSimpleAverage;
            }
            pointBufferE[jt].Dequeue();
            Point[] list = pointBufferE[jt].ToArray();
            Point point = new Point();
            double x = 0;
            double y = 0;

            int n = pointBufferE[jt].Count;
            for (int i = 0; i < pointBufferE[jt].Count; i++)
            {
                Point p = list[i];
                x += p.X;
                y += p.Y;
            }
            point.X = x / n;
            point.Y = y / n;

            return point;
        }
    }
}
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1