Hatena::ブログ(Diary)

明日とロボット このページをアンテナに追加 RSSフィード

2011-07-26

深度データのノイズ軽減とポリゴン表示

Kinect関連記事

内容

  • 深度データのノイズが気になったのものすごく適当にノイズをごまかした。
  • 今まではポイントの集合で図形を表示していたのを、ポリゴンの集合で表示することにした。

ノイズ除去

  • 本当は、ガウシアンフィルタとか使ってやるのがふさわしいのだと思うが、今はまだ勉強不足なので、簡単に以下の方法で。
  • kinectから受け取った深度データを色配列に入れる際に、指定したサイズ以下の空白(深度が0から4000外)はノイズと見なし、その前後の平均値の色で埋める。(深度データの復習はkinectセンサーから任意の範囲の深度マップ抽出より)
if(sizeCount++ < maxHoleSize)
    hole = true;
else
    hole = false;
  • ホールを抜けて、新たな深度データのセルに出くわした際に、そのホールを埋める
if (hole)
{
    int dist = (distance + startDist) / 2;
    int di = depthIndex / 2;
    int i;
    int tmpx = x;
    byte t = (byte)(255 * (dist - minRange) / range);

    while (sizeCount-- > 0)
    {
        i = ((width - (--tmpx) - 1) + heightOffset) * 4;
        colorFrame[i + BlueIndex] = t;
        colorFrame[i + GreenIndex] = t;
        colorFrame[i + RedIndex] = 10;
    }
    hole = false;
}
else
{
    startDist = distance;
    hole = false;
}

ものすごく適当だが、結果は以下の通り

  • before

f:id:astrobot:20110726194842j:image

  • after

f:id:astrobot:20110726194841j:image

イメージのポリゴン表示

f:id:astrobot:20110726200223j:image

  • 何も考えずに全部の点を繋げたため、当然、大きな格差がある部分もこのように延び延びで繋がってしまう。
  • よって、z座標の値にある基準以上のギャップがある場合は、描写しないことにしたところ、以下のようになった。

f:id:astrobot:20110726200224j:image

Kinect関連記事

2011-07-21

Kinect for Windows SDK 入門4:骨格トラッキングと3D表示

Kinect関連記事

objective

  • 未だに骨格追跡の機能を使ったことがなかったので、使ってみた。
  • OpenGLを使って3Dデータに骨格をかぶせてみたりする

骨格トラッキングを使う

  • 基本的に他と同様、まずはWPFで作ったwindowのWindow_Loadedの外側に、以下を
Runtime nui = new Runtime();
  • そして、Window_Loadedイベント内でランタイムの初期化のパラメーターに、骨格データを扱うためのRuntimeOptions.UseSkeletalTrackingを追加し、SkeletonFrameReadyに登録
  • また、TransformSmoothParametersを使うことによって、骨格エンジンの細かい揺らぎを減少させることができる。
nui.Initialize(RuntimeOptions.UseSkeletalTracking);

nui.SkeletonEngine.TransformSmooth = true;
var parameters = new TransformSmoothParameters
{
    Smoothing = 0.75f,
    Correction = 0.0f,
    Prediction = 0.0f,
    JitterRadius = 0.05f,
    MaxDeviationRadius = 0.04f
};
nui.SkeletonEngine.SmoothParameters = parameters;

nui.SkeletonFrameReady += new EventHandler<SkeletonFrameReadyEventArgs>(nui_SkeletonFrameReady);
void nui_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
	//to be implemented
}

UI

  • UIのXAMLには、キャンバス上に、追跡された関節を表すためのellipseを追加
<Canvas Name="MainCanvas">
    <Ellipse Canvas.Left="0" Canvas.Top="0" Height="50" Name="headEllipse" Stroke="Black" Width="50" Fill="Orange" />
    <Ellipse Canvas.Left="50" Canvas.Top="0" Height="50" Name="rightEllipse" Stroke="Black" Width="50" Fill="SlateGray" />
    <Ellipse Canvas.Left="100" Canvas.Top="0" Fill="SpringGreen" Height="50" Name="leftEllipse" Stroke="Black" Width="50" />
</Canvas>

追跡された骨格の取得

  • 以下のようなLINQクエリで、捕捉した骨格を取得する。
void nui_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
    SkeletonFrame allSkeletons = e.SkeletonFrame;
 
    //最初に捕捉した骨格を取得
    SkeletonData skeleton = (from s in allSkeletons.Skeletons
                             where s.TrackingState == SkeletonTrackingState.Tracked
                             select s).FirstOrDefault();
}

関節の座標を得る

  • 指定した関節毎の、xyz座標は、それぞれ以下のように表現される
    • X = 水平方向に –1 から +1 の間で
    • Y = 垂直方向に –1 から +1 の間で
    • Z = kinectからのメートル距離
  • これらのXYの値は、(specific joint).ScaleTo(x pixel, y pixel)とすることでスケールしなおせる
    • よって今回は、nui_SkeletonFrameReadyより、表示したいそれぞれのjointを新しく作る関数SetEllipsePositionに送ることによって、320x240にスケールし直し、window上のそれぞれのellipseを動かす
private void SetEllipsePosition(FrameworkElement ellipse, Joint joint)
{
    var scaledJoint = joint.ScaleTo(320, 240);
    Canvas.SetLeft(ellipse, scaledJoint.Position.X);
    Canvas.SetTop(ellipse, scaledJoint.Position.Y);
}
  • そしてnui_SkeletonFrameReady内より表示したい関節を送る
SetEllipsePosition(ellipseHead, skeleton.Joints[JointID.Head]);
SetEllipsePosition(ellipseHead, skeleton.Joints[JointID.ShoulderCenter]);
...

f:id:astrobot:20110721231730p:image

イメージに重ねる

f:id:astrobot:20110721182848j:image

OpenGLで描写

f:id:astrobot:20110721182849j:image

  • 違う角度から

f:id:astrobot:20110721182850j:image

Kinect関連記事