Kinect V2 在Windows Form 上的配置教學_秀彩色影像_L1

Step1.  開啟  Windows Form 專案
























介面部分先單純只拉一個pictureBox物件



Step2.引入Kinect v2 的參考 及 命名空間






















Step3. 撰寫程式碼

這次目標要顯示彩影

首先我們要先思考怎麼秀出一般彩色影像


在一開始需要先宣告

【首先要引入(用)兩個命名空間(函式庫)】

一個是using Microsoft.Kinect

for Kinect SDK

一個是using System.Drawing.Imaging

用來指定 像素格式

 起初需在一開始做三個東西的宣告(皆要引用Microsoft.Kinect)
private KinectSensor KsOpen = null;//啟動Kinect感測器(傳感器接口處理)      
private FrameDescription frameDes = null;//影格描述
private ColorFrameReader colorReader ;//開啟




Kinect SDK V2中的基本觀念

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



開啟Kinect V2彩色視訊三階段處理(傳感器-->源-->閱讀器)

傳感器  三步驟處理

1.a 傳感器接口處理
private KinectSensor KsOpen = null;//啟動Kinect感測器 ...........................1.a

1.b獲得傳感器的默認
KsOpen = KinectSensor.GetDefault();//Kinect v2感測器獲取(獲得傳感器的默認)............1.b

1.c打開傳感器
KsOpen.Open();//開啟Kinect 使用它......................................................1.c



切記!!!
1.b  和   1.c都在
Form1_Load時做



===================================================================
源  兩步驟處理

傳感器得到


2.a顏色源之frame接口處理(先宣告 源 之影像影格描述)  
private FrameDescription frameDes = null;//影格描述(顏色源之frame接口)................2.a

使用  FrameDescription這個類(記得引用Microsoft.Kinect)
來做宣告

用來接收KinectSensor的彩色數據源











2.b獲得從傳感器接收到的彩色數據源

frameDes = KsOpen.ColorFrameSource.FrameDescription;
//獲得從傳感器接收到的彩色數據源.............2.b

























===================================================================

閱讀器    兩步驟處理

打開閱讀器


3.a 彩屏閱讀器界面框架(宣告彩色閱讀器)




3.b從感測器接收到的彩色數據源中開啟彩色Reader

















在 using System.Drawing.Imaging命名空間下

可滿足開發者指定像素格式的需求


後方有眾多PixelFormat這個列舉型態提供的像素格式參數





















在此我們選用 PixelFormat.Format32bppRgb

用來秀RGB


使用WritableBitmap來做處理

這邊請教了  我的好朋友 Vangos 如何在Windows Form撰寫 V2

而不是在WPF































這裡我們需要用Bitmap來代替WriteableBitmap

Bitmap使用  

(1)宣告








(2)指定參數(寬 , 高  , 像素格式 )


















WriteableBitmap 類別
提供 BitmapSource ,可以寫入而更新。
命名空間:   System.Windows.Media.Imaging
網頁link:
https://msdn.microsoft.com/zh-tw/library/system.windows.media.imaging.writeablebitmap(v=vs.110).aspx























Bitmap 類別


封裝 GDI+ 點陣圖的像素資料的圖形映像和其屬性所組成。
 A Bitmap 是用來處理影像像素資料所定義的物件。

命名空間:   System.Drawing
組件:  System.Drawing (在 System.Drawing.dll 中)

網頁link:
https://msdn.microsoft.com/zh-tw/library/system.drawing.bitmap(v=vs.110).aspx


























彩色數據流排放格式順序和大小

彩色圖像的結構















每一pixel佔32個位元,也就是4個byte

其中是以  藍 --> 綠 --> 紅 --> 透明值   這樣排序

皆為 unsigned integer


我們來想一下一整張frame  共包含多個 pixel 呢???

不是就   寬 乘 高 這麼多嗎

那每一 pixel 又佔了 4個byte


喔   原來如此


那就需要多宣告一個   unit  做大小吧!!!
你也可以用  UInt32  會有  異曲同工之妙










第一階段程式碼



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; // for Kinect SDK
using System.Drawing.Imaging; // for PixelFormat

namespace KinectV2_WindowsFormsApplication
{
    public partial class Form1 : Form
    {
        private KinectSensor KsOpen = null;//啟動Kinect感測器
        private FrameDescription frameDes = null;//影格描述
        private ColorFrameReader colorReader ;

        private Bitmap Bmp; // 給影像pictureBox物件做承載
        private Rectangle Rect;
        private uint Size;
        

        public Form1()
        {
            InitializeComponent(); 
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            KsOpen = KinectSensor.GetDefault();//Kinect v2感測器獲取

            frameDes = KsOpen.ColorFrameSource.FrameDescription;
            //在全屏模式RGB攝像頭的位圖格式數據流的數據(1920×1080像素)
            Bmp = new Bitmap(frameDes.Width , frameDes.Height ,PixelFormat.Format32bppRgb);
            Rect = new Rectangle(0, 0, frameDes.Width, frameDes.Height);
            Size = (uint)(frameDes.Width * frameDes.Height * 4);


            colorReader = KsOpen.ColorFrameSource.OpenReader();
            colorReader.FrameArrived += colorReader_FrameArrived;
            KsOpen.Open();//開啟Kinect 使用它
        }

        private void colorReader_FrameArrived(object sender, ColorFrameArrivedEventArgs e)
        {
            //throw new NotImplementedException();
            using (ColorFrame colorFrame = e.FrameReference.AcquireFrame())
            {
                //.NET Compact Framework 提供 LockBits 方法的支援
                //這個方法可讓您在未受管理的記憶體緩衝區中操作點陣圖的像素陣列
                //將點陣圖中的像素換成來自緩衝區的像素。
                BitmapData cBitmapData = Bmp.LockBits(Rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppRgb);
                //換言之,就是將 Bitmap 鎖定在系統記憶體內
                //LockBits參數 
                /*
                 LockBits(System.Drawing.Rectangle,
                            System.Drawing.Imaging.ImageLockMode, 
                              System.Drawing.Imaging.PixelFormat);
                */


                colorFrame.CopyConvertedFrameDataToIntPtr(cBitmapData.Scan0, Size, ColorImageFormat.Bgra);
                Bmp.UnlockBits(cBitmapData);

                // 相對於y軸上對pictureBox物件做左右翻轉
                Bmp.RotateFlip(RotateFlipType.Rotate180FlipY);

                pictureBox1.Image = Bmp;
            }
        }


    }
}




不過你在測試完之後會發現有幾個問題需要修正

第一.影像畫面有點不穩定


















第二.只顯示在某一區塊(右上角還左上角的樣子)























手靠近感測器 畫面























原因是因為

PictureBoxSizeMode.Normal

默認情況下,在Normal 模式中,
Image 置於PictureBox 的左上角,
凡是因過大而不適合PictureBox 的任何圖像部分都將被剪裁掉





PictureBoxSizeMode這個列舉型態提供總共五種參數給你作修正
若沒設定   默認就為 Normal 喔!!!!



PictureBoxSizeMode.StretchImage
使用StretchImage 值會使圖像拉伸或收縮,較適合PictureBox,方便我們看到完整畫面喔。






















PictureBoxSizeMode.CenterImage
使用CenterImage 值會使圖像居於工作區的中心。





















PictureBoxSizeMode.Zoom
使用Zoom 的值可以使圖像被拉伸或收縮以適應PictureBox;但是仍然保持原始寬高比。























PictureBoxSizeMode.AutoSize
使用AutoSize 值會使控件調整大小,以便總是適合圖像的大小































在經過多次測試後
發現很長跳出此錯誤訊息























到底發生捨麼問題了  真是God!!!!






















他是說需要多加一個   判別  colorFrame 是否為 null 的判斷

那我們就加吧


























修正過後的
最後階段code



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; // for Kinect SDK
using System.Drawing.Imaging; // for PixelFormat

namespace KinectV2_WindowsFormsApplication
{
    public partial class Form1 : Form
    {
        private KinectSensor KsOpen = null;//啟動Kinect感測器 ...........................1.a
        private FrameDescription frameDes = null;//影格描述(顏色源之frame接口)................2.a
        private ColorFrameReader colorReader;//彩屏閱讀器界面框架(宣告彩色閱讀器)................3.a 

        private Bitmap Bmp; // 給影像pictureBox物件做承載
        //private uint Size;
        private UInt32 Size;

        private Rectangle Rect;
        
        

        public Form1()
        {
            InitializeComponent(); 
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            KsOpen = KinectSensor.GetDefault();//Kinect v2感測器獲取(獲得傳感器的默認)............1.b

            frameDes = KsOpen.ColorFrameSource.FrameDescription;//獲得從傳感器接收到的彩色數據源...2.b
            //RGB攝像頭的位元圖格式數據流的數據(1920×1080像素)
            Bmp = new Bitmap(frameDes.Width , frameDes.Height ,PixelFormat.Format32bppRgb);
            Rect = new Rectangle(0, 0, frameDes.Width, frameDes.Height);
            Size = (uint)(frameDes.Width * frameDes.Height * 4);

            //this.pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
            //this.pictureBox1.SizeMode = PictureBoxSizeMode.CenterImage;
            this.pictureBox1.SizeMode = PictureBoxSizeMode.Zoom;
            //this.pictureBox1.SizeMode = PictureBoxSizeMode.AutoSize;



            colorReader = KsOpen.ColorFrameSource.OpenReader();//從感測器接收到的彩色數據源中開啟彩色Reader.......3.b
            colorReader.FrameArrived += colorReader_FrameArrived;
            KsOpen.Open();//開啟Kinect 使用它......................................................1.c
        }

        private void colorReader_FrameArrived(object sender, ColorFrameArrivedEventArgs e)
        {
            //throw new NotImplementedException();
            using (ColorFrame colorFrame = e.FrameReference.AcquireFrame())
            {
                if (colorFrame != null)
                {
                    //.NET Compact Framework 提供 LockBits 方法的支援
                    //這個方法可讓您在未受管理的記憶體緩衝區中操作點陣圖的像素陣列
                    //將點陣圖中的像素換成來自緩衝區的像素。
                    BitmapData cBitmapData = Bmp.LockBits(Rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppRgb);
                    //換言之,就是將 Bitmap 鎖定在系統記憶體內
                    //LockBits參數 
                    /*
                     LockBits(System.Drawing.Rectangle,
                                System.Drawing.Imaging.ImageLockMode, 
                                  System.Drawing.Imaging.PixelFormat);
                    */
                    colorFrame.CopyConvertedFrameDataToIntPtr(cBitmapData.Scan0, Size, ColorImageFormat.Bgra);
                    Bmp.UnlockBits(cBitmapData);

                    // 相對於y軸上對pictureBox物件做左右翻轉
                    Bmp.RotateFlip(RotateFlipType.Rotate180FlipY);

                    pictureBox1.Image = Bmp;
                }
            }
        }


    }
}





希望對相關開發者有幫助

------------------------------------------------------------------------------------------------------
PictureBoxSizeMode部分參考部落格
【C#圖解】PictureBox.SizeMode 屬性   作者:銀月術
http://blog.csdn.net/moonsilvering/article/details/5940506


Bitmap部分代換問題請教於
微軟MVP
Vangos Pterneas






留言

  1. 可以請問一下kinectV2的深度圖如何用在windows form

    回覆刪除

張貼留言

這個網誌中的熱門文章

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

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

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