星期三, 3月 21, 2012

如何使用 Kinect 來控制滑鼠鼠標移動 (For Windows SDK V1)

Photobucket
未來體感更發達,真的搞不好,「滑鼠」、「遙控器」都會變成一種歷史名詞。


現在看體感控制,其實真的越來越來進步,

已有玩家釋出,單純使用左、右手的五指來控制程式(Candescent NUI),

Photobucket

所以這些不再是遙不可及或只會在電影出現的畫面。



今天KT要來說明一下 :「如何使用 Kinect 來控制滑鼠鼠標移動」,

原作者Brian Peek,採用KinectWpfViewers控制項來完成,
Photobucket
最近KT收到的來信,都是希望可以改寫KinectWpfViewers的控制項,

或如何不去使用這控制項來完成,這件事確實有點困擾我。

KinectWpfViewers 真的滿好用的,不知道為什麼大家這麼排斥它,

裡面的source code,KT改天再來剖析給大家玩玩看。




所以今天來示範一下,不用KinectWpfViewers控制項,來控制滑鼠鼠標移動。

在講這之前,你需要有"骨架追蹤"的概念,因為這是屬於"骨架追蹤"的延伸應用。



有了骨架追蹤的概念,要來控制滑鼠鼠標移動,就變得是件很簡單的事,

因為只要追蹤出,如:右手關節點,然後將關節點的螢幕X、Y值,

餵給鼠標位置函數,這件事就等於大功告成。

// 取得左手和右手關節點
                    Joint jointRight = currentSkeleton.Joints[JointType.HandRight];
                    Joint jointLeft = currentSkeleton.Joints[JointType.HandLeft];

                    //將3D座標轉換成螢幕2D座標(採用Coding4Fun的ScaleTo方法)
                    Joint scaledRight = jointRight.ScaleTo((int)SystemParameters.PrimaryScreenWidth, (int)SystemParameters.PrimaryScreenHeight, SkeletonMaxX, SkeletonMaxY);
                    Joint scaledLeft = jointLeft.ScaleTo((int)SystemParameters.PrimaryScreenWidth, (int)SystemParameters.PrimaryScreenHeight, SkeletonMaxX, SkeletonMaxY);
                    
                    //採用右手關節點的 X和Y座標值,來控制滑鼠標
                    int cursorX, cursorY;
                    cursorX = (int)scaledRight.Position.X;
                    cursorY = (int)scaledRight.Position.Y;                  

                    //將右手座標,餵給 SendMouseInput這個方法,來改變滑鼠鼠標位置。
                    NativeMethods.SendMouseInput(cursorX, cursorY, (int)SystemParameters.PrimaryScreenWidth, (int)SystemParameters.PrimaryScreenHeight, leftClick);
                

另外可在加一些手勢判斷來控制滑鼠,如左手舉高,代表滑鼠左鍵按下:
private const float ClickThreshold = 0.33f;//大於此值,代表手舉高
bool leftClick;
                    //當左手大於舉起高度的臨界值,則代表左鍵按下。
                    if (jointLeft.Position.Y > ClickThreshold)
                    {
                        leftClick = true;
                    }
                    else
                    {
                        leftClick = false;
                    }

附帶一提,當然如果你是要用左手來控制鼠標,
則餵左手的關節點XY位置給鼠標位置函數:
//採用左手關節點X和Y座標值,來控制滑鼠標
cursorX = (int)scaledLeft.Position.X;
cursorY = (int)scaledLeft.Position.Y;

執行畫面:
Photobucket

完整XAML 程式碼如下:

    
             使用說明:右手:移動,改變滑鼠位置 左手:舉高,左鍵按下
    



完整C# 程式碼如下:

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Microsoft.Kinect;
using System.Linq;

using Coding4Fun.Kinect.Wpf;
using Microsoft.Kinect.Samples.CursorControl;

namespace KinectMouseControl_Demo
{
    public partial class MainWindow : Window
    {
        //大於此值,代表手舉高
        private const float ClickThreshold = 0.33f;

        //骨架 X 和 Y最高值設定
        private const float SkeletonMaxX = 0.60f;
        private const float SkeletonMaxY = 0.40f;

        //宣告 KinectSensor 裝置ID
        KinectSensor sensor = KinectSensor.KinectSensors[0];
        
        Skeleton[] skeletons;

        public MainWindow()
        {
            InitializeComponent();

            //宣告視窗"載入"和"卸載"處理函數
            this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
            this.Unloaded += new RoutedEventHandler(MainWindow_Unloaded);

            //平滑處理,防止高頻率微小抖動和突發大跳動造成的關節雜訊
            TransformSmoothParameters parameters = new TransformSmoothParameters();
            parameters.Smoothing = 0.7f;
            parameters.Correction = 0.3f;
            parameters.Prediction = 0.4f;
            parameters.JitterRadius = 1.0f;
            parameters.MaxDeviationRadius = 0.5f;
            sensor.SkeletonStream.Enable(parameters);

            //開啟骨架追蹤功能
            sensor.SkeletonStream.Enable();
        }

        //骨架追蹤處理函數
        void runtime_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
        {
            bool receivedData = false;

            using (SkeletonFrame SFrame = e.OpenSkeletonFrame())
            {
                if (SFrame == null)
                {
                    // The image processing took too long. More than 2 frames behind.
                }
                else
                {
                    skeletons = new Skeleton[SFrame.SkeletonArrayLength];
                    SFrame.CopySkeletonDataTo(skeletons);
                    receivedData = true;
                }
            }

            if (receivedData)
            {

                Skeleton currentSkeleton = (from s in skeletons
                                            where s.TrackingState == SkeletonTrackingState.Tracked
                                            select s).FirstOrDefault();

                if (currentSkeleton != null)
                {                   
                    // 取得左手和右手關節點
                    Joint jointRight = currentSkeleton.Joints[JointType.HandRight];
                    Joint jointLeft = currentSkeleton.Joints[JointType.HandLeft];

                    //將3D座標轉換成螢幕2D座標(採用Coding4Fun的ScaleTo方法)
                    Joint scaledRight = jointRight.ScaleTo((int)SystemParameters.PrimaryScreenWidth, (int)SystemParameters.PrimaryScreenHeight, SkeletonMaxX, SkeletonMaxY);
                    Joint scaledLeft = jointLeft.ScaleTo((int)SystemParameters.PrimaryScreenWidth, (int)SystemParameters.PrimaryScreenHeight, SkeletonMaxX, SkeletonMaxY);
                    
                    //採用右手關節點的 X和Y座標值,來控制滑鼠標
                    int cursorX, cursorY;
                    cursorX = (int)scaledRight.Position.X;
                    cursorY = (int)scaledRight.Position.Y;

                    bool leftClick;
                    //當左手大於舉起高度的臨界值,則代表左鍵按下。
                    if (jointLeft.Position.Y > ClickThreshold)
                    {
                        leftClick = true;
                    }
                    else
                    {
                        leftClick = false;
                    }

                    //將右手座標,餵給 SendMouseInput這個方法,來改變滑鼠鼠標位置。
                    NativeMethods.SendMouseInput(cursorX, cursorY, (int)SystemParameters.PrimaryScreenWidth, (int)SystemParameters.PrimaryScreenHeight, leftClick);
                }
            }
        }


      

 
        //視窗關閉,卸載處裡函數
        void MainWindow_Unloaded(object sender, RoutedEventArgs e)
        {
            //關閉 Kinect裝置
            sensor.Stop();
        }

        //視窗開啟,載入處裡函數
        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            //宣告骨架追蹤處理函數
            sensor.SkeletonFrameReady += runtime_SkeletonFrameReady;    
            
            //開啟 Kinect裝置
            sensor.Start();
        }

     
        
    }
}


範例程式碼下載:


更多相關資料參考:

1 則留言 :

回覆意見時,麻煩輸入一下暱稱
(隨便取個名字也好~ ^_^)
好讓我方便回覆您的問題,
選擇「名稱/網址」輸入您的暱稱,
麻煩一下,謝謝大家。

關閉廣告 [X]