不幸的是,我仍在努力使用新的Kinect SDK 1.7。 这个问题实际上与“finding events via reflection c#”在同一个环境中:Click事件(但是,没有必要理解这个问题)。
我的问题很简单:如果我右手控制光标(“新”Kinect HandPointer)并且它位于屏幕的左上角,我希望它返回坐标(0,0)。如果光标位于右下角,则坐标应分别为(1920,1080)当前屏幕分辨率。
新的SDK为每个HandPointer(最多4个)都有所谓的PhysicalInteractionZones(PIZ),它随HandPointers一起移动,其值从(左上角)0.0到(右下角)1.0。 这基本上意味着,我不能使用它们映射到屏幕,因为它们根据Kinect前面的用户移动动态变化。至少,我无法找到一种方法来完成这项工作。
然后我通过SkeletonStream尝试了它:跟踪右手的坐标,一旦注册了单击手势,Click-Event就会在此特定点触发。我用以下代码尝试了它:
private void ksensor_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
using (SkeletonFrame frame = e.OpenSkeletonFrame())
{
if (frame != null)
{
frame.CopySkeletonDataTo(this._FrameSkeletons);
var accelerometerReading =
Settings.Instance.ksensor.AccelerometerGetCurrentReading();
ProcessFrame(frame);
_InteractionStream.ProcessSkeleton(_FrameSkeletons,
accelerometerReading, frame.Timestamp);
}
}
}
private void ProcessFrame(ReplaySkeletonFrame frame)
{
foreach (var skeleton in frame.Skeletons)
{
if (skeleton.TrackingState != SkeletonTrackingState.Tracked)
continue;
foreach (Joint joint in skeleton.Joints)
{
if (joint.TrackingState != JointTrackingState.Tracked)
continue;
if (joint.JointType == JointType.HandRight)
{
_SwipeGestureDetectorRight.Add(joint.Position,
Settings.Instance.ksensor);
_RightHand = GetPosition(joint);
myTextBox.Text = _RightHand.ToString();
}
if (joint.JointType == JointType.HandLeft)
{
_SwipeGestureDetectorLeft.Add(joint.Position,
Settings.Instance.ksensor);
_LeftHand = GetPosition(joint);
}
}
}
}
辅助性GetPosition
方法定义如下:
private Point GetPosition(Joint joint)
{
DepthImagePoint point =
Settings.Instance.ksensor.CoordinateMapper.MapSkeletonPointToDepthPoint(joint.Position, Settings.Instance.ksensor.DepthStream.Format);
point.X *=
(int)Settings.Instance.mainWindow.ActualWidth / Settings.Instance.ksensor.DepthStream.FrameWidth;
point.Y *=
(int)Settings.Instance.mainWindow.ActualHeight / Settings.Instance.ksensor.DepthStream.FrameHeight;
return new Point(point.X, point.Y);
}
一旦检测到点击手势,就会调用一个简单的invokeClick(_RightHand)
并执行点击。点击本身工作得很好(再次感谢回答这个问题的人)。到目前为止还没有工作的是坐标的映射,因为我只从
x轴:900 - 1500(从左到右) y轴:300 - 740(从上到下)
这些坐标甚至会随着每次尝试到达屏幕上的一个特定点100或200像素而变化,例如,屏幕的左侧首先是900,但是当我将手移出Kinect的范围(在我背后或桌子下面)并向左侧重复移动时我突然得到700的坐标或者周围的东西。
我甚至尝试了来自ScaleTo
Coding4Fun.Kinect.Wpf
ScaleTo(1920,1080)
的{{1}}方法,但这只是给了我x:300000,y:-100000或240000中的疯狂坐标。我的想法已经不多了所以我希望那里的人有一个给我,甚至是解决方案。
对于长篇文章感到抱歉,但我试图尽可能具体。在此先感谢您的帮助!
答案 0 :(得分:2)
InteractionHandPointer类包含手的屏幕坐标。 我从SDK演示中调整了这段代码;有很多箍可以跳过!:
this.sensor.DepthFrameReady += this.Sensor_DepthFrameReady;
this.interaction = new InteractionStream(sensor, new InteractionClient());
this.interaction.InteractionFrameReady += interaction_InteractionFrameReady;
...
private void Sensor_DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
{
using (var frame = e.OpenDepthImageFrame())
{
if (frame != null)
{
try
{
interaction.ProcessDepth(frame.GetRawPixelData(), frame.Timestamp);
}
catch (InvalidOperationException) { }
}
}
}
private void interaction_InteractionFrameReady(object sender, InteractionFrameReadyEventArgs e)
{
using (var frame = e.OpenInteractionFrame())
{
if (frame != null)
{
if ((interactionData == null) ||
(interactionData.Length !== InteractionStream.FrameUserInfoArrayLength))
{
interactionData = new UserInfo[InteractionStream.FrameUserInfoArrayLength];
}
frame.CopyInteractionDataTo(interactionData);
foreach (var ui in interactionData)
{
foreach (var hp in ui.HandPointers)
{
// Get screen coordinates
var screenX = hp.X * DisplayWidth;
var screenY = hp.Y * DisplayHeight;
// You can also access IsGripped, IsPressed etc.
}
}
}
}
}
public class InteractionClient: IInteractionClient
{
public InteractionInfo GetInteractionInfoAtLocation(
int skeletonTrackingId,
InteractionHandType handType,
double x, double y)
{
return new InteractionInfo();
}
}
答案 1 :(得分:1)
我的一位同事正在试图将手感应线映射到屏幕上。他通过一些简单的数学成功地做到了;但结果并不好,因为少量的像素(手部区域)会被映射到更大数量的像素,这会导致光标非常不准确,并且当你是自然的小手抖动时跳转把它举起来,或联合识别不准确。
除了这种方法,我还会推荐笔记本电脑触控板的功能:如果你在触控板上移动的速度非常慢,光标只会移动很小的范围。但是如果你快速移动手指,光标会移动更远的距离。因此,如果手动坐标缓慢移动100px,您可以将光标移动100px在屏幕上,但如果手的相同100px移动发生得很快,则可以将光标移动300px。这与手坐标空间和屏幕坐标空间之间的任何映射无关。
答案 2 :(得分:1)
另一种解决此问题的方法是使用kinect sdk toolkit v1.8中名为“Skeleton Basics - WPF”的示例中提供的代码,然后您已经设置了一个函数来接收骨架点并返回一个像这样的点:
private Point SkeletonPointToScreen(SkeletonPoint skelpoint)
{
// Convert point to depth space.
// We are not using depth directly, but we do want the points in our 640x480 output resolution.
DepthImagePoint depthPoint = this.sensor.CoordinateMapper.MapSkeletonPointToDepthPoint(skelpoint, DepthImageFormat.Resolution640x480Fps30);
return new Point(depthPoint.X, depthPoint.Y);
}