如何使用Kinect_V2_在WPF開發應用_基於KinectV2開發的_揮拍復健系統測試_加油~體感復健系統開發工程師

首先我們應該要先能夠開啟Kinect 攝像機

Kinect 的 準備流程

(1) 取得 Sensor / Get the sensor
(2)選擇你所要讀取的資料源(data source) / Select the data source to read from
(3)處理從資料源讀取到的資料 / Handle the data you read from the source



「傳感器」獲得「源」
「源」打開「閱讀器」



【第一階段_先開啟彩色視訊】

MainWindow.xaml.cs
(程式運行的功能)


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Kinect;



namespace Kinect_V2_flappy_bird
{
    /// <summary>
    /// MainWindow.xaml 的互動邏輯
    /// </summary>
    public partial class MainWindow : Window
    {
        KinectSensor sensor;
        ColorFrameReader colorFrameReader;
        WriteableBitmap colorBitmap;

        public MainWindow()
        {            
            InitializeComponent();
            
            //Get the sensor
            sensor = KinectSensor.GetDefault();
            sensor.Open();

            //setup readers for each source of data we want to use
            colorFrameReader = sensor.ColorFrameSource.OpenReader();

            //setup event handlers that use what we get from the readers
            colorFrameReader.FrameArrived += this.Reader_ColorFrameArrived;

            //create the bitmap to display
            colorBitmap = new WriteableBitmap(1920,1080,96.0,96.0,PixelFormats.Bgr32,null);
            ColorImage.Source = colorBitmap;
        }

        private void Reader_ColorFrameArrived(object sender, ColorFrameArrivedEventArgs e)
        {
            //Get the current frame in a memory-safe manner
            using (ColorFrame colorFrame = e.FrameReference.AcquireFrame())
            {                 
                //Defensive programming : Just in case the sensor frame is no longer valid
                if (colorFrame == null)
                    return;

                using (KinectBuffer colorBuffer = colorFrame.LockRawImageBuffer() )
                {
                    //Put a thread-safe lock on this data so it doesn't get modified elsewhere
                    colorBitmap.Lock();
                    //Let the application know where the image is being stored                  
                    colorFrame.CopyConvertedFrameDataToIntPtr(
                        colorBitmap.BackBuffer,
                        (uint)( 1920 * 1080 * 4 ), //width*height*BytesPerPixel
                        ColorImageFormat.Bgra);

                    //Let the application know that it needs to redraw the screen in this area(the whole image)
                    colorBitmap.AddDirtyRect(new Int32Rect(0,0,colorBitmap.PixelWidth,colorBitmap.PixelHeight));
                    //Remove the thread-safe lock on this data
                    colorBitmap.Unlock();
                }
            }
        }

        void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            sensor.Close();
        }




    }
}


MainWindow.xaml
(介面布局)


<Window x:Class="Kinect_V2_flappy_bird.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Image x:Name="ColorImage" HorizontalAlignment="Left" VerticalAlignment="Top" Stretch="UniformToFill"/>
    </Grid>
</Window>



效果圖



可以開啟彩色視訊畫面了


緊接著


我做了幾件事情




KinectV2 _ 雙手y座標值顯示 開發平台 WPF

藉助於 WPF 幫助我們 秀出 y座標值的改變


可以清楚觀察到  兩手 y座標值上升下降隨之改變


我們在來做一件事情

將 y座標值改為

z座標值

【KinectV2雙手Z座標值變化觀察】
目的 觀察手部離攝影機的遠近變化幅度
擬研究出一套簡易的揮拍計數系統
左下方 textBox 藉助於 WPF 幫助我們 秀出 揮拍計數




本來是想試著統計揮拍次數
後來問了資深高手和老師發線

Accelerator 在舊版kinect裡才有,新版因無需求,而沒在裡面
末位置、初位置,就是位置而已,拿位置來用即可



這裡我做了一個簡易版的計算

雙手一同靠近攝影機鏡頭時
值約介於 0.6160924 ~ 0.6857489
雙手一同遠離攝影機鏡頭時
值約介於1.534026 ~ 1.82197
右手Z值
第一次遠離為
為 1.821213


第一次靠近
為 0.6228145


第二次遠離
為 1.836249

第二次靠近
為 0.6664682

第三次遠離
為 1.853669
第三次靠近
為 0.6488236

我們把 第一次靠近值相加取平均
( 0.6228145 + 0.6664682 + 0.6488236 ) / 3 = 0.6460354333
再把 第一次遠離值相加取平均
( 1.821213 + 1.836249 + 1.853669 ) / 3 = 1.83704366
這樣就可以得到兩組平均門檻值

最後將 這兩個得到的平均值相加
除以2
(0.6460354333 + 1.83704366 ) / 2 = 1.24153954665
這個數值我們稱之為「中間值平面」
Median Value Plane

這個數值先暫存起來等之後或許會有用到

基於KinectV2開發的_揮拍復健系統測試(右撇子)測試
-網球肘,顧名思義是網球運動常發生的症狀,一般而言,大約有30%的網球選手都有過這樣的經驗,其實網球肘不止是網球的專利,像是高爾夫球、棒球、排球等需要做出擊球、投球動作的運動上、都能見到網球肘的蹤跡,只要感覺肘關節周圍有出現原因不明的疼痛,就可泛稱為網球肘。







MainWindow.xaml.cs
(程式運行的功能)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Kinect;



namespace Kinect_V2_flappy_bird
{
    /// <summary>
    /// MainWindow.xaml 的互動邏輯
    /// </summary>
    public partial class MainWindow : Window
    {
        KinectSensor sensor;
        
        ColorFrameReader colorFrameReader;
        BodyFrameReader bodyFrameReader;

        WriteableBitmap colorBitmap;

        Body[] bodies;

        public MainWindow()
        {            
            InitializeComponent();
            
            //Get the sensor
            sensor = KinectSensor.GetDefault();
            sensor.Open();

            //setup readers for each source of data we want to use
            colorFrameReader = sensor.ColorFrameSource.OpenReader();

            bodyFrameReader = sensor.BodyFrameSource.OpenReader();


            //setup event handlers that use what we get from the readers
            colorFrameReader.FrameArrived += this.Reader_ColorFrameArrived;
            bodyFrameReader.FrameArrived += this.Reader_BodyFrameArrived;


            //create the bitmap to display
            colorBitmap = new WriteableBitmap(1920,1080,96.0,96.0,PixelFormats.Bgr32,null);
            ColorImage.Source = colorBitmap;
        }

        private void Reader_BodyFrameArrived(object sender, BodyFrameArrivedEventArgs e)
        {
            using (BodyFrame bodyFrame = e.FrameReference.AcquireFrame())
            {
                if (bodyFrame == null)
                    return;

                if (bodies == null)
                {  //Create an array of the bodies in the scene and update it
                    bodies = new Body[bodyFrame.BodyCount];
                }
                bodyFrame.GetAndRefreshBodyData(bodies);

                //For each body in the scene
                foreach (Body body in bodies)
                {
                    if (body.IsTracked)
                    {
                        var joints = body.Joints; // Get all of the joints in that body
                        if(joints[JointType.HandRight].TrackingState==TrackingState.Tracked && 
                            joints[JointType.HandLeft].TrackingState == TrackingState.Tracked)
                        {
                            //txtLeft.Text = joints[JointType.HandLeft].Position.Y.ToString();
                            //txtRight.Text = joints[JointType.HandRight].Position.Y.ToString();
                            txtLeft.Text = joints[JointType.HandLeft].Position.Z.ToString();
                            txtRight.Text = joints[JointType.HandRight].Position.Z.ToString();
                            if (joints[JointType.HandRight].Position.Z < 0.6460354333)
                            {
                                avgNear.Content = "靠近了";
                            }
                            else
                            {
                                avgNear.Content = "沒靠近了";
                            }

                            if (joints[JointType.HandRight].Position.Z > 1.83704366)
                            {
                                avgFar.Content = "遠離了";
                            }
                            else
                            {
                                avgFar.Content = "沒遠離了";
                            }
                        }
                    }
                }
            }
        }


        
        private void Reader_ColorFrameArrived(object sender, ColorFrameArrivedEventArgs e)
        {
            //Get the current frame in a memory-safe manner
            using (ColorFrame colorFrame = e.FrameReference.AcquireFrame())
            {                 
                //Defensive programming : Just in case the sensor frame is no longer valid
                if (colorFrame == null)
                    return;

                using (KinectBuffer colorBuffer = colorFrame.LockRawImageBuffer() )
                {
                    //Put a thread-safe lock on this data so it doesn't get modified elsewhere
                    colorBitmap.Lock();
                    //Let the application know where the image is being stored                  
                    colorFrame.CopyConvertedFrameDataToIntPtr(
                        colorBitmap.BackBuffer,
                        (uint)( 1920 * 1080 * 4 ), //width*height*BytesPerPixel
                        ColorImageFormat.Bgra);

                    //Let the application know that it needs to redraw the screen in this area(the whole image)
                    colorBitmap.AddDirtyRect(new Int32Rect(0,0,colorBitmap.PixelWidth,colorBitmap.PixelHeight));
                    //Remove the thread-safe lock on this data
                    colorBitmap.Unlock();
                }
            }
        }
        

        void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            sensor.Close();
        }
    }
}



MainWindow.xaml
(介面布局)




<Window x:Class="Kinect_V2_flappy_bird.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="600" Width="800">
    <Grid>
        <Image x:Name="ColorImage" HorizontalAlignment="Left" VerticalAlignment="Top" Stretch="UniformToFill"/>
        <TextBox x:Name="txtLeft"  HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120" FontSize="18.667"/>
        <TextBox x:Name="txtRight" HorizontalAlignment="Right" Height="23" Margin="0,0,-0.333,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120" FontSize ="18.667"/>

        <TextBox x:Name="txtNum" HorizontalAlignment="Left" Height="23" Width="120" VerticalAlignment="Bottom" FontSize="18.667" TextWrapping="Wrap"/>
        <Label x:Name="avgNear"  Content="接近靠近平均值時做警示" HorizontalAlignment="Left" Margin="547,498,0,0" VerticalAlignment="Top" Height="48" Width="235" FontSize="18.667" Background="#FF1B9EC5" Foreground="#FF782064"  />
        <Label x:Name="avgFar" Content="接近遠離平均值時做警示" HorizontalAlignment="Left" Margin="547,445,0,0" VerticalAlignment="Top" Height="48" Width="235" FontSize="18.667" Background="#FF62B84F" BorderBrush="#FFDADA3F" Foreground="#FF020295"  />        
    </Grid>
</Window>





會有這個衝動做這個  除了一個原因是因為專題需用到之外

還有就是是  看到  朋友

Vangos  做了一個舉重的應用

覺得很厲害

也想像他學習

XDD    加油    體感復健系統開發工程師







留言

這個網誌中的熱門文章

經得起原始碼資安弱點掃描的程式設計習慣培養(五)_Missing HSTS Header

經得起原始碼資安弱點掃描的程式設計習慣培養(三)_7.Cross Site Scripting(XSS)_Stored XSS_Reflected XSS All Clients

(2021年度)駕訓學科筆試準備題庫歸納分析_法規是非題