楕円を手関節にマッピングしたいのですが、手関節が動くので楕円を動かさなければなりません。
kinectSdk1.5を使用してプログラムを実行するのに役立つリファレンスリンクをいくつか提供してください。ありがとうございました
@Heisenbugは機能しますが、WPFにははるかに簡単な方法があります。チュートリアルは、Channel9のSkeletonFundamentalsにあります。基本的にはキャンバスが必要ですが、必要な楕円はいくつも必要です。これがコードXAMLです
<Window x:Class="SkeletalTracking.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="600" Width="800" Loaded="Window_Loaded"
Closing="Window_Closing" WindowState="Maximized">
<Canvas Name="MainCanvas">
<Ellipse Canvas.Left="0" Canvas.Top="0" Height="50" Name="leftEllipse" Width="50" Fill="#FF4D298D" Opacity="1" Stroke="White" />
<Ellipse Canvas.Left="100" Canvas.Top="0" Fill="#FF2CACE3" Height="50" Name="rightEllipse" Width="50" Opacity="1" Stroke="White" />
<Image Canvas.Left="66" Canvas.Top="90" Height="87" Name="headImage" Stretch="Fill" Width="84" Source="/SkeletalTracking;component/c4f-color.png" />
<Ellipse Canvas.Left="283" Canvas.Top="233" Height="23" Name="leftknee" Stroke="Black" Width="29" />
<Ellipse Canvas.Left="232" Canvas.Top="233" Height="23" Name="rightknee" Stroke="Black" Width="30" />
</Canvas>
</Window>
ここでは、4つの楕円(膝、手)と画像(頭)を使用しています。これに不可欠なコードはここにあります:
private void ScalePosition(FrameworkElement element, Joint joint)
{
//convert the value to X/Y
//Joint scaledJoint = joint.ScaleTo(1280, 720);
//convert & scale (.3 = means 1/3 of joint distance)
//note you need to have Coding4Fun
Joint scaledJoint = joint.ScaleTo(1280, 720, .3f, .3f);
Canvas.SetLeft(element, scaledJoint.Position.X);
Canvas.SetTop(element, scaledJoint.Position.Y);
}
これがこのプログラムの鍵です。ジョイントから位置を取得し、要素の位置をそこに変更します。次の部分も重要です。次のようにします。
void GetCameraPoint(Skeleton first, AllFramesReadyEventArgs e)
{
using (DepthImageFrame depth = e.OpenDepthImageFrame())
{
if (depth == null ||
kinectSensorChooser1.Kinect == null)
{
return;
}
//Map a joint location to a point on the depth map
//head
DepthImagePoint headDepthPoint =
depth.MapFromSkeletonPoint(first.Joints[JointType.Head].Position);
//left hand
DepthImagePoint leftDepthPoint =
depth.MapFromSkeletonPoint(first.Joints[JointType.HandLeft].Position);
//right hand
DepthImagePoint rightDepthPoint =
depth.MapFromSkeletonPoint(first.Joints[JointType.HandRight].Position);
//Map a depth point to a point on the color image
//head
ColorImagePoint headColorPoint =
depth.MapToColorImagePoint(headDepthPoint.X, headDepthPoint.Y,
ColorImageFormat.RgbResolution640x480Fps30);
//left hand
ColorImagePoint leftColorPoint =
depth.MapToColorImagePoint(leftDepthPoint.X, leftDepthPoint.Y,
ColorImageFormat.RgbResolution640x480Fps30);
//right hand
ColorImagePoint rightColorPoint =
depth.MapToColorImagePoint(rightDepthPoint.X, rightDepthPoint.Y,
ColorImageFormat.RgbResolution640x480Fps30);
//Set location
CameraPosition(headImage, headColorPoint);
CameraPosition(leftEllipse, leftColorPoint);
CameraPosition(rightEllipse, rightColorPoint);
}
}
上記のコードは、スケルトンポイントを深度フレームにマップし、次にカラーフレームにマップします。
Skeleton GetFirstSkeleton(AllFramesReadyEventArgs e)
{
using (SkeletonFrame skeletonFrameData = e.OpenSkeletonFrame())
{
if (skeletonFrameData == null)
{
return null;
}
skeletonFrameData.CopySkeletonDataTo(allSkeletons);
//get the first tracked skeleton
Skeleton first = (from s in allSkeletons
where s.TrackingState == SkeletonTrackingState.Tracked
select s).FirstOrDefault();
return first;
}
}
これにより、選択するスケルトンのコードが取得されます。次に、AllFrameReadyEventArgs
これを実行してすべてをまとめます。
void sensor_AllFramesReady(object sender, AllFramesReadyEventArgs e)
{
if (closing)
{
return;
}
//Get a skeleton
Skeleton first = GetFirstSkeleton(e);
if (first == null)
{
return;
}
//set scaled position
ScalePosition(headImage, first.Joints[JointType.Head]);
ScalePosition(leftEllipse, first.Joints[JointType.HandLeft]);
ScalePosition(rightEllipse, first.Joints[JointType.HandRight]);
ScalePosition(leftknee, first.Joints[JointType.KneeLeft]);
ScalePosition(rightknee, first.Joints[JointType.KneeRight]);
GetCameraPoint(first, e);
}
後ろにカラー画像があると結果は最高に見えますが、今はその部分をスキップすることにしました。お役に立てれば!
基本的に、コードのどこかに、KinectSDKと対話するためのクラスがあります。
private KinectSensor kinectSensor;
この方法でKinectSensorを初期化できます。
public void kinectInit()
{
KinectSensor.KinectSensors.StatusChanged += (object sender, StatusChangedEventArgs e) =>
{
if (e.Sensor == kinectSensor)
{
if (e.Status != KinectStatus.Connected)
{
SetSensor(null);
}
}else if ((kinectSensor == null) && (e.Status == KinectStatus.Connected))
{
SetSensor(e.Sensor);
}
};
foreach (var sensor in KinectSensor.KinectSensors)
{
if (sensor.Status == KinectStatus.Connected)
{
SetSensor(sensor);
}
}
}
基本的に、変更されたKinectSensorのステータスを処理するためのデリゲートを定義しています。SetSensorメソッドは次のようになります。
private void SetSensor(KinectSensor newSensor)
{
if (kinectSensor != null)
{
kinectSensor.Stop();
}
kinectSensor = newSensor;
if (kinectSensor != null)
{
kinectSensor.SkeletonStream.Enable();
kinectSensor.SkeletonFrameReady += OnSkeletonFrameReady;
kinectSensor.Start();
}
}
さて、OnSkeletonFrameReadyは「更新関数」です。これは、Kinectセンサーが更新されるたびに継続的に呼び出されます。その中から、ジョイントに関する情報を取得して、必要なものをレンダリングできます。
private void OnSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
skelFrame = e.OpenSkeletonFrame();
skeletons = new Skeleton[kinectSensor.SkeletonStream.FrameSkeletonArrayLength];
if (skelFrame != null)
{
skelFrame.CopySkeletonDataTo(skeletons);
foreach (Skeleton skel in skeletons) {
if (skel.TrackingState >= SkeletonTrackingState.Tracked)
{
//here's get the joints for each tracked skeleton
SkeletonPoint rightHand = skel.Joints[JointType.HandRight].Position;
....
}
}
}
C#とKinectを使用しているため、楕円のレンダリングに使用できる単純なライブラリはXNAです。