可能你會認為人臉識別用起來會很復雜,老周當初也這么想,但通過實際操作后,我發現非然。
經過微軟封裝的東西,向來都是復雜問題簡單化,只要用得舒心,代碼越少越好,用最少的代碼做最多的事情,此為大師境界也。
好,屁話不說,先介紹一下如何完成人臉識別(或者叫人臉檢測,隨你怎么翻譯,反正知道是怎么一回事就行)。核心的類是FaceDetector,不要問我這個類在哪里,自己打開對象瀏覽器搜索。
第一步,訪問靜態屬性IsSupported,看看當前平台是不是支持人臉識別,如果返回false,那就沒戲了。
第二步,調用靜態方法CreateAsync得到一個FaceDetector實例,所以該類不需要手動實例化,初始化過程由運行庫來完成,然后把初始化好的實例返回給咱們,然后就可以用它來干活了。
第三步,調用實例方法DetectFacesAsync進行識別,識別完后會返回一個DetectedFace列表,每個DetectedFace表示一張臉,因為你用來識別的照片中可能包含N張臉。FaceBox屬性包含了人臉的矩形區域,就是人臉位於整張照片的哪個位置,可通過X,Y坐標描述矩形的左上角位置,並用寬度和高度來表明那張臉的大小。
DetectFacesAsync方法需要一個SoftwareBitmap類型的參數,該參數就是你要用來識別人臉的圖像。
可能大家已經知道,通過BitmapDecoder類的GetSoftwareBitmapAsync方法可以返回一個SoftwareBitmap實例,不過要注意的是,FaceDetector在進行檢測時並不是所有像素格式都支持,可以調用GetSupportedBitmapPixelFormats方法來獲取所有受支持的像素格式列表,經老周測試,該方法返回Nv12和Gray8,也就是當前只支持這兩種格式。當然,你也可以通過IsBitmapPixelFormatSupported方法來驗證一下某個像素格式是否被支持。
好了,基本用法已經說完了,確實不是很復雜。下面,老周給大家演示一個例子,該例子允許你選擇一張照片,然后識別出照片上的人臉,並用一個矩形來標記。
先看看UI的設計,主要的XAML如下:
<Grid> <Grid.RowDefinitions> <RowDefinition Height="auto"/> <RowDefinition Height="*"/> <RowDefinition Height="auto"/> </Grid.RowDefinitions> <Button Content="選擇要識別的照片" Click="OnClick"/> <Viewbox Grid.Row="1" Margin="5" Stretch="Uniform" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> <Canvas Name="cv" Width="{x:Bind img.Width,Mode=OneWay}" Height="{x:Bind img.Height,Mode=OneWay}" > <Image Name="img" Stretch="None"/> </Canvas> </Viewbox> <TextBlock Name="tbMessage" Foreground="Red" FontSize="16" Grid.Row="2"/> </Grid>
為啥我要用一個ViewBox呢,因為這個控件有一個好處,就是會自動將它里面的可視化對象進行縮放,待會兒我要在Image上顯示圖片,而且還要用到Rectangle元素來標記人臉的位置,為了讓絕對坐標計算起來能與原圖相等,就把這些內容都放在ViewBox中,讓Viewbox來進行縮放,這樣一來,就能夠根據窗口的大小自動調整顯示區域了。
之所以用Canvas,是因它是絕對坐標定位的,這方便我稍后放置Rectangle元素。
處理按鈕事件,通過OpenFilePicker來打開圖像文件。
FileOpenPicker picker = new FileOpenPicker(); picker.FileTypeFilter.Add(".jpg"); picker.FileTypeFilter.Add(".jpeg"); picker.FileTypeFilter.Add(".png"); StorageFile file = await picker.PickSingleFileAsync();
記得以前跟大家講過,picker調用后要掛起當前應用,並通過響應應用激活來處理獲取的文件,這是在WP 8.1的文章中說過,但是,現在不用了,很簡單,因為Windows Phone App和Windows App已經完全統一了,所以不必再考慮平台隔離的代碼了。
下面代碼完成兩件事:1、在Image控件上顯示圖像;2、進行識別,並用矩形標記人臉位置。
if (file != null) { using (IRandomAccessStream streamIn= await file.OpenReadAsync()) { // 對圖像文件進行解碼 BitmapDecoder decoder = await BitmapDecoder.CreateAsync(streamIn); // 獲取圖像內容 SoftwareBitmap sbmp = await decoder.GetSoftwareBitmapAsync(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight); WriteableBitmap bmp = new WriteableBitmap(sbmp.PixelWidth, sbmp.PixelHeight); sbmp.CopyToBuffer(bmp.PixelBuffer); this.img.Source = bmp; img.Width = bmp.PixelWidth; img.Height = bmp.PixelHeight; // 通過循環,嘗試以各種受支持的格式來進行識別 // 如果識別順利,就跳出循環 // 否則進入下一輪循環 int n = 0; while (n < formats.Count) { if (FaceDetector.IsBitmapPixelFormatSupported(formats[n])) { FaceDetector detector = await FaceDetector.CreateAsync(); try { // 轉換圖像像素格式 SoftwareBitmap sbmp2 = SoftwareBitmap.Convert(sbmp, formats[n]); // 進行檢測 IList<DetectedFace> results = await detector.DetectFacesAsync(sbmp2); // 清理Canvas中的矩形 while (cv.Children.Count > 1) cv.Children.RemoveAt(cv.Children.Count - 1); // 在界面上添加矩形 for (int i = 0; i < results.Count; i++) { DetectedFace dface = results[i]; Rectangle rect = new Rectangle(); rect.Stroke = new SolidColorBrush(Colors.Yellow); rect.StrokeThickness = 5d; // 定位矩形 Canvas.SetLeft(rect, dface.FaceBox.X); Canvas.SetTop(rect, dface.FaceBox.Y); rect.Width = dface.FaceBox.Width; rect.Height = dface.FaceBox.Height; cv.Children.Add(rect); } tbMessage.Text = "人臉識別完成。"; break; } catch { tbMessage.Text = "人臉識別失敗。"; n++; } //cv.InvalidateArrange(); } } }
因為我要在Image上顯示圖像,所以從decoder中得到的SoftwareBitmap不能直接用於識別,原因是我剛才說了,目前SDK的人臉識別只支持少量的像素格式,Bgra8是不受支持的,所以可以用SoftwareBitmap的Convert方法轉換格式,並返回轉換后的SoftwareBitmap對象。
這里我用一個while循環來完成識別:
int n = 0; while (n < formats.Count) { if (FaceDetector.IsBitmapPixelFormatSupported(formats[n])) { FaceDetector detector = await FaceDetector.CreateAsync(); try { …… break; } catch { …… n++; } }
意思是,我用FaceDetector所支持的所有像素格式都去嘗試進行識別,只要其中有一種格式能夠順利完成識別,就終止循環(break);如果第一種格式不能識別,就把n++來使用第二種格式來識別。
=============================================
示例的大致情況就是這樣,做完后我們當然要來試試效果了。
首先,來檢測一下八戒的豬臉。
很顯然,豬臉也能檢測出來,不錯。
接着,我又請神仙妹妹來試鏡。發現效果甚好。
然后,我又找來一位MM再試,效果也甚佳。
怎么樣,這姿勢不錯吧。
示例源碼下載:http://files.cnblogs.com/files/tcjiaan/FaceDetApp.zip