2012-07-19 53 views
2

我试图为MS Kinect实施一个实时战略控制方案。 到目前为止,我有一个光标,可以通过移动左手(或右手,取决于你的手)来移动。我有一个基于Open-NI的Kinect控制器,它为玩家动作设置了一个框架,并将腕,肘,肩和身体中心坐标传递给我的应用程序。 为了将这些手腕坐标投影到屏幕上,我设置了一个矩形,它位于玩家中心的左侧/右侧,只要手腕在矩形内移动,光标就会在屏幕上移动。 我的问题是,XNA-Rectangle以左上角为原点,即X轴指向右边,因为它“应该”,但Y轴指向下方,而Kinect的Y轴 - 坐标系指向上。这会导致光标在屏幕上向上移动,当我将手向下移动时,反之亦然。我无法用Kinect坐标系改变任何东西,所以是否可以'翻转'矩形的'坐标系',以便Y轴也指向?Kinect光标控制与虚拟XNA矩形 - '触摸板' - Y轴反转

下面是相关代码:

(自校准() - 方法:)

List<Vector3> joints = UDPlistener.getInstance().ParseCalibCoordinates(data); 
//0 = Right Wrist 1 = Right Elbow 2 = Right Shoulder 
//3 = Left Wrist 4 = Left Elbow 5 = Left Shoulder 
//6 = Center 
height = 762; 
width = 1024;    
switch (hand) 
{ 
    case 0: 
    cursorSpace = new Rectangle((int)(joints[6].X * 2) - 200, (int)(joints[6].Y * 2) + height, width, height); 
    break; 
    case 3: 
    cursorSpace = new Rectangle((int)(joints[6].X * 2) - 1200, (int)(joints[6].Y * 2) + height, width, height); 
    break; 
} 

public Point Cursor(String data) 
{ 
    List<Vector3> joints = UDPlistener.getInstance().ParsePlayCoordinates(data); 
    //0 = Right Wrist 1 = Left Wrist 2 = Center 
    double mhx = 0; //main hand x-coordinate 
    double mhy = 0; // main hand y-coordinate 
    switch (hand) 
    { 
     case 0: 
     mhx = joints[hand].X; 
     mhy = joints[hand].Y; 
     break; 

     case 3: 
     mhx = joints[hand-2].X; 
     mhy = joints[hand-2].Y; 
     break;      
    } 

int x; 
int y; 
if (Math.Abs(mhx - mhxOld) < 1.0 || Math.Abs(mhy - mhyOld) < 1.0) 
//To remove jittering of the cursor 
{ 
    x = (int) mhxOld * 2; 
    y = (int) mhyOld * 2; 
} 
else 
{ 
    x = (int) mhx * 2; 
    mhxOld = mhx; 
    y = (int) mhy * 2; 
    mhyOld = mhy; 
} 

Point cursor = new Point(0,0); 

if (cursorSpace.Contains(x,y)) 
{ 
    cursor = new Point(x - cursorSpace.X, y - CursorSpace.Y);      
    lastCursorPos = cursor; 
    return cursor;      
} 

对不起,文字的墙,我希望,我能说清楚了。

由于提前,

KK

回答

2

我使用用于转换OpenNI坐标的扩展方法。以下示例将OpenNI坐标映射到左上角的640x480矩形中的XNA坐标,表示为Vector2对象。

public static Vector2 ToXnaCoordinates(this Point3D point) 
{ 
    return new Vector2(
     point.X + 320, 
     (point.Y - 240) * -1); 
} 

翻转y坐标的魔力是* -1部分。

如果您想要达到一个不同于640x480大小的矩形,则需要在转换后相应地缩放坐标。例如:

public static Vector2 ToScaledXnaCoordinates(this Point3D point, int rectSizeX, int rectSizeY) 
{ 
    return new Vector2(
     (point.X + 320) * rectSizeX/640, 
     (point.Y - 240) * -rectSizeY/480); 
} 
+0

+1从来没有想到的* -1 ...尽可能简单,因为它:) – 2012-07-23 14:36:26

+0

好吧,它的工作,非常感谢。但是另一个问题出现了。用我的方法,我有一个整洁的区域,向用户的光标指针移动,并使屏幕上的每个点都可以轻松到达,而不会拉伸或弯曲过多。我将你的方法应用到了我的'光标' - 方法的开关(手部) - 区块中,它的功能非常出色,但现在'传感器'区域恰好位于播放器的前方,并且降至略高于膝盖的水平。我尝试使用'if(cursorSpace.Contains)'的未修改的手部坐标,然后将'魔术'用作偏移,但是它没有按预期工作。有任何想法吗? – 2012-07-24 15:15:15

+0

为了最大限度地减少手部移动,我建议调整+320和-240。此外,您可能需要将坐标(移位后)缩放到矩形的大小。基本上,你将不得不尝试改变+320,-240,640,480值。不幸的是,我无法提供理想的解决方案,因为它因案例而异。但是,不要忘记,随着目标区域大小的增加,准确度会降低。 – 2012-07-25 06:17:40

0

我知道这是不是XNA,但我希望把这个在那里为那些WPF用户:)如果你正在使用类似的方法Channel 9's,只是有一个布尔值,以确定是否反转或不。例如:

private void ScalePosition(FrameworkElement element, Joint joint, bool inverted) 
    { 
     //convert the value to X/Y 
     Joint scaledJoint = joint.ScaleTo(967, 611); 

     //convert & scale (.3 = means 1/3 of joint distance) 
     //Joint scaledJoint = joint.ScaleTo(1280, 720, 1f, 1f); 
     if (!inverted) 
     { 
      Canvas.SetLeft(element, scaledJoint.Position.X); 
      Canvas.SetTop(element, scaledJoint.Position.Y); 
     } 

     if (inverted) 
     { 
      Canvas.SetLeft(element, scaledJoint.Position.X); 
      Canvas.SetBottom(element, scaledJoint.Position.Y); 
     } 
    } 

希望这有助于WPF用户!