Kinect for windows的脸部识别

简介:

Kinect for windows提供了脸部识别的功能,可以识出人脸。主要是通过FaceTrackFrame类的GetTriangles()来得到一个三角形数组,这个三角形数组就是给成人面部的基本形状,并且组成的效果是立体的(可以这样理解,可以把3D都拆成三角形来表示,看上去像3D,但其实是2D),这个数组的每个元素都存放着三个整数,分别代码三角形的第一个点,第二个点和第三个点。FaceTrackFrameGetProjected3DShape方法,可以获取一组坐标信息,这样就可以结合三角形数组元素中的点作为索引,从本方法的坐标集合中取出每个三角形的坐标点来了,就可以绘制这些三角形,就可以组成一个人脸的网络3D效果图了。

本例是从色彩摄像头中获取彩色数据流,并显示到窗体上,再通过FaceTracker得到得到脸部3D信息,并用GDI+的方式把网络图形画到窗体上,这时就可以在真实图像上看到浮着一张网络的面套。同时可以得出脸部交汇最多的坐标,并用GDI+添加上不同有色彩,同时还可以得到人体面部和Kinect 正面的偏差,即人头是否竖直,有没有偏上一边等角度信息。

结果图像如下图:

 新建一个WinForm项目,在窗体上添加一人ListBox,更改NameMessbox_LB。后台代码如下:

 

 
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.ComponentModel;  
  4. using System.Data;  
  5. using System.Drawing;  
  6. using System.Linq;  
  7. using System.Text;  
  8. using System.Threading.Tasks;  
  9. using System.Windows.Forms;  
  10.  
  11. using Microsoft.Kinect;  
  12. using Microsoft.Kinect.Toolkit;  
  13. using Microsoft.Kinect.Toolkit.FaceTracking;  
  14. using System.Threading;  
  15. using System.IO;  
  16. using System.Drawing.Imaging;  
  17.  
  18.  
  19. namespace Face  
  20. {  
  21.     public partial class Form1 : Form  
  22.     {  
  23.         public Form1()  
  24.         {  
  25.             InitializeComponent();  
  26.         }  
  27.  
  28.         KinectSensor ks = null;  
  29.         private void Form1_Load(object sender, EventArgs e)  
  30.         {  
  31.             //让winform窗体刷新不闪动  
  32.             this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);  
  33.             this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);  
  34.             this.SetStyle(ControlStyles.UserPaint, true);  
  35.             this.SetStyle(ControlStyles.DoubleBuffer, true);  
  36.             //找到连接的Kinect设备  
  37.             foreach (var ks in KinectSensor.KinectSensors)  
  38.             {  
  39.                 if (ks.Status == KinectStatus.Connected)  
  40.                 {  
  41.                     this.ks = ks;  
  42.                 }  
  43.             }  
  44.             //开启色彩流,深度流,骨骼流的跟踪  
  45.             if (this.ks != null)  
  46.             {  
  47.                 this.ks.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);  
  48.                 this.ks.DepthStream.Enable(DepthImageFormat.Resolution320x240Fps30);  
  49.                 this.ks.DepthStream.Range = DepthRange.Near;  
  50.                 this.ks.SkeletonStream.EnableTrackingInNearRange = true;  
  51.                 this.ks.SkeletonStream.TrackingMode = SkeletonTrackingMode.Seated;  
  52.                 this.ks.SkeletonStream.Enable();  
  53.                 //订阅跟踪数据读取事件  
  54.                 this.ks.AllFramesReady += OnAllFramesReady;  
  55.                 ks.Start();  
  56.             }  
  57.         }  
  58.  
  59.         //这个方法很重要,就是重绘人脸跟踪采集到的数据  
  60.         protected override void OnPaint(PaintEventArgs e)  
  61.         {  
  62.             base.OnPaint(e);  
  63.             foreach (SkeletonFaceTracker faceInformation in this.trackedSkeletons.Values)  
  64.             {  
  65.                 //第一个参数为当前窗体为画布,第二个是添加采集到的信息到listbox中,这个方法画识别到脸部的信息  
  66.                 faceInformation.DrawFaceModel(e.Graphics, Messbox_LB);  
  67.             }  
  68.         }  
  69.  
  70.         //定义脸部识别的集合  
  71.         private readonly Dictionary<int, SkeletonFaceTracker> trackedSkeletons = new Dictionary<int, SkeletonFaceTracker>();  
  72.         //色彩流字节数组  
  73.         private byte[] colorImage;  
  74.         private ColorImageFormat colorImageFormat = ColorImageFormat.Undefined;  
  75.         //深度流字节数组  
  76.         private short[] depthImage;  
  77.         private DepthImageFormat depthImageFormat = DepthImageFormat.Undefined;  
  78.         //骨骼信息数组  
  79.         private Skeleton[] skeletonData;  
  80.  
  81.  
  82.         private void OnAllFramesReady(object sender, AllFramesReadyEventArgs allFramesReadyEventArgs)  
  83.         {  
  84.             ColorImageFrame colorImageFrame = null;  
  85.             DepthImageFrame depthImageFrame = null;  
  86.             SkeletonFrame skeletonFrame = null;  
  87.             try 
  88.             {  
  89.                 colorImageFrame = allFramesReadyEventArgs.OpenColorImageFrame();     //接到色彩流对框架  
  90.                 depthImageFrame = allFramesReadyEventArgs.OpenDepthImageFrame();     //接到深度流对框架  
  91.                 skeletonFrame = allFramesReadyEventArgs.OpenSkeletonFrame();     //接到骨骼流对框架  
  92.  
  93.                 if (colorImageFrame == null || depthImageFrame == null || skeletonFrame == null)  
  94.                 {  
  95.                     return;  
  96.                 }  
  97.                   
  98.                 if (this.depthImageFormat != depthImageFrame.Format)  
  99.                 {  
  100.                     this.ResetFaceTracking();  
  101.                     this.depthImage = null;  
  102.                     this.depthImageFormat = depthImageFrame.Format;  
  103.                 }  
  104.  
  105.                 if (this.colorImageFormat != colorImageFrame.Format)  
  106.                 {  
  107.                     this.ResetFaceTracking();  
  108.                     this.colorImage = null;  
  109.                     this.colorImageFormat = colorImageFrame.Format;  
  110.                 }  
  111.                 if (this.depthImage == null)  
  112.                 {  
  113.                     this.depthImage = new short[depthImageFrame.PixelDataLength];  
  114.                 }  
  115.  
  116.                 if (this.colorImage == null)  
  117.                 {  
  118.                     this.colorImage = new byte[colorImageFrame.PixelDataLength];  
  119.                 }  
  120.  
  121.                 if (this.skeletonData == null || this.skeletonData.Length != skeletonFrame.SkeletonArrayLength)  
  122.                 {  
  123.                     this.skeletonData = new Skeleton[skeletonFrame.SkeletonArrayLength];  
  124.                 }  
  125.                 //获取各种数据流信息  
  126.                 colorImageFrame.CopyPixelDataTo(this.colorImage);  
  127.                 depthImageFrame.CopyPixelDataTo(this.depthImage);  
  128.                 skeletonFrame.CopySkeletonDataTo(this.skeletonData);  
  129.                 //清空列表信息  
  130.                 Messbox_LB.Items.Clear();  
  131.                 //编历骨骼流  
  132.                 foreach (Skeleton skeleton in this.skeletonData)  
  133.                 {  
  134.                     //找到有效的骨骼信息  
  135.                     if (skeleton.TrackingState == SkeletonTrackingState.Tracked  
  136.                         || skeleton.TrackingState == SkeletonTrackingState.PositionOnly)  
  137.                     {  
  138.                         if (!this.trackedSkeletons.ContainsKey(skeleton.TrackingId))  
  139.                         {  
  140.                             //添加骨骼信息到集合中  
  141.                             this.trackedSkeletons.Add(skeleton.TrackingId, new SkeletonFaceTracker());  
  142.                         }  
  143.                         // 得到脸部识别对象  
  144.                         SkeletonFaceTracker skeletonFaceTracker;  
  145.                         if (this.trackedSkeletons.TryGetValue(skeleton.TrackingId, out skeletonFaceTracker))  
  146.                         {  
  147.                             //把获取的数据流的相关信息传给OnFrameReady方法  
  148.                             skeletonFaceTracker.OnFrameReady(Messbox_LB, this.ks, colorImageFormat, colorImage, depthImageFormat, depthImage, skeleton);  
  149.                             skeletonFaceTracker.LastTrackedFrame = skeletonFrame.FrameNumber;  
  150.                         }  
  151.                     }  
  152.                 }  
  153.                 //这个刷新会触发窗体的重画,OnPaint方法会被调用。  
  154.                 this.Refresh();  
  155.                 //把色彩流转转成位图显示成窗体的背景  
  156.                 this.BackgroundImage = ToGrayBitmap(colorImage, 640, 480);  
  157.  
  158.             }  
  159.             finally 
  160.             {  
  161.                 if (colorImageFrame != null)  
  162.                 {  
  163.                     colorImageFrame.Dispose();  
  164.                 }  
  165.                 if (depthImageFrame != null)  
  166.                 {  
  167.                     depthImageFrame.Dispose();  
  168.                 }  
  169.                 if (skeletonFrame != null)  
  170.                 {  
  171.                     skeletonFrame.Dispose();  
  172.                 }  
  173.             }  
  174.         }  
  175.         //把色采流数据转成位图返回  
  176.         public static Bitmap ToGrayBitmap(byte[] rawValues, int width, int height)  
  177.         {  
  178.             //定议转换图片的格式,一个像素占32个,前24位为红绿蓝,后8位为空  
  179.             PixelFormat pf = PixelFormat.Format32bppRgb;  
  180.             //申请目标位图的变量  
  181.             Bitmap bmp = new Bitmap(width, height, pf);  
  182.             //将其内存区域锁定   
  183.             BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, pf);  
  184.             //获取位图的起始地址  
  185.             IntPtr iptr = bmpData.Scan0;  
  186.             //用Marshal的Copy方法,将色彩流字节数组复制到BitmapData中   
  187.             System.Runtime.InteropServices.Marshal.Copy(rawValues, 0, iptr, rawValues.Length);  
  188.             //释放锁  
  189.             bmp.UnlockBits(bmpData);  
  190.             return bmp;  
  191.         }  
  192.         //重新设置识别对象  
  193.         private void ResetFaceTracking()  
  194.         {  
  195.             foreach (int trackingId in new List<int>(this.trackedSkeletons.Keys))  
  196.             {  
  197.                 this.RemoveTracker(trackingId);  
  198.             }  
  199.         }  
  200.         //从集合中移动识别信息  
  201.         private void RemoveTracker(int trackingId)  
  202.         {  
  203.             this.trackedSkeletons[trackingId].Dispose();  
  204.             this.trackedSkeletons.Remove(trackingId);  
  205.         }  
  206.  
  207.         private void Form1_FormClosing(object sender, FormClosingEventArgs e)  
  208.         {  
  209.             if (this.ks.Status == KinectStatus.Connected)  
  210.             {  
  211.                 ks.Stop();  
  212.             }  
  213.         }  
  214.         //定义脸识别类  
  215.         class SkeletonFaceTracker : IDisposable  
  216.         {  
  217.             //定义脸部识别形状三角形数组  
  218.             private static FaceTriangle[] faceTriangles;  
  219.             //脸部识别坐标点集合  
  220.             private EnumIndexableCollection<FeaturePoint, Microsoft.Kinect.Toolkit.FaceTracking.PointF> facePoints;  
  221.             //脸部跟踪类  
  222.             private FaceTracker faceTracker;  
  223.             //定义识别成功标识  
  224.             private bool lastFaceTrackSucceeded;  
  225.             //骨骼跟踪状态  
  226.             private SkeletonTrackingState skeletonTrackingState;  
  227.  
  228.             public int LastTrackedFrame { getset; }  
  229.  
  230.             public void Dispose()  
  231.             {  
  232.                 if (this.faceTracker != null)  
  233.                 {  
  234.                     this.faceTracker.Dispose();  
  235.                     this.faceTracker = null;  
  236.                 }  
  237.             }  
  238.             //用来把识别的信息绘制出来  
  239.             public void DrawFaceModel(Graphics graphics, ListBox lb)  
  240.             {  
  241.                 if (!this.lastFaceTrackSucceeded || this.skeletonTrackingState != SkeletonTrackingState.Tracked)  
  242.                 {  
  243.                     return;  
  244.                 }  
  245.  
  246.                 List<System.Drawing.PointF> faceModelPts = new List<System.Drawing.PointF>();  
  247.  
  248.                 for (int i = 0; i < this.facePoints.Count; i++)  
  249.                 {  
  250.                     faceModelPts.Add(new System.Drawing.PointF(this.facePoints[i].X + 0.5f, this.facePoints[i].Y + 0.5f));  
  251.                 }  
  252.                 System.Drawing.Pen pen = new System.Drawing.Pen(System.Drawing.Color.Green);  
  253.  
  254.                 List<System.Drawing.PointF> list = new List<System.Drawing.PointF>();  
  255.                 //遍历所有的三角形,分别画三角形  
  256.                 for (int i = 0; i < faceTriangles.Count(); i++)  
  257.                 {  
  258.                     System.Drawing.PointF[] pointFarr = new System.Drawing.PointF[4];  
  259.                     pointFarr[0] = faceModelPts[faceTriangles[i].First];  
  260.                     pointFarr[1] = faceModelPts[faceTriangles[i].Second];  
  261.                     pointFarr[2] = faceModelPts[faceTriangles[i].Third];  
  262.                     pointFarr[3] = faceModelPts[faceTriangles[i].First];  
  263.                     list.AddRange(pointFarr.Take(3));  
  264.                     graphics.DrawLines(pen, pointFarr);  
  265.                 }  
  266.  
  267.                 lb.Items.Add(list.GroupBy(f => f).Count() + "点");  
  268.                 int count = list.GroupBy(f => f).Max(s => s.Count());  
  269.                 lb.Items.Add(count);  
  270.                 foreach (var v in list.GroupBy(f => f).Where(s => s.Count() == 10))  
  271.                 {  
  272.                     lb.Items.Add(v.Key + " " + 10);  
  273.                     graphics.FillEllipse(new SolidBrush(System.Drawing.Color.Red), v.Key.X, v.Key.Y, 5, 5);  
  274.                 }  
  275.                 foreach (var v in list.GroupBy(f => f).Where(s => s.Count() == 9))  
  276.                 {  
  277.                     lb.Items.Add(v.Key + " " + 9);  
  278.                     graphics.FillEllipse(new SolidBrush(System.Drawing.Color.Blue), v.Key.X, v.Key.Y, 5, 5);  
  279.                 }  
  280.                 foreach (var v in list.GroupBy(f => f).Where(s => s.Count() == 8))  
  281.                 {  
  282.                     lb.Items.Add(v.Key + " " + 8);  
  283.                     graphics.FillEllipse(new SolidBrush(System.Drawing.Color.Black), v.Key.X, v.Key.Y, 5, 5);  
  284.                 }  
  285.  
  286.             }  
  287.  
  288.  
  289.             /// <summary>  
  290.             /// 数据更新的方法  
  291.             /// </summary>  
  292.             internal void OnFrameReady(ListBox lb, KinectSensor kinectSensor, ColorImageFormat colorImageFormat, byte[] colorImage, DepthImageFormat depthImageFormat, short[] depthImage, Skeleton skeletonOfInterest)  
  293.             {  
  294.                 this.skeletonTrackingState = skeletonOfInterest.TrackingState;  
  295.                 //判断是否为跟踪状态  
  296.                 if (this.skeletonTrackingState != SkeletonTrackingState.Tracked)  
  297.                 {  
  298.                     return;  
  299.                 }  
  300.                 if (this.faceTracker == null)  
  301.                 {  
  302.                     try 
  303.                     {  
  304.                         //从KinectSensor中实例化出一个脸部识别对象  
  305.                         this.faceTracker = new FaceTracker(kinectSensor);  
  306.                     }  
  307.                     catch (InvalidOperationException)  
  308.                     {  
  309.                         this.faceTracker = null;  
  310.                     }  
  311.                 }  
  312.  
  313.                 if (this.faceTracker != null)  
  314.                 {  
  315.                     //从脸部识别对象中得到脸识别框架  
  316.                     FaceTrackFrame frame = this.faceTracker.Track(  
  317.                         colorImageFormat, colorImage, depthImageFormat, depthImage, skeletonOfInterest);  
  318.                     //标识识别成功  
  319.                     this.lastFaceTrackSucceeded = frame.TrackSuccessful;  
  320.                     if (this.lastFaceTrackSucceeded)  
  321.                     {  
  322.                         if (faceTriangles == null)  
  323.                         {  
  324.                             //得到脸部识别三角形数组  
  325.                             faceTriangles = frame.GetTriangles();  
  326.                              
  327.                         }  
  328.                         //得到脸部识别点的坐标  
  329.                         this.facePoints = frame.GetProjected3DShape();  
  330.  
  331.                         //加载脸部的空间位置  
  332.  
  333.                         lb.Items.Add("Rotation   仰低头:" + frame.Rotation.X);  
  334.                         lb.Items.Add("Rotation   左右转头:" + frame.Rotation.Y);  
  335.                         lb.Items.Add("Rotation   左右偏头:" + frame.Rotation.Z);  
  336.                     }  
  337.                 }  
  338.             }  
  339.              
  340.             }  
  341.         }  
  342.     }  

 同时项目中需要引入下面文件中的dll。

http://down.51cto.com/data/774502

 













本文转自桂素伟51CTO博客,原文链接:http://blog.51cto.com/axzxs/1191261 ,如需转载请自行联系原作者


相关实践学习
部署高可用架构
本场景主要介绍如何使用云服务器ECS、负载均衡SLB、云数据库RDS和数据传输服务产品来部署多可用区高可用架构。
负载均衡入门与产品使用指南
负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。 本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法。
相关文章
|
传感器 UED Windows
|
语音技术 Windows 数据格式
|
1月前
|
安全 数据安全/隐私保护 Windows
解锁安全之门,Windows Server 2019密码修改攻略大揭秘
解锁安全之门,Windows Server 2019密码修改攻略大揭秘