1、新建項目,選擇C#中的“windows窗體應用程序”。
2、添加引用:
第一個引用:在.net選項中選擇Microsoft.Kinect
第二個引用:在瀏覽選項中找到EMGU的Emgu\emgucv-windows-x86 2.4.0.1717\bin,添加Emgu.CV.dll、Emgu.CV.UI.dll、Emgu.Util.dll
第三個引用:在Microsoft SDKs的Microsoft SDKs\Kinect\Developer Toolkit v1.8.0\bin下的Microsoft.Speech.dll
3、然後就像平常編程一樣了。
4、基本例程
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 System.Drawing.Imaging;
using System.Runtime.InteropServices;
using Microsoft.Kinect;
using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.Util;
using Microsoft.Speech.AudioFormat;
using Microsoft.Speech.Recognition;
using LightBuzz.Vitruvius;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
//啓用的Kinect設備
private KinectSensor sensor;
//數據緩衝存儲空間
ColorImageFormat colorImageFormat;
DepthImageFormat depthImageFormat;
private byte[] colorPixels;
private DepthImagePixel[] depthPixels;
private byte[] depthPixels4Channels;
private Skeleton[] skeletonData;
//顯示圖像中間結構 Kinect -> Bitmap -> Emgu CV
private Bitmap colBitmap;
private Bitmap depBitmap;
int depthWidth, depthHeight;
int colorWidth, colorHeight;
private Image colorImage;
private Image depthImage;
//EmguCV 繪製字符串時候使用的字體
private MCvFont font = new MCvFont(Emgu.CV.CvEnum.FONT.CV_FONT_HERSHEY_COMPLEX, 0.3, 0.3);
//繪製骨骼使用的Image
private Image skeletonImage;
private ColorImagePoint[] colorCoordinates;
//語音識別引擎
private SpeechRecognitionEngine speechEngine;
GestureController _gestureController;
[System.Runtime.InteropServices.DllImport("user32")]
private static extern int mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
//移動鼠標
const int MOUSEEVENT_MOVE = 0x0001;
//模擬鼠標左鍵按下
const int MOUSEEVENT_LEFTDOWN = 0x0002;
//模擬鼠標左鍵擡起
const int MOUSEEVENT_LEFTUP = 0x0004;
//模擬鼠標右鍵按下
const int MOUSEEVENT_RIGHTDOWN = 0x0008;
//模擬鼠標右鍵擡起
const int MOUSEEVENT_RIGHTUP = 0x0010;
//模擬鼠標中鍵按下
const int MOUSEEVENT_MIDDLEDOWN = 0x0020;
//模擬鼠標中鍵擡起
const int MOUSEEVENT_MIDDLEUP = 0x0040;
//標示是否採用絕對座標
const int MOUSEEVENT_ABSOLUTE = 0x8000;
[System.Runtime.InteropServices.DllImport("user32")]
public static extern void keybd_event(
byte bVk, //虛擬鍵值
byte bScan,// 一般爲0
int dwFlags, //這裏是整數類型 0 爲按下,2爲釋放
int dwExtraInfo //這裏是整數類型 一般情況下設成爲 0
);
const int KEY_DOWN = 0;
const int KEY_UP = 2;
public Form1()
{
InitializeComponent();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
//停止設備
if (null != this.sensor)
{
this.sensor.AudioSource.Stop();
this.sensor.Stop();
}
//退出語音識別
if (null != this.speechEngine)
{
this.speechEngine.SpeechRecognized -= SpeechRecognized;
this.speechEngine.SpeechRecognitionRejected -= SpeechRejected;
this.speechEngine.RecognizeAsyncStop();
}
}
private void Form1_Load(object sender, EventArgs e)
{
//枚舉Kinect設備,並將第一個連接成功的設備做爲當前設備
foreach (var potentialSensor in KinectSensor.KinectSensors)
{
if (potentialSensor.Status == KinectStatus.Connected)
{
this.sensor = potentialSensor;
break;
}
}
if (null != this.sensor)
{
//初始化Kinect設置
colorImageFormat = ColorImageFormat.RgbResolution640x480Fps30;
depthImageFormat = DepthImageFormat.Resolution640x480Fps30;
this.sensor.ColorStream.Enable(colorImageFormat);
this.sensor.DepthStream.Enable(depthImageFormat);
this.sensor.SkeletonStream.Enable();
this.colorPixels = new byte[this.sensor.ColorStream.FramePixelDataLength];
this.depthPixels = new DepthImagePixel[this.sensor.DepthStream.FramePixelDataLength];
this.depthPixels4Channels = new byte[this.sensor.DepthStream.FramePixelDataLength * 4];
this.skeletonData = new Skeleton[this.sensor.SkeletonStream.FrameSkeletonArrayLength];
this.colorCoordinates = new ColorImagePoint[this.sensor.DepthStream.FramePixelDataLength];
depthWidth = this.sensor.DepthStream.FrameWidth;
depthHeight = this.sensor.DepthStream.FrameHeight;
colorWidth = this.sensor.ColorStream.FrameWidth;
colorHeight = this.sensor.ColorStream.FrameHeight;
skeletonImage = new Image(depthWidth, depthHeight);
skeletonImage.Draw(new Rectangle(0, 0, depthWidth, depthHeight), new Bgr(0.0, 0.0, 0.0), -1);
imageBox3.Image = skeletonImage;
this.sensor.ColorFrameReady += this.SensorColorFrameReady;
this.sensor.DepthFrameReady += this.SensorDepthFrameReady;
this.sensor.SkeletonFrameReady += this.SensorSkeletonFrameReady;
_gestureController = new GestureController(GestureType.All);
_gestureController.GestureRecognized += GestureController_GestureRecognized;
//啓動設備
try
{
this.sensor.Start();
}
catch (System.IO.IOException)
{
this.sensor = null;
}
}
if (null == this.sensor)
{
MessageBox.Show("Kinect設備未準備好");
}
else
{
this.Text = "Kinect連接成功";
}
//獲取Kinect語音識別引擎
RecognizerInfo ri = GetKinectRecognizer();
if (null != ri)
{
//創建引擎
this.speechEngine = new SpeechRecognitionEngine(ri.Id);
//創建識別語法
var directions = new Choices();
directions.Add(new SemanticResultValue("one", 1));
directions.Add(new SemanticResultValue("two", 2));
directions.Add(new SemanticResultValue("three", 3));
directions.Add(new SemanticResultValue("four", 4));
directions.Add(new SemanticResultValue("five", 5));
var gb = new GrammarBuilder { Culture = ri.Culture };
gb.Append(directions);
var g = new Grammar(gb);
speechEngine.LoadGrammar(g);
//添加識別處理函數
speechEngine.SpeechRecognized += SpeechRecognized;
speechEngine.SpeechRecognitionRejected += SpeechRejected;
//設置語音引擎參數
speechEngine.SetInputToAudioStream(
sensor.AudioSource.Start(),
new SpeechAudioFormatInfo(EncodingFormat.Pcm, 16000, 16, 1, 32000, 2, null));
//啓用識別
speechEngine.RecognizeAsync(RecognizeMode.Multiple);
}
}
void GestureController_GestureRecognized(object sender, GestureEventArgs e)
{
Text = e.Name;
switch (e.Type)
{
case GestureType.JoinedHands:
break;
case GestureType.Menu:
break;
case GestureType.SwipeDown:
break;
case GestureType.SwipeLeft:
{
mouse_event(MOUSEEVENT_MOVE, -10, 0, 0, 0);
}
break;
case GestureType.SwipeRight:
{
mouse_event(MOUSEEVENT_MOVE, 10, 0, 0, 0);
}
break;
case GestureType.SwipeUp:
break;
case GestureType.WaveLeft:
{
keybd_event((byte)Keys.PageDown, 0, KEY_DOWN, 0);
keybd_event((byte)Keys.PageDown, 0, KEY_UP, 0);
}
break;
case GestureType.WaveRight:
{
keybd_event((byte)Keys.PageUp, 0, KEY_DOWN, 0);
keybd_event((byte)Keys.PageUp, 0, KEY_UP, 0);
}
break;
case GestureType.ZoomIn:
break;
case GestureType.ZoomOut:
break;
default:
break;
}
}
//識別處理函數
private void SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
{
const double ConfidenceThreshold = 0.3;
if (e.Result.Confidence >= ConfidenceThreshold)
{
MessageBox.Show(e.Result.Semantics.Value.ToString());
}
}
//識別拒絕函數,基本無意義
private void SpeechRejected(object sender, SpeechRecognitionRejectedEventArgs e)
{
}
//獲取Kinect語音識別引擎
private static RecognizerInfo GetKinectRecognizer()
{
foreach (RecognizerInfo recognizer in SpeechRecognitionEngine.InstalledRecognizers())
{
string value;
recognizer.AdditionalInfo.TryGetValue("Kinect", out value);
if ("True".Equals(value, StringComparison.OrdinalIgnoreCase) &&
"en-US".Equals(recognizer.Culture.Name, StringComparison.OrdinalIgnoreCase))
{
return recognizer;
}
}
return null;
}
//骨骼數據處理事件
private void SensorSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
bool received = false;
using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
{
if (skeletonFrame != null)
{
skeletonFrame.CopySkeletonDataTo(this.skeletonData);
received = true;
}
}
if (received)
{
foreach (Skeleton skeleton in this.skeletonData)
{
if (skeleton.TrackingState == SkeletonTrackingState.Tracked)
{
_gestureController.Update(skeleton);
}
}
//重繪整個畫面,沖掉原有骨骼圖像
skeletonImage.Draw(new Rectangle(0, 0, skeletonImage.Width, skeletonImage.Height), new Bgr(0.0, 0.0, 0.0), -1);
DrawSkeletons(skeletonImage, 0);
imageBox3.Image = skeletonImage;
}
}
private void DrawSkeletons(Image img, int depthOrColor)
{
//繪製所有正確Tracked的骨骼
foreach (Skeleton skeleton in this.skeletonData)
{
if (skeleton.TrackingState == SkeletonTrackingState.Tracked)
{
DrawTrackedSkeletonJoints(img, skeleton.Joints, depthOrColor);
}
}
}
private void DrawTrackedSkeletonJoints(Image img, JointCollection jointCollection, int depthOrColor)
{
// Render Head and Shoulders
DrawBone(img, jointCollection[JointType.Head], jointCollection[JointType.ShoulderCenter], depthOrColor);
DrawBone(img, jointCollection[JointType.ShoulderCenter], jointCollection[JointType.ShoulderLeft], depthOrColor);
DrawBone(img, jointCollection[JointType.ShoulderCenter], jointCollection[JointType.ShoulderRight], depthOrColor);
// Render Left Arm
DrawBone(img, jointCollection[JointType.ShoulderLeft], jointCollection[JointType.ElbowLeft], depthOrColor);
DrawBone(img, jointCollection[JointType.ElbowLeft], jointCollection[JointType.WristLeft], depthOrColor);
DrawBone(img, jointCollection[JointType.WristLeft], jointCollection[JointType.HandLeft], depthOrColor);
// Render Right Arm
DrawBone(img, jointCollection[JointType.ShoulderRight], jointCollection[JointType.ElbowRight], depthOrColor);
DrawBone(img, jointCollection[JointType.ElbowRight], jointCollection[JointType.WristRight], depthOrColor);
DrawBone(img, jointCollection[JointType.WristRight], jointCollection[JointType.HandRight], depthOrColor);
// Render other bones...
DrawBone(img, jointCollection[JointType.ShoulderCenter], jointCollection[JointType.Spine], depthOrColor);
DrawBone(img, jointCollection[JointType.Spine], jointCollection[JointType.HipRight], depthOrColor);
DrawBone(img, jointCollection[JointType.KneeRight], jointCollection[JointType.HipRight], depthOrColor);
DrawBone(img, jointCollection[JointType.KneeRight], jointCollection[JointType.AnkleRight], depthOrColor);
DrawBone(img, jointCollection[JointType.FootRight], jointCollection[JointType.AnkleRight], depthOrColor);
DrawBone(img, jointCollection[JointType.Spine], jointCollection[JointType.HipLeft], depthOrColor);
DrawBone(img, jointCollection[JointType.KneeLeft], jointCollection[JointType.HipLeft], depthOrColor);
DrawBone(img, jointCollection[JointType.KneeLeft], jointCollection[JointType.AnkleLeft], depthOrColor);
DrawBone(img, jointCollection[JointType.FootLeft], jointCollection[JointType.AnkleLeft], depthOrColor);
}
private void DrawBone(Image img, Joint jointFrom, Joint jointTo, int depthOrColor)
{
if (jointFrom.TrackingState == JointTrackingState.NotTracked ||
jointTo.TrackingState == JointTrackingState.NotTracked)
{
return; // nothing to draw, one of the joints is not tracked
}
if (jointFrom.TrackingState == JointTrackingState.Inferred ||
jointTo.TrackingState == JointTrackingState.Inferred)
{
DrawBoneLine(img, jointFrom.Position, jointTo.Position, 1, depthOrColor);
}
if (jointFrom.TrackingState == JointTrackingState.Tracked &&
jointTo.TrackingState == JointTrackingState.Tracked)
{
DrawBoneLine(img, jointFrom.Position, jointTo.Position, 3, depthOrColor);
}
}
private Point SkeletonPointToDepthScreen(SkeletonPoint skelpoint)
{
DepthImagePoint depthPoint = this.sensor.CoordinateMapper.MapSkeletonPointToDepthPoint(skelpoint, depthImageFormat);
return new Point(depthPoint.X, depthPoint.Y);
}
private Point SkeletonPointToColorScreen(SkeletonPoint skelpoint)
{
ColorImagePoint colorPoint = this.sensor.CoordinateMapper.MapSkeletonPointToColorPoint(skelpoint, colorImageFormat);
return new Point(colorPoint.X, colorPoint.Y);
}
private void DrawBoneLine(Image img, SkeletonPoint p1, SkeletonPoint p2, int lineWidth, int depthOrColor)
{
Point p_1, p_2;
if (depthOrColor == 0)
{
p_1 = SkeletonPointToDepthScreen(p1);
p_2 = SkeletonPointToDepthScreen(p2);
}
else
{
p_1 = SkeletonPointToColorScreen(p1);
p_2 = SkeletonPointToColorScreen(p2);
}
img.Draw(new LineSegment2D(p_1, p_2), new Bgr(255, 255, 0), lineWidth);
img.Draw(new CircleF(p_1, 5), new Bgr(0, 0, 255), -1);
StringBuilder str = new StringBuilder();
str.AppendFormat("({0},{1},{2})", p1.X.ToString("0.0"), p1.Y.ToString("0.0"), p1.Z.ToString("0.0"));
img.Draw(str.ToString(), ref font, p_1, new Bgr(0, 255, 0));
img.Draw(new CircleF(p_2, 5), new Bgr(0, 0, 255), -1);
str.Clear();
str.AppendFormat("({0},{1},{2})", p2.X.ToString("0.0"), p2.Y.ToString("0.0"), p2.Z.ToString("0.0"));
img.Draw(str.ToString(), ref font, p_2, new Bgr(0, 255, 0));
}
private void SensorColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
{
bool received = false;
using (ColorImageFrame colorFrame = e.OpenColorImageFrame())
{
if (colorFrame != null)
{
//緩存數據
colorFrame.CopyPixelDataTo(this.colorPixels);
received = true;
}
}
if (received)
{
//將byte數組轉爲Bitmap
colBitmap = new Bitmap(colorWidth, colorHeight);
BitmapData colImageBitmapData = colBitmap.LockBits(new Rectangle(0, 0, colBitmap.Width, colBitmap.Height),
ImageLockMode.WriteOnly,
colBitmap.PixelFormat);
IntPtr IptrColImage = colImageBitmapData.Scan0;
Marshal.Copy(colorPixels, 0, IptrColImage, colorPixels.Length);
colBitmap.UnlockBits(colImageBitmapData);
//顯示Bitmap
UpdateColImage(colBitmap);
}
}
private void SensorDepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
{
bool received = false;
int minDepth = 1000;
int maxDepth = 0;
using (DepthImageFrame depthFrame = e.OpenDepthImageFrame())
{
if (depthFrame != null)
{
//獲取有效深度範圍
minDepth = depthFrame.MinDepth;
maxDepth = depthFrame.MaxDepth;
//緩存深度數據
depthFrame.CopyDepthImagePixelDataTo(this.depthPixels);
received = true;
}
}
if (received)
{
this.sensor.CoordinateMapper.MapDepthFrameToColorFrame(
depthImageFormat,
this.depthPixels,
colorImageFormat,
this.colorCoordinates);
//將深度數據轉爲Bitmap
depBitmap = new Bitmap(depthWidth, depthHeight);
BitmapData depImageBitmapData = depBitmap.LockBits(new Rectangle(0, 0, depBitmap.Width, depBitmap.Height),
ImageLockMode.WriteOnly,
depBitmap.PixelFormat);
IntPtr IptrDepImage = depImageBitmapData.Scan0;
for (int y = 0; y < this.depthHeight; ++y)
{
for (int x = 0; x < this.depthWidth; ++x)
{
int i = x + (y * this.depthWidth);
int player = depthPixels[i].PlayerIndex;
short depth = depthPixels[i].Depth;
byte intensity = (byte)((1.0f * (depth - minDepth) / (maxDepth - minDepth)) * 255f);
if (depth < minDepth) intensity = 0;
if (depth > maxDepth) intensity = 255;
if (player > 0)
{
int j = x + (y * this.colorWidth);
if (cbBody.Checked)
{
this.depthPixels4Channels[i * 4 + 0] = this.colorPixels[j * 4 + 0];
this.depthPixels4Channels[i * 4 + 1] = this.colorPixels[j * 4 + 1];
this.depthPixels4Channels[i * 4 + 2] = this.colorPixels[j * 4 + 2];
}
else
{
this.depthPixels4Channels[i * 4 + 0] = intensity;
this.depthPixels4Channels[i * 4 + 1] = 255;
this.depthPixels4Channels[i * 4 + 2] = intensity;
}
}
else
{
if (depth > minDepth && depth < minDepth + 1000)
{
this.depthPixels4Channels[i * 4 + 0] = 255;
this.depthPixels4Channels[i * 4 + 1] = intensity;
this.depthPixels4Channels[i * 4 + 2] = intensity;
}
else
{
this.depthPixels4Channels[i * 4 + 0] = intensity;
this.depthPixels4Channels[i * 4 + 1] = intensity;
this.depthPixels4Channels[i * 4 + 2] = intensity;
}
}
this.depthPixels4Channels[i * 4 + 3] = 255;
}
}
Marshal.Copy(depthPixels4Channels, 0, IptrDepImage, depthPixels4Channels.Length);
depBitmap.UnlockBits(depImageBitmapData);
//顯示深度
UpdateDepImage(depBitmap);
}
}
private void UpdateColImage(Bitmap bmp)
{
try
{
colorImage = new Image(bmp);
if (skeletonData != null)
{
DrawSkeletons(colorImage, 1);
}
imageBox1.Image = colorImage;
}
catch { }
}
private void UpdateDepImage(Bitmap bmp)
{
try
{
depthImage = new Image(bmp);
if (this.skeletonData != null)
DrawSkeletons(depthImage, 0);
imageBox2.Image = depthImage;
}
catch { }
}
private void cbNearMode_CheckedChanged(object sender, EventArgs e)
{
//近模式和默認模式切換
if (this.sensor != null)
{
try
{
if (this.cbNearMode.Checked)
{
this.sensor.DepthStream.Range = DepthRange.Near;
}
else
{
this.sensor.DepthStream.Range = DepthRange.Default;
}
}
catch (InvalidOperationException)
{
}
}
}
private void cbSeat_CheckedChanged(object sender, EventArgs e)
{
//坐姿和默認模式切換
if (this.sensor != null)
{
try
{
if (this.cbSeat.Checked)
{
this.sensor.SkeletonStream.TrackingMode = SkeletonTrackingMode.Seated;
}
else
{
this.sensor.SkeletonStream.TrackingMode = SkeletonTrackingMode.Default;
}
}
catch (InvalidOperationException)
{
}
}
}
}
}