Chủ Nhật, 2 tháng 12, 2012

Kinect và ứng dụng trong mobile robot (Phần 2)


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!
      }

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.dll hoặ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)
-         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(object sender,                                         
                                     ColorImageFrameReadyEventArgs e)
          {
            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à 640x480 (mặc định), 320x240 vào 80x60. 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,                                         
                                     ColorImageFrameReadyEventArgs e)
          {
            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 void hScr_dieuChinhGoc_ValueChanged(object sender, EventArgs e)
        {
            lbl_gocnghieng.Text = hScr_dieuChinhGoc.Value.ToString();
        }

        private void button1_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.
v Code
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 KinectSensor sensor;// Khai báo sensor
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {  
            //Kiểm tra các sensor được kết nối
            foreach(var sensorKetnoi 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 void SensorColorFrameReady(object sender,                                             
                                             ColorImageFrameReadyEventArgs e)
          {
            using (ColorImageFrame colorFrame = e.OpenColorImageFrame())
            {
              if (colorFrame != null)
              {
                  colorImage.Image = colorFrame.ToBitmap();
             
              }
            } 
          }
         private void SensorDepthFrameReady(object sender,
                                              DepthImageFrameReadyEventArgs e)
         {
             using (DepthImageFrame depthFrame = e.OpenDepthImageFrame())
             {
                 if (depthFrame != null)
                 {
                     depthImage.Image= depthFrame.ToBitmap();
                 }
                
             }
         }

        private void Form1_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 void hScr_dieuChinhGoc_ValueChanged(object sender, EventArgs e)
        {
            lbl_gocnghieng.Text = hScr_dieuChinhGoc.Value.ToString();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            sensor.ElevationAngle = hScr_dieuChinhGoc.Value;
        }
                    
    }
}

v Kế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.

6 nhận xét:

  1. Bài hay quá anh ơi.Nhưng em muốn lấy dữ liệu khoảng cách từ vật cản đến cảm biến thì làm như thế nào vậy anh.Thank you a trc!!!

    Trả lờiXóa
  2. Anh ơi.a còn làm về Kinect k vậy.Cho e hỏi chút đc k ?
    Bây giờ e làm 1 con robot dò đg tránh vật cản đến 1 đích nào đó sử dụng kinect.
    Thì cái hàm xử lý tín hiệu bên kinect e cần làm những gì vậy.
    Và e dùng thư viện kinectSDK thì có phải dùng cả thư viện Point Cloud nữa không a?
    Thank you a trc!!!

    Trả lờiXóa
    Trả lời
    1. Bộ Kinect SDK thì chỉ dùng trên Visual Studio thôi, muốn sử dụng PCL thì bạn cần dùng OpenNI nhé.
      Ngày xưa mình nghịch cả 2 nhưng để xử lý 3D cho phần tránh vật cản thì phải chuyển qua PCL.

      Xóa
    2. Vậy sao a.Thế thì chắc e toi rồi.Em cứ đâm đầu vào Kinect SDK cho robot.Sắp hết hạn rồi mà h chuyển sang PCL thì không kịp nữa.

      Xóa
    3. A còn code xử lý 3D cho phần tránh vật cản không.Share cho e với.Mail e đây a ak: vodanhhihi@gmail.com

      Xóa
    4. Em xin cảm ơn a nhé!!!

      Xóa