1

不幸的是,我还在为新的 Kinect SDK 1.7 苦苦挣扎。这个问题实际上与“通过反射 c# 查找事件”处于相同的上下文中:Click 事件(但是,理解这个问题不是必需的)。

我的问题很简单:如果我用右手控制光标(“新”Kinect HandPointer)并且它位于屏幕的左上角,我希望它返回坐标 (0,0)。如果光标在右下角,则坐标应分别为(1920,1080)当前屏幕分辨率。

新的 SDK 为每个 HandPointer(最多 4 个)具有所谓的 PhysicalInteractionZones (PIZ),这些 HandPointer 随 HandPointer 一起移动,值从(左上角)0.0 到(右下角)1.0。这基本上意味着,我不能将它们用于映射到屏幕,因为它们会根据用户在 Kinect 前的移动而动态变化。至少,我无法找到一种方法来完成这项工作。

然后我通过 SkeletonStream 进行了尝试:跟踪右手的坐标,一旦注册了点击手势,点击事件就会在这个特定点触发。我尝试使用以下代码:

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方法,但这只是给了我在 x:300000、y:-100000 或 240000 中的疯狂坐标……而且我的想法已经不多了,所以我希望有人有一个适合我或甚至可以解决这个问题。Coding4Fun.Kinect.WpfScaleTo(1920,1080)ScaleTo(SystemParameters.PrimaryScreenWidth,SystemParameters.PrimaryScreenHight)

很抱歉,文字很长,但我尽量做到具体。提前感谢您的帮助!

4

3 回答 3

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();
    }
}
于 2013-06-20T14:05:32.580 回答
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);

    }
于 2013-12-02T16:10:43.077 回答
1

我的一位同事试图将手坐标映射到屏幕坐标。他通过一些简单的数学成功地做到了。但结果并不理想,因为少量像素(手部区域)会映射到大量像素,这会导致光标非常不准确,并且会随着您手部的自然小幅度抖动而跳动把它举起来,或者联合识别不准确。

而不是这种方法,我会推荐笔记本电脑触控板上的做法:如果你在触控板上非常缓慢地移动你的手,光标只会移动一个很小的范围。但是,如果您非常快地移动手指,则光标会移动更大的距离。因此,例如,如果手坐标缓慢移动 100px,您可以将光标在屏幕上移动 100px,但如果手的相同 100px 移动发生得很快,您可以将光标移动 300px。这与手坐标空间和屏幕坐标空间之间的任何映射无关。

于 2013-06-19T15:30:55.680 回答