Lập trình xử lý anh với kinect

Đã đăng vào thg 11 29, 2015 10:26 SA 4 phút đọc

Lời mở đầu

**Ở bài trước, tôi đã giới thiệu với các bạn cách tạo animation cho nhân vật và xuất ra định dạng file để có thể sử dụng trong game engine Unity. Ở bài này, tôi muốn giới thiệu một ứng dụng khác của Kinect trong việc làm game, nó sẽ được sử dụng như một đạo cụ, phương thức để người chơi tương tác với game. **

**Đặc điểm của Kinect là nó đặc trang bị một cảm biến hồng ngoại, giúp tạo được một depth map [biết được khoảng cách đến từng điểm trên ảnh]. Nhờ có thông tin của depth, việc nhận dạng con người và các cử chỉ của họ một cách tự động đã trở nên dễ dàng, chính xác hơn. Do đó, chúng ta hoàn toàn có thể áp dụng nhận dạng cử chỉ của người chơi và lập trình các hành động tương ứng với các cử chỉ đó. **

Cài đặt

  • Tải Kinect SDK 1.8 [Đã thử với bản 2.0 trở đi nhưng lỗi thư viện với wrapper]
  • Tải Kinect wrapper package cho Unity theo link dưới đây

//wiki.etc.cmu.edu/unity3d/index.php/Microsoft_Kinect_-_Microsoft_SDK

  • Import package vào project.

Làm quen

Trong package có một số ví dụ, việc bạn cần làm để trải nghiệm là cắm giắc nối Kinect vào và play the scene

. Điều quan trọng là bạn nên tìm hiểu về cấu trúc, cách vận hành của từng class, ví dụ như class SkeletonWrapper để lấy thông tin vị trí người chơi, depthwrapper xử lý thông tin của depth map,...

Qua đó, bạn có thể nắm được phần nào sẽ cần thiết cho game của bạn, cấu trúc thông tin như thế nào.

Thực hiện

Đến đây, những gì tôi đã trình bày vẫn hơi trừu tượng và rất khó hình dung phải không? Vậy thông tin vị trí của người chơi là như thế nào? Dựa theo mô hình cấu tạo xương người, SDK đã tạo ra mô hình với những điểm khớp xương và nối các điểm đó lại, ta có một khung người cơ bản [skeleton]. Và SDK có khả năng track vị trí [x, y, z] của những điểm khớp đó. Việc lấy thông tin đó rất đơn giản, trong wrapper, ta chỉ cần gọi

Kinect.NuiSkeletonPositionIndex.Head;

là sẽ lấy được thông tin vị trí x,y,z của đầu, tương tự như tay, bàn tay, cổ,... Hay ta cũng có thể lấy thông tin của toàn bộ các điểm khớp bằng cách gọi

SkeletonWrapper.bonePos;

Theo những gì tôi đã trình bày, việc lấy thông tin người chơi quả thực dễ dàng, nhưng việc xử lý những thông tin đấy như thế nào lại là một câu chuyện khác. Làm sao từ những thông tin vị trí đấy có thể biết được người chơi đang thực hiện động tác nào, người chơi mong muốn máy sẽ phản ứng ra sao? Đó hoàn toàn phụ thuộc vào nội dung game của bạn, bạn cần tạo ra một tập hợp những hành động của người chơi, và ánh xạ tới những xử lý tương ứng trong chương trình của bạn.

Trong những ngày đầu tiên tiếp xúc với lập trình game của tôi, tôi đã tạo một game với Kinect, cách tôi xử lý với những hành động của người chơi là tính toán khoảng cách tương đối giữa các khớp và định nghĩa đó là 1 action tương ứng trong game. Ví dụ như: Đầu người chơi di chuyển theo phương x sẽ tương ứng với nhân vật của tôi đi ngang, tay giơ lên cao -> tấn công,...

Demo

Dưới đây là game tôi làm từ những ngày đầu, sử dụng Unity với Kinect: //drive.google.com/file/d/0B2mj3ezS8y7mdU12Qm1KSU03Zms/view?usp=sharing

All rights reserved

2.Tìm hiểu và sử dụng thư viện Kinect

Thư viện Kinect là thư viện do Microsoft tạo ra để tạo môi trường cho người dùng có thể dễ dàng xây dựng những ứng dụng một cách nhanh chóng trên cả PC lẫn dòng máy chơi game Xbox 360. Thư viện này hỗ trợ cho cả 3 ngôn ngữ thông dụng là C#, C++ và VB đồng thời cũng tương thích với win7 và 8. Hiện tại, phiên bản mới nhất là SDK for Kinect version 1.6 đã cải tiến nhiều tính năng nên dễ sử dụng và tỏ ra là một lựa chọn hiệu quả hơn so với các thư viện mã nguồn mở. Tuy nhiên để sử dụng thư viện này cho các ứng dụng thương mại thì cần trả tiền bản quyền cho Microsoft.

Yêu cầu hệ thống :

·        Microsoft Kinect SDK – Các bạn có thể download tại đây .

·        Visual Studio 2010 .

·        Kinect

Để bắt đầu với tìm hiểu, ở đây sẽ sử dụng C#.

2.1 Tạo project:

Bước đầu tiên cần thực hiện là tạo một project mới, có thể là dạng Windows Forms hay dạng WPF.

Bước tiếp theo là thực hiện add reference để có thể thao tác với Kinect SDK. Bấm chuột phải vào phần References ở cửa sổ bên trái  và chọn Add reference sau đó tìm file Microsoft.Kinect.dll trong tab .Net

Chú ý rằng nếu sử dụng các phiên bản beta thì file cần add là Microsoft.Research.Kinect.

 2.2Thiết lập cho Kinect

Hầu như tất cả các chương trình Kinect đều bắt đầu như nhau.

Đầu tiên là tìm kiếm các senser đã kết nối với máy tính và kiểm tra tình trạng của chúng. [Chú ý rằng các phiên bản trước thì code sẽ hơi khác so với bản 1.6]

Để làm việc này chúng ta khai báo một đối tượng thuộc lớp KinectSenser

Khai báo thêm  thư viện kinect       using Microsoft.Kinect;

Trong sự kiện  WindowLoaded chúng ta sử dụng lệnh foreach để kiểm tra tất cả các sensor đc kết nối.

   foreach [var SensorKetNoi in KinectSensor.KinectSensors]

            {

                if[SensorKetNoi.Status == KinectStatus.Connected]

                {

                    this.sensor = SensorKetNoi;

                    break;

                }

            }

Khi tất cả các senser đã được kết nối, ta tiến hành cho phép nhận các dòng dữ liệu cần thiết cho ứng dụng như độ sâu, âm thanh hoặc ảnh màu từ cảm biến sau đó khởi động cảm biến và viết các hàm để xử lý dữ liệu nhận được [Có thể là xuất ảnh ra màn hình, tính toán khoảng cách, nhận dạng…]

if [null!= this.sensor]

     {

                this.sensor.ColorStream.Enable[ColorImageFormat.RgbResolution640x480Fps30];

                this.sensor.DepthStream.Enable[DepthImageFormat.Resolution640x480Fps30];

this.sensor.SkeletonStream.Enable[];

            // Khởi động sensor!

            this.sensor.Start[];

      }

2.3 Nhận và hiển thị dữ liệu từ cảm biến.

Dữ liệu gửi về dưới dạng data stream. NUI API cho phép lập trình kiểm soát và truy nhập dữ liệu.

Các bước làm bao gồm:

1.      Xác định dòng dữ liệu cần thiết.

2.      Cho phép mở dòng dữ liệu [Enable Data Streaming]

3.      Tạo bộ đệm để lưu trữ dữ liệu sensor.

4.      Giải phóng bộ đệm để có thể sử dụng trong khung hình tiếp theo.

Trong việc hiển thị dữ liệu, các hàm hỗ trợ trong SDK rất phức tạp, các bạn có thể down Coding4Fun.Kinect.Toolkit về sau đó add reference đến file coding4Fun.Kinect.winForm.dllhoặc coding4Fun.Kinect hoặc coding.4Fun.kinect.Wpf.dll

[bằng cách chuột phải lên refeference -> chọn thẻ browse-> dẫn đến thư mục  Coding4Fun.Kinect.Toolkit]

Khi sử dụng bạn chú ý thêm  using Coding4Fun.Kinect.WinForm;

2.3.1  ColorStream:

ColorStream có nhiều độ phân giải và định dạng tùy thuộc vào các lựa chọn colorStream là RGB, YUV hay Bayer.

SDK cung cấp một số tùy chọn cho phép tối ưu hóa camera ứng với các tác động môi trường như:

         Tăng giảm độ sáng

         Thay đổi màu sắc, độ tương phản

Tất cả được hỗ trợ trong class ColorCameraSetting.

Để hiển thị các thành phần dữ liệu mầu sắc bằng C# chúng ta cần tiến hành các công việc sau:

         Khởi tạo cảm biến để tạo dữ liệu màu [đã đề cập ở trên]

         Tạo sự kiện thông báo dữ liệu đã sẵn sàng.

         Xử lý sự kiện và hiển thị lên Forms.

a.      Tạo sự kiện báo dữ liệu đã sẵn sàng:

if [this.sensor != null]

          {

            this.sensor.ColorFrameReady += this.SensorColorFrameReady;

          }

b.      Xử lý sự kiện và hiển thị lên Forms.

Ví dụ bên dưới được thực hiện với windows Forms với sự hỗ trợ của công cụ Coding4Fun.Kinect.Toolkit . Để hiển thị với WPF các bạn có thể tham khảo thêm ở địa chỉ.

private void SensorColorFrameReady[objectsender,                                         

                                     ColorImageFrameReadyEventArgse]

          {

            using[ColorImageFrame colorFrame = e.OpenColorImageFrame[]]

            {

              if[colorFrame != null]

              {

                  colorImage.Image = colorFrame.ToBitmap[];

              }

            } 

          }

2.3.2 Depth Stream

Mỗi khung hình của dữ liệu Depth Stream được tạo thành từ các pixels chứa khoảng cách [bằng mm] từ mặt phẳng camera đến đối tượng.

Các ứng dụng có thể sử dụng depth data để bám theo chuyển động hoặc nhận dạng đối tượng.

Dữ liệu về khoảng cách tính bằng mm là bộ số [x,y] chứa tọa độ trong field of view của sensor.

Có 3 tùy chọn độ phân giải là 640×480 [mặc định], 320×240 vào 80×60. Tất cả được quy định trong DepthImageFormat Enumeration.

Việc hiển thị dữ liệu cho DepthStream hoàn toàn tương tự ColorStream.

if [this.sensor != null]

          {

            this.sensor.DepthFrameReady += this.SensorDepthFrameReady;

          }

private void SensorDepthFrameReady [object sender,                                         

                                     ColorImageFrameReadyEventArgse]

          {

            using[DepthImageFrame DepthFrame = e.OpenColorImageFrame[]]

            {

              if[DepthFrame != null]

              {

                  DepthImage.Image = DepthFrame.ToBitmap[];

              }

            } 

          }

2.4 Điều khiển góc nghiêng sensor

Góc nghiêng của sensor trong kinect có giá trị từ -27 đến 27, giá trị này tính theo phương vuông góc với trọng lực, tức là nếu góc bằng 0 thì phương của camera sẽ vuông góc với trọng lực.

Để điều khiển góc nghiên của sensor ta sử dụng thuộc tính sensor.ElevationAngle

Thuộc tính này cho phép ta có thể get hoặc set giá trị cho góc sensor.

Ví dụ sau mô tả việc hiển thị góc và đặt giá trị góc nghiêng bằng một thanh cuộn ngang kết hợp với 1 nút bấm và hiển thị giá trị đó lên một label.

private voidhScr_dieuChinhGoc_ValueChanged[object sender, EventArgs e]

        {

            lbl_gocnghieng.Text = hScr_dieuChinhGoc.Value.ToString[];

        }

        private voidbutton1_Click[object sender, EventArgs e]

        {

            sensor.ElevationAngle = hScr_dieuChinhGoc.Value;

        }

2.5 Demo sử dụng Kinect với WindowsForms

Demo này tổng hợp lại các ví dụ ở trên trong đó sử dụng các thành phần sau:

         2 PictureBox là colorImage và DepthImage để hiển thị dữ liệu ảnh mầu và dữ liệu độ sâu.

         1 HscrollBar là hScr_dieuChinhGoc kết hợp với 1 Button để đặt giá trị góc quay.

         Các lable lbl_HienThiGocNghieng và lbl_gocnghieng để hiển thị giá trị đo góc.

vCode

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

using Microsoft.Kinect;

using Coding4Fun.Kinect.WinForm;

namespace DemoWinForm2

{

    public partial class Form1 : Form

    {

        private KinectSensorsensor;// Khai báo sensor

        public Form1[]

        {

            InitializeComponent[];

        }

        private voidForm1_Load[object sender, EventArgs e]

        {  

            //Kiểm tra các sensor được kết nối

            foreach[varsensorKetnoi in KinectSensor.KinectSensors]

            {

                if[sensorKetnoi.Status==KinectStatus.Connected]

                {

                    this.sensor = sensorKetnoi;

                    break;

                }

            }

            if[this.sensor!=null]

            {  

 // Enable dòng dữ liệu và thiết lập các tùy chọn cho dữ liệu ảnh

                this.sensor.ColorStream.Enable[ColorImageFormat.RgbResolution640x480Fps30];

// Enable dòng dữ liệu và thiết lập các tùy chọn cho dữ liệu độ sâu

                this.sensor.DepthStream.Enable[DepthImageFormat.Resolution320x240Fps30];

                // Khởi động sensor

                this.sensor.Start[];

                // Hiển thị góc nghiêng ban đầu của sensor.

                lbl_gocnghieng.Text = sensor.ElevationAngle.ToString[];

                // Các sự kiện thông báo dữ liệu đã sẵn sàng.

                this.sensor.ColorFrameReady += this.SensorColorFrameReady;

                this.sensor.DepthFrameReady += this.SensorDepthFrameReady;

            }

        }

        // Xử lý các sự kiện.

         private voidSensorColorFrameReady[object sender,                                             

                                             ColorImageFrameReadyEventArgs e]

          {

            using [ColorImageFramecolorFrame = e.OpenColorImageFrame[]]

            {

              if [colorFrame != null]

              {

                  colorImage.Image = colorFrame.ToBitmap[];

              }

            } 

          }

         private voidSensorDepthFrameReady[object sender,

                                              DepthImageFrameReadyEventArgs e]

         {

             using [DepthImageFramedepthFrame = e.OpenDepthImageFrame[]]

             {

                 if [depthFrame != null]

                 {

                     depthImage.Image= depthFrame.ToBitmap[];

                 }

             }

         }

        private voidForm1_FormClosing[object sender, FormClosingEventArgs e]

        {

            if [sensor != null]

            {

// Đưa góc nghiêng về 0 trước khi tắt sensor.

                sensor.ElevationAngle = 0;

                sensor.Stop[];

            }

        }

        // Các hàm xử lý sự kiện để điều chỉnh góc nghiêng.

        private voidhScr_dieuChinhGoc_ValueChanged[object sender, EventArgs e]

        {

            lbl_gocnghieng.Text = hScr_dieuChinhGoc.Value.ToString[];

        }

        private voidbutton1_Click[object sender, EventArgs e]

        {

            sensor.ElevationAngle = hScr_dieuChinhGoc.Value;

        }

    }

}

vKết quả:

Trên đây là những tìm hiểu mang tính chất tổng hợp kiến thức, tuy rằng vẫn đang còn sơ lược nhưng có thể sẽ hữu ích với những bạn mới bắt đầu tiếp cận với Kinect.

Chủ Đề