我想将一个椭圆映射到手关节。椭圆必须随着我的手关节移动而移动。
请提供一些参考链接,帮助我使用 kinect Sdk 1.5 进行程序。谢谢
尽管 @Heisenbug 可以工作,但 WPF 中有一种更简单的方法。您可以在Channel 9 的 Skeleton Fundamentals找到有关它的教程。基本上你需要一个画布,不管你想要多少椭圆。这是代码 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);
}
如果您后面有彩色图像,您的结果将看起来最好,但我决定暂时跳过这部分。希望这可以帮助!
基本上,在代码中的某个地方,您将拥有一个与 Kinect SDK 交互的类:
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。