C# Kinect SDK 1.7:将关节/光标坐标映射到屏幕分辨率
不幸的是,我仍然在为新的Kinect SDK 1.7而挣扎。 此问题实际上与“”处于相同的上下文中:单击事件(但是,理解此问题不需要此事件) 我的问题很简单:如果我用右手控制光标(“新”Kinect指针),并且它位于屏幕的左上角,我希望它返回坐标(0,0)。如果光标位于右下角,坐标应分别为(19201080)当前屏幕分辨率 新SDK为每个指针(最多4个)提供了所谓的PhysicalInteractionZones(PIZ),这些指针随指针一起移动,其值从(左上)0.0到(右下)1.0。 这基本上意味着,我不能使用它们来映射到屏幕,因为它们是根据用户在Kinect面前的移动而动态变化的。至少,我找不到一种方法来实现这一点 然后我通过SkeletonStream进行了尝试:跟踪右手的坐标,一旦注册了点击手势,点击事件就会在这个特定点触发。我使用以下代码进行了尝试:C# Kinect SDK 1.7:将关节/光标坐标映射到屏幕分辨率,c#,wpf,mapping,coordinates,kinect,C#,Wpf,Mapping,Coordinates,Kinect,不幸的是,我仍然在为新的Kinect SDK 1.7而挣扎。 此问题实际上与“”处于相同的上下文中:单击事件(但是,理解此问题不需要此事件) 我的问题很简单:如果我用右手控制光标(“新”Kinect指针),并且它位于屏幕的左上角,我希望它返回坐标(0,0)。如果光标位于右下角,坐标应分别为(19201080)当前屏幕分辨率 新SDK为每个指针(最多4个)提供了所谓的PhysicalInteractionZones(PIZ),这些指针随指针一起移动,其值从(左上)0.0到(右下)1.0。 这基本上
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);
}
}
}
}
auxialiaryGetPosition
方法定义如下:
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左右的坐标。
我甚至尝试了Coding4Fun.Kinect.Wpf
(ScaleTo(19201080)
分别ScaleTo(SystemParameters.PrimaryScreenWidth,SystemParameters.PrimaryScreenHight)
)中的ScaleTo
方法,但这给了我在x:300000的疯狂坐标,y:-100000或240000……我的想法快用完了,所以我希望有人能给我一个想法,甚至是一个解决方案
对不起,我的文字太长了,但我已经尽量说得具体一些。提前感谢您的帮助 我的一位同事试图将手坐标映射到屏幕坐标。他通过简单的数学运算成功地做到了这一点;但结果并不理想,因为少量像素(手部区域)将被映射到大量像素,这将导致光标非常不准确,当你将光标举在空中时,手自然地轻轻晃动,或者关节识别不准确
我建议不要使用这种方法,而是使用笔记本电脑的触控板:如果你在触控板上非常缓慢地移动你的手,光标只会移动很小的范围。但是如果你的手指移动得很快,光标移动的距离就会更大。因此,例如,如果手坐标缓慢移动100px,您可以在屏幕上移动光标100px,但如果手的相同100px移动很快,您可以移动光标,比如说300px。这与手坐标空间和屏幕坐标空间之间的任何映射无关。我的一位同事试图将手坐标映射到屏幕坐标。他通过简单的数学运算成功地做到了这一点;但结果并不理想,因为少量像素(手部区域)将被映射到大量像素,这将导致光标非常不准确,当你将光标举在空中时,手自然地轻轻晃动,或者关节识别不准确
我建议不要使用这种方法,而是使用笔记本电脑的触控板:如果你在触控板上非常缓慢地移动你的手,光标只会移动很小的范围。但是如果你的手指移动得很快,光标移动的距离就会更大。因此,例如,如果手坐标缓慢移动100px,您可以在屏幕上移动光标100px,但如果手的相同100px移动很快,您可以移动光标,比如说300px。这与手坐标空间和屏幕坐标空间之间的任何映射无关。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();
}
}
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();
}
}
解决此问题的另一种方法是使用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);
}
解决此问题的另一种方法是使用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);
}
谢谢你的回答!实际上是个好主意(笔记本电脑轨迹板的事情)。在这种情况下,这不是我想要的,但我相信我可以在将来使用它。谢谢你的回答!实际上是个好主意(笔记本电脑轨迹板的事情)。在这种情况下,这不是我想要的,但我相信我可以在将来使用它。非常感谢,它真的很有效,@Garethegeek。我不知道为什么我从来没有尝试过HandPointer.X*ScreenWidth术语…通常我使用它,但不知为什么在这种情况下我没有。非常感谢你的帮助,现在我终于可以继续了。非常感谢,这真的很有效,@garethegeek。