可能你會認為人臉識别用起來會很複雜,老周當初也這麼想,但通過實際操作後,我發現非然。
經過微軟封裝的東西,向來都是複雜問題簡單化,隻要用得舒心,代碼越少越好,用最少的代碼做最多的事情,此為大師境界也。
好,屁話不說,先介紹一下如何完成人臉識别(或者叫人臉檢測,随你怎麼翻譯,反正知道是怎麼一回事就行)。核心的類是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++來使用第二種格式來識别。
=============================================
示例的大緻情況就是這樣,做完後我們當然要來試試效果了。
首先,來檢測一下八戒的豬臉。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLyYjM5kTO3ADMxMDMxUjMvwlNwUTMwIzLclDOzcjNz8CX1EDMyc2bsJ2Lc12bj5ycn9Gbi52YuAzcldWYtl2Lc9CX6MHc0RHaiojIsJye.png)
很顯然,豬臉也能檢測出來,不錯。
接着,我又請神仙妹妹來試鏡。發現效果甚好。
然後,我又找來一位MM再試,效果也甚佳。
怎麼樣,這姿勢不錯吧。
示例源碼下載下傳:https://files.cnblogs.com/files/tcjiaan/FaceDetApp.zip