如何使用 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();
        }

     
        
    }
}


範例程式碼下載:


更多相關資料參考:

這個網誌中的熱門文章

16天記下7000單字

nano 文字編輯器

2023 最新入門零基礎 Kotlin教學【從零開始學 Kotlin 程式設計】Kotlin 教學課程目錄 (Android Kotlin, IntelliJ IDEA, Android Studio, Android APP 開發教學)

2022 最新入門零基礎 Flutter教學 【Flutter 程式設計入門實戰 30 天】Flutter 教學課程目錄 (IntelliJ IDEA 開發教學)

【從零開始學 Flutter 程式設計】SharedPreferences 設定檔資料存取