在前面一篇文章中,我們使用Emgu來識別人的臉部,當時的Kinect SDK版本是1.0,五月份發布1.5版本的SDK之後,我們就能夠直接使用Kinect實現人臉識別,而不需要借助第三方類庫。
SDK1.5中新增了人臉識別類庫:Microsoft.Kinect.Toolkit.FaceTracking使得在Kinect中進行人臉識別變得簡單,該類庫的源代碼也在Developer Toolkit中。在Developer Toolkit中也自帶人臉識別的例子,您也可以打開運行或者查看源代碼。
本文使用一個簡單的例子來演示如何使用Kinect中的面部追蹤功能。本例子實現的簡單功能是使用WPF來繪制一個簡單的人臉圖,然後使用面部追蹤來讓這個圖動起來,這裡面只使用了Kinect中獲取面部的一些簡單的信息,用來演示如何使用Kinect來進行面部追蹤,所以您如果想要實現人臉的三維展現,或者繪制臉部三角形面的話,您可以參考Developer Toolkit中的自帶例子。
一、開發前准備
要使用面部追蹤功能,Kinect SDK版本應該至少是1.5,最新版本為1.6,您可以參考之前的那篇文章下載安裝,Kinect SDK 和 Kinect Developer Toolkit要一起安裝,我的機器上裝的是最新的SDK1.6版本。
安裝Kinect Developer Toolkit會安裝Kinect Studio、一些C#/VB.Net/C++的應用程序示例、源碼以及兩個用於面部追蹤的類庫FaceTrackData.dll ,FaceTrackLib.dll包括32位和64位版本,安裝好了之後,這些dll應該都在該目錄下面 :
如果用C++開發的話,可以直接在項目中使用著兩個dll,否則,如果使用.NET開發的話,還需要將這些dll包裝成托管代碼。
幸運的是, Developer Toolkit中提供了兩個使用.NET來實現面部追蹤的代碼,我們可以直接使用其替我們包裝好了dll,該類庫的源碼也可以看到。 打開Developer Toolkit Browser 找到Component示例,然後安裝,之後浏覽所在目錄,應該能夠找到下面兩個dll,不安裝也可以,您也可以直接到SDK目錄中查找這兩個dll,在我的及其上目錄為C:\Program Files\Microsoft SDKs\Kinect\Developer Toolkit v1.6.0\Samples\bin:
Microsoft.Kinect.Toolkit
Microsoft.Kinect.Toolkit.FaceTracking
這兩個dll的源碼可以在示例中找到,引用了這兩個dll之後,還需要將FaceTrackData.dll和FaceTrackLib.dll拷貝到項目中,並保證他和exe在同一個目錄下面。
二、創建WPF項目
新建一個名為KinectFaceTracking的WPF項目,然後引用Microsoft.Kinect ,Microsoft.Kinect.Toolkit.FaceTracking 和Microsoft.Kinect.Toolkit這三個dll。
2.1 初始化KinectSensor和FaceTracker
要使用面部追蹤,在開啟KinectSensor之後需要啟用ColorImageStream, DepthImageStream 和SkeletonStream這三個Stream,部分代碼如下:
//啟用必要的三個Stream kinectSensor.ColorStream.Enable(); kinectSensor.DepthStream.Enable(DepthImageFormat.Resolution80x60Fps30); kinectSensor.SkeletonStream.TrackingMode = SkeletonTrackingMode.Seated; kinectSensor.SkeletonStream.Enable(new TransformSmoothParameters() { Correction = 0.5f, JitterRadius = 0.05f, MaxDeviationRadius = 0.05f, Prediction = 0.5f, Smoothing = 0.5f }); // 監聽流事件. kinectSensor.AllFramesReady +=kinectSensor_AllFramesReady; // 初始化數據 colorPixelData = new byte[kinectSensor.ColorStream.FramePixelDataLength]; depthPixelData = new short[kinectSensor.DepthStream.FramePixelDataLength]; skeletonData = new Skeleton[6]; //打開Kinect kinectSensor.Start(); //初始化人臉識別 faceTracker = new FaceTracker(kinectSensor);
前面的代碼應該都好懂,值得一提的是最後一句,初始化FaceTracker 對象。在初始化景深數據流時,我們使用最低分辨率的景深影像數據流,這樣fps會更高,使得結果更加流暢. 最後,我們注冊了AllFramesReady事件。
void kinectSensor_AllFramesReady(objectsender, AllFramesReadyEventArgse) { // 面部追蹤邏輯…… }
2.2獲取臉部數據幀
在Developer Toolkit中,臉部數據幀使用FaceTrackFrame表示。 為了獲取數據,我們需要調用FaceTracker對象的Track方法並傳入我們從Kinect中獲取的數據,然後FaceTracker對象會對這些數據進行處理來進行面部追蹤,部分代碼如下:
// 獲取每一幀數據,然後存儲到變量中來 using (ColorImageFrame colorImageFrame = e.OpenColorImageFrame()) { if (colorImageFrame == null) return; colorImageFrame.CopyPixelDataTo(colorPixelData); } using (DepthImageFrame depthImageFrame = e.OpenDepthImageFrame()) { if (depthImageFrame == null) return; depthImageFrame.CopyPixelDataTo(depthPixelData); } using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame()) { if (skeletonFrame == null) return; skeletonFrame.CopySkeletonDataTo(skeletonData); } //獲取處於跟蹤狀態的骨骼數據對象,如果沒有,則返回. var skeleton = skeletonData.FirstOrDefault(s => s.TrackingState == SkeletonTrackingState.Tracked); if (skeleton == null) return;
前面的都是數據准備階段,一旦數據都獲取了之後,我們使用FaceTracker對象來對這些數據進行識別,提取面部信息。
// 面部追蹤 FaceTrackFrame faceFrame = faceTracker.Track(kinectSensor.ColorStream.Format, colorPixelData, kinectSensor.DepthStream.Format, depthPixelData, skeleton);
faceFrame是一個FaceTrackFrame類型的變量,代表面部追蹤的處理結果,該對象的更詳細信息,您可以查看 MSDN ,下面是該對象的OMD圖
首先,TrackSuccessful 屬性只是是否識別出了面部,FaceRect是面部所在的矩形區域,最重要的是下面的幾個方法:這些方法可以提供最多87個點來表示面部信息,這些點可以以二維或者三維的形式提供。我們可以提取一些用戶的面部表情信息:
Get3DShape() 方法返回三維表示的121個點集合.
GetProjected3DShape() 方法返回同樣數目的以二維形式展現的點的集合,這些點映射到640×480像素的圖像上.
GetAnimationUnitCoefficients() 返回面部表情的描述值,在下面我們會用到這個值來繪制人物圖像.更多的信息,您可以查看 Animation Units on MSDN.
GetTriangles() 該方法可以 和Get3DShape 方法一起使用. 他返回一個三角形集合,集合中的每個三角形的頂點都是由 Get3DShape 中的點組成。這些三角形可以用來進行3D建模,就像Developer Toolkit自帶例子中的那樣,我們可以用它來對整個面部進行動態建模。
2.3 繪制臉部
有了數據之後,我們可以在WPF中用XAML來繪制一個簡單的人臉了。在繪制過程中,我們會使用一些變換Transformations (Translations, Rotations, Scales, …) 來表示人的表情的變化,比如說RenderTransform對象可以用來改變對象的渲染方式,我們使用一個Ellipse 對象來代表嘴巴 (Ellipse with x:Name=”Mouth”) :他有一個 ScaleTransform屬性,我們可以使用它來改變X軸和Y軸上的縮放,來模擬口型的變化,眉頭的模擬也是如此。
<Window x:Class="KinectFaceTracking.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <Grid> <Grid> <Canvas x:Name="MainCanvas" Width="500" Height="500"> <Canvas.RenderTransform> <TransformGroup> <RotateTransform x:Name="CanvasRotate" CenterX="250" CenterY="250" /> <!--<TranslateTransform x:Name="CanvasTranslate" />--> </TransformGroup> </Canvas.RenderTransform> <Ellipse Width="300" Height="300" x:Name="Face" StrokeThickness="2" Stroke="Black" Canvas.Left="105" Canvas.Top="6" /> <Ellipse Width="30" Height="30" x:Name="LeftEye" Stroke="Black" StrokeThickness="2" Canvas.Left="289" Canvas.Top="102" /> <Ellipse Canvas.Left="194" Canvas.Top="102" x:Name="RightEye" Height="30" Stroke="Black" StrokeThickness="2" Width="30" /> <Ellipse Canvas.Left="224" Canvas.Top="239" Height="18" x:Name="Mouth" Stroke="Black" StrokeThickness="2" Width="64" > <Ellipse.RenderTransform> <ScaleTransform x:Name="MouthScaleTransform" CenterX="32" CenterY="9" ScaleX="1" ScaleY="1"/> </Ellipse.RenderTransform> </Ellipse> <!--<Ellipse Canvas.Left="244" Canvas.Top="151" Height="53" x:Name="Nose" Stroke="Black" StrokeThickness="2" Width="22" />--> <Rectangle Width="70" Stroke="Black" Fill="Black" StrokeThickness="10" Height="5" Canvas.Left="169" Canvas.Top="80"> <Rectangle.RenderTransform> <TransformGroup> <TranslateTransform x:Name="RightBrow" /> <RotateTransform x:Name="RightBrowRotate" CenterX="50" Angle="0" /> </TransformGroup> </Rectangle.RenderTransform> </Rectangle> <Rectangle Width="70" Stroke="Black" Fill="Black" StrokeThickness="10" Height="5" Canvas.Left="274" Canvas.Top="80" > <Rectangle.RenderTransform> <TransformGroup> <TranslateTransform x:Name="LeftBrow" /> <RotateTransform x:Name="LeftBrowRotate" CenterX="20" Angle="0" /> </TransformGroup> </Rectangle.RenderTransform> </Rectangle> <Rectangle Canvas.Left="207" Canvas.Top="148" Fill="Black" Height="5" Stroke="Black" StrokeThickness="10" Width="50"> <Rectangle.RenderTransform> <TransformGroup> <RotateTransform Angle="-70" CenterX="50" /> </TransformGroup> </Rectangle.RenderTransform> </Rectangle> <Rectangle Canvas.Left="246" Canvas.Top="190" Fill="Black" Height="5" Stroke="Black" StrokeThickness="10" Width="15"> <Rectangle.RenderTransform> <TransformGroup> <RotateTransform Angle="0" CenterX="50" /> </TransformGroup> </Rectangle.RenderTransform> </Rectangle> </Canvas> </Grid> </Grid> </Window>
查看本欄目
完成之後,一個簡單的人臉就繪制完成了,如下:
2.4 將數據和表現綁定
現在表情繪制完成,我們只需要使用面部追蹤的數據來改變各部分的動畫參數就可以模擬臉部表情了。
獲取數據之前,我們需要檢查是否識別出來了臉部。如果識別出來人臉,我們就接著獲取動畫單位系數(Animation Units coefficients). 這個參數可以告訴哦我們被追蹤對象嘴巴是張開還是合攏,還是在笑,眉頭緊鎖還是笑顏逐開等等…
//如果識別出來,進行進一步處理 if (faceFrame.TrackSuccessful) { // 獲取動畫單位系數 Animation Units coeffs. var AUCoeff = faceFrame.GetAnimationUnitCoefficients(); var jawLowerer = AUCoeff[AnimationUnit.JawLower]; jawLowerer = jawLowerer < 0 ? 0 : jawLowerer; MouthScaleTransform.ScaleY = jawLowerer * 5 + 0.1; MouthScaleTransform.ScaleX = (AUCoeff[AnimationUnit.LipStretcher] + 1); LeftBrow.Y = RightBrow.Y = (AUCoeff[AnimationUnit.BrowLower]) * 40; RightBrowRotate.Angle = (AUCoeff[AnimationUnit.BrowRaiser] * 20); LeftBrowRotate.Angle = -RightBrowRotate.Angle; CanvasRotate.Angle = faceFrame.Rotation.Z; }
上面的動畫參數的取值范圍都是在-1和1之間。到這裡一個簡單的面部追蹤小程序就完成了,您可以對著Kinect做一些表情試一試變化。下面是我做的一些截圖:
三、結語
本文簡單演示了一個如何使用Kinect進行面部追蹤,並使用一個簡單的例子來展現了面部追蹤需要用到的一些對象,可以看出在Kinect SDK 1.5及之後的版中使用面部追蹤功能是比較簡單的。希望本文對您了解Kinect SDK中如何使用面部追蹤有所幫助。
作者: yangecnu(yangecnu's Blog on 博客園)
出處:http://www.cnblogs.com/yangecnu/