KinectV2_人體索引(BodyIndex)_[WPF_vs_WinForm]

在 WPF上運行的測試結果





在 WPF上運行的代碼

視窗介面


MainWindow.xaml

<Window x:Class="KinectV2_BodyIndex_exercise.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:KinectV2_BodyIndex_exercise"
        mc:Ignorable="d"
        Title="MainWindow" Height="600" Width="1200"
        Loaded="Window_Loaded"
        Closing="Window_Closing"
        >
    <Grid>
        <Image x:Name="ImageBodyIndex"  Width="512" Height="424"/>
    </Grid>
</Window>



事件運行的代碼

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;


//K4W2  _  人體位置(BodyIndex) _ 練習範例

namespace KinectV2_BodyIndex_exercise
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        // Kinect SDK
        KinectSensor kinect;
        BodyIndexFrameReader bodyIndexFrameReader;
        FrameDescription bodyIndexFrameDesc;        
        byte[] bodyIndexBuffer;//宣告一個用來存放 BodyIndex 的 bodyIndexBuffer

        // 顯示用
        WriteableBitmap bodyIndexColorImage; //在WPF中我們使用WriteableBitmap物件顯示BitmapSource
        Int32Rect bodyIndexColorRect;
        int bodyIndexColorStride;
        int bodyIndexColorBytesPerPixel = 4;
        byte[] bodyIndexColorBuffer;

        Color[] bodyIndexColors;//使用Color這個Struct宣告一個存顏色的陣列

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            try
            {
                // Kinect設備獲取
                kinect = KinectSensor.GetDefault();
                kinect.Open();

                // 建立用於顯示的影格描述數據(BodyIndex)從深度資料獲取
                bodyIndexFrameDesc = kinect.DepthFrameSource.FrameDescription;

                // 開啟Reader
                bodyIndexFrameReader = kinect.BodyIndexFrameSource.OpenReader();
                bodyIndexFrameReader.FrameArrived += bodyIndexFrameReader_FrameArrived;


                // 初始化 BodyIndexBuffer的資料大小(空間)
                bodyIndexBuffer = new byte[bodyIndexFrameDesc.LengthInPixels];

                // WriteableBitmap位元圖物件的實體化,顯示資料的參數指派
                bodyIndexColorImage = new WriteableBitmap(
                    bodyIndexFrameDesc.Width, bodyIndexFrameDesc.Height,
                    96, 96, PixelFormats.Bgra32, null);

                /*new WriteableBitmap(int pixelWidth,            //所需的點陣圖寬度
                 *                    int pixelHeight,           //所需的點陣圖高度
                 *                    double dpiX,               //點陣圖的水平 dots per inch (dpi)
                 *                    double dpiY,               //點陣圖的垂直 dots per inch (dpi)
                 *                    PixelFormat pixelFormat,   //點陣圖的 PixelFormat
                 *                    BitmapPalette palette);    //點陣圖的 BitmapPalette                             
                 */


                bodyIndexColorRect = new Int32Rect(0, 0,bodyIndexFrameDesc.Width, bodyIndexFrameDesc.Height);

                //bodyIndexColorStride = 深度width:512    *   bodyIndexColorBytesPerPixel: 4 = 2048
                bodyIndexColorStride = bodyIndexFrameDesc.Width * bodyIndexColorBytesPerPixel;

                // 
                bodyIndexColorBuffer = new byte[bodyIndexFrameDesc.LengthInPixels *
                                                bodyIndexColorBytesPerPixel];

                ImageBodyIndex.Source = bodyIndexColorImage;

                // 創建一個顏色陣列 用來染色人體索引位置(最多總計6人)
                bodyIndexColors = new Color[]{Colors.Red, Colors.Blue, Colors.Green,
                                                Colors.Yellow, Colors.Pink, Colors.Purple,};
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                Close();
            }
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (bodyIndexFrameReader != null)
            {
                bodyIndexFrameReader.Dispose();
                bodyIndexFrameReader = null;
            }

            if (kinect != null)
            {
                kinect.Close();
                kinect = null;
            }
        }

        void bodyIndexFrameReader_FrameArrived(object sender,BodyIndexFrameArrivedEventArgs e)
        {
            UpdateBodyIndexFrame(e); //作影格資料更新
            DrawBodyIndexFrame();   //作顯示
        }

        // BodyIndex  影格更新
        private void UpdateBodyIndexFrame(BodyIndexFrameArrivedEventArgs e)
        {
            using (var bodyIndexFrame = e.FrameReference.AcquireFrame())
            {
                if (bodyIndexFrame == null)
                {
                    return;
                }

                // 取得BodyIndex 資料並傳至 bodyIndexBuffer
                //第一次中斷點停住時 bodyIndexBuffer裡面是空值 0~0
                //第一次中斷點停住時 bodyIndexBuffer裡面是255~255
                bodyIndexFrame.CopyFrameDataToArray(bodyIndexBuffer);
            }
        }

        // BodyIndex 的 顯示
        private void DrawBodyIndexFrame()
        {
            // 轉換人體索引的BGRA數據
            for (int i = 0; i < bodyIndexBuffer.Length; i++)
            {
                var index = bodyIndexBuffer[i];
                var colorIndex = i * 4;

                if (index != 255)
                {
                    var color = bodyIndexColors[index];
                    bodyIndexColorBuffer[colorIndex + 0] = color.B;
                    bodyIndexColorBuffer[colorIndex + 1] = color.G;
                    bodyIndexColorBuffer[colorIndex + 2] = color.R;
                    bodyIndexColorBuffer[colorIndex + 3] = 255;
                }
                else //非人體的區塊  pixel value 設為0(黑色背景)
                {
                    bodyIndexColorBuffer[colorIndex + 0] = 0;
                    bodyIndexColorBuffer[colorIndex + 1] = 0;
                    bodyIndexColorBuffer[colorIndex + 2] = 0;
                    bodyIndexColorBuffer[colorIndex + 3] = 255;
                }
            }

            // WriteableBitmap當中提供一個WritePixels 的 method
            //WriteableBitmap.WritePixels(Int32Rect sourceRect, 要更新的 WriteableBitmap矩形
            //                            byte[] pixels, 用來更新點陣圖的像素陣列 
            //                            int stride, 更新區域的步距 (Stride),以 pixels 為單位
            //                            int offset) 輸入緩衝區的位移
            bodyIndexColorImage.WritePixels
                (bodyIndexColorRect, bodyIndexColorBuffer, bodyIndexColorStride, 0);

        }
    }
}




DPI (Dots Per Inch): 每一英吋的點數量

用於點陣數位影像,意思是指每一英吋長度中,取樣或可顯示或輸出點的數目。

dpi正確來說是印表機或噴墨型輸出機的解析度單位,

例如1200dpi的解析度,就是指每一英吋能列印1200個點數量,也可稱為"設備解析度"。




以前大一的計概筆記
轉自:http://dryjoker.blogspot.tw/2014/02/ch6.html

一般顯示器為72 DPI,印刷所需點陣圖的DPI數則視印刷網線數而定。
而這裡的D(dot)就是像素(pixel)。



Printer(列印機)是一種輸出裝置能產生文字和圖像在實體媒介上像是紙張。
被印出在紙上呈現的資訊,被稱作hard copy(硬性拷貝) 列印出來的資訊是實際存在於紙張或檔案上面而且是一種更永久的顯現輸出型態。
Hard copy(硬拷貝)也被稱作printout(白話而言紙上列印)
列印orientation(方向)分成:
Portrait(直立式)
Landscape(橫列式)
……….p.313
Nonimpact Printers(非碰撞(接觸)式列印機)………..p.315
Nonimpact Printers(非碰撞式列印機)形成字符和圖像在一張紙上而事實上是沒有撞擊紙面的。有些使用噴墨、其他使用加熱或壓力去產生圖片影像。
8大類非撞擊式列印機:
Ink-jet printers
(噴墨式印表機)
1.      可以藉由噴灑小墨水滴在紙張上生成文字和圖像。…p.316
2.      它的解析度是以dots per inch(dpi)每一英吋裡所含有的點數來計算。…..p.316
3.      Dpi 性能(品質)↑ 墨汁耗量↑。……金本老師口頭解說
4.      噴墨式印表機工作四步驟:…..p.317
Step1.透過resistor(電阻)把墨水加熱產生蒸汽熱泡
Step2.蒸汽熱泡藉由nozzle(噴嘴)推動墨水
Step3.墨水滴在紙上
Step4.當蒸汽熱泡瓦解時,新的墨水右被拉進到燃燒室
Photo printers
(照片印表機)
1.      是一種彩色印表機能產生具有一定等級(photo-lab)品質的圖
片影像。……….p.318
2.      許多照片印表機使用噴墨式科技。……p.318
3.      PictBridge(不知道怎麼翻就背起來吧 再問就扭斷脖子喔)是一個標準規格科技能讓人很直接地從數位相機印出相片藉由連接印表機上的USB端口。……..p.318
4.      照片印表機通常含有內建卡的插槽為了能讓印表機可以很直接地從記憶卡中印出數位照片……p.318
5.      有些照片印表機含有內建液晶顯示彩色螢幕能讓使用者預先看見照片並對其作加強效果。…p.318
Laser printers
(雷射印表機)
1.          高品質高速度……p.319
2.          彩色黑白列印……p.319
3.          黑白雷射印表機是如何工作的呢?分5步驟
Step1.下指令去印一個文件然後磁鼓先把紙捲進去
Step2.選轉之鏡反射低能量的雷射激光越過磁鼓的表面
Step3.雷射激光會再磁鼓表面產生對應位置之碳粉使其附著
Step4.在磁鼓上的碳粉轉移至對應的紙面上
Step5.透過滾壓機的加熱與壓力之設定去使碳粉永遠黏著於紙上…….p.320
              Multifunction            Peripherals
        (MFP)(多功能週邊)
1.          也被稱作all-in-one(多合一)裝置,是一個單一裝置看起來很像印表機或影印機担卻提供了不只印表機、掃瞄機、影印機甚至傳真機的功能
2.           通常給small offices & home officeSOHO使用需要空間小又較不貴又划算…………….p.320
        Thermal Printers
(熱印表機)
1.          產生圖像靠加熱針頭()電子地推動到熱敏感的紙面上
2.          較便宜品質較差………..p.321
3.          底下又可分為thermal wax-transfer(熱蠟轉移)印表機跟dye-sublimation(染料昇華)印表機…..p.321

Mobile Printers
(行動式印表機)
是一種小型輕便仰賴電池供電的印表機,能讓行動中的使用者從他們的筆電、智能手機或其他行動裝置中做印表當它們在旅行時。

              Label &Postage Printers
        (標籤&郵資印表機)
1.          Label printer(標籤印表機)是一種小型專門印在具有黏著性物質上的印表機…………..p.322
2.          Postage printer(郵資印表機)是專門印在郵票上的特定型態之標籤印表機…………..p.322
              Plotters & Large-           Format Printers
                (繪圖器&大型規格印表機)
1.          Plotters(繪圖器)是一種精密印表機被用來產生高品質繪圖、地圖、藍圖、電路圖。
2.          Large-format printer(大型規格印表機)用來產生具有相片真實感品質的彩色列印

Impact Printers(撞擊式印表機)藉由列印磁頭的撞擊而且具有實際接觸紙面來形成字符、圖像到紙面上。
撞擊方式分成兩種:
Dot-matrix printer
一個一個撞擊
Line printer
一次列印一行



在WinForm上的程式撰寫結合 EmguCv3.1


運行效果




「傳感器」獲得「源」
「源」打開「閱讀器」
「閱讀器」獲得「視訊(frame)」





判定為人體的部分就只顯示 Blue Channel(255)

其餘部分皆為  黑色(0)也就是背景部分


這也相當於  一個  二值化影像的概念

藉助於  Emgucv 的 imageBox 可以幫助我們觀察

當滑鼠游標移置 身體區塊 這裡我又改設為三個通道為255(也就是白色)

B:255 G:255 R:255



當移至背景黑色區 就都是

B:0 G:0 R:0






Winform程式碼


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Kinect;
using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.Util;

namespace bodyIndex_K4W2
{
    public partial class Form1 : Form
    {
        KinectSensor sensor=null;
        BodyIndexFrameReader bodyIndexReader=null;
        FrameDescription fd=null;
        byte[] data = null;
        Image<Bgra, byte> bodyIndexImg;

        public Form1()
        {
            InitializeComponent();
            //獲取Kinect感測器
            sensor = KinectSensor.GetDefault();
            sensor.Open();//開啟

            //
            bodyIndexReader = sensor.BodyIndexFrameSource.OpenReader();
            bodyIndexReader.FrameArrived += bodyIndexReader_FrameArrived;

            fd = sensor.BodyIndexFrameSource.FrameDescription;
            bodyIndexImg = new Image<Bgra, byte>(fd.Width, fd.Height);
            data = new byte[fd.LengthInPixels*4];            
        }

        private void bodyIndexReader_FrameArrived(object sender, BodyIndexFrameArrivedEventArgs e)
        {
            using (BodyIndexFrame bodyFrame = e.FrameReference.AcquireFrame())
            {
                if(bodyFrame!=null)
                {
                    using (KinectBuffer kb = bodyFrame.LockImageBuffer())
                    {
                        if(fd.Width*fd.Height == kb.Size)
                        {
                            ProcessBodyIndexFrameData(kb.UnderlyingBuffer, kb.Size);
                        }
                        bodyIndexImg.Bytes = data;
                        imageBox1.Image = bodyIndexImg;
                    }
                }
            }
        }

        private unsafe void ProcessBodyIndexFrameData(IntPtr bodyIndexFrameData, uint bodyIndexFrameDataSize)
        {
            byte* frameData = (byte*)bodyIndexFrameData;
            for(int i=0;i<bodyIndexFrameDataSize;i++)
            {
                if(frameData[i]<6)
                {
                    data[i * 4] = 255;//B
                    data[i * 4 +1] = 0;//G
                    data[i * 4 +2] = 0;//R
                    data[i * 4 +3] = 255;//A
                }
                else
                {
                    data[i * 4] = 0;//B
                    data[i * 4 + 1] = 0;//G
                    data[i * 4 + 2] = 0;//R
                    data[i * 4 + 3] = 255;//A
                }
            }
        }
    }
}



















留言

這個網誌中的熱門文章

何謂淨重(Net Weight)、皮重(Tare Weight)與毛重(Gross Weight)

Architecture(架構) 和 Framework(框架) 有何不同?_軟體設計前的事前規劃的藍圖概念

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