本文共 5428 字,大约阅读时间需要 18 分钟。
目录
通用Windows平台的Windows.Media.FaceAnalysis
名称空间包含可用于检测图像文件和视频帧中的面部的API。人脸检测API是可用于桌面应用程序的UWP API,使得这种可用性成为可能。本文将介绍如何在WPF应用程序中使用UWP人脸检测API,特别是在图像文件中检测人脸。
接下来,需要熟悉MVVM模式。要运行示例项目,您应该安装以下软件:
该示例应用程序是一个引用Microsoft.Windows.SDK.Contracts
程序包(Windows 10 WinRT API包)的.NET Core WPF项目,该程序使桌面应用程序可以访问某些UWP API。用户可以选择一个图像文件,并点击检测面孔按钮来检测所选择的图像中的人脸。
要使用UWP人脸检测API,您必须导入Windows.Media.FaceAnalysis
命名空间。在示例项目中,此操作在包含执行人脸检测过程的DetectFaces()
方法的FaceDetectionService
类中完成。
public async Task> DetectFaces(Stream fileStream){ var stream = fileStream.AsRandomAccessStream(); var bitmapDecoder = await BitmapDecoder.CreateAsync(stream); using SoftwareBitmap bitmap = await bitmapDecoder.GetSoftwareBitmapAsync(); var bmp = FaceDetector.IsBitmapPixelFormatSupported(bitmap.BitmapPixelFormat) ? bitmap : SoftwareBitmap.Convert(bitmap, BitmapPixelFormat.Gray8); var faceDetector = await FaceDetector.CreateAsync(); var detectedFaces = await faceDetector.DetectFacesAsync(bmp); return detectedFaces;}
FaceDetector
仅于SoftwareBitmap
一起工作,因此目标图像被转换为使用BitmapDecoder
。然后检查位图像素格式,如果不是当前设备FaceDetector
支持的位图像素格式之一,则完成转换。DetectFacesAsync()
检测SoftwareBitmap
中的人脸并返回DetectedFace
对象的集合。
为了使用边界框标记检测到的面部,我正在使用System.Drawing
命名空间中的Graphics
类。
public Bitmap DetectedFacesBitmap(Stream fileStream, IListdetectedFaces, Color boxColor, int strokeThickness = 2){ var bitmap = new Bitmap(fileStream); using (var graphics = Graphics.FromImage(bitmap)) { using var stroke = new Pen(boxColor, strokeThickness); foreach (var face in detectedFaces) { BitmapBounds faceBox = face.FaceBox; graphics.DrawRectangle(stroke, (int)faceBox.X, (int)faceBox.Y, (int)faceBox.Width, (int)faceBox.Height); } } return bitmap;}
DetectedFace
包含一个名为FaceBox
的属性,它提供检测到的脸部的边界。在检测到的脸所在的图像上绘制矩形时,将使用边界。
该示例项目遵循MVVM模式,并且仅包含一个视图模型– MainWindowViewModel
。该视图模型包含两个属性。一种用于指定所选图像的路径的string
类型,另一种用于处理图像的Bitmap
类型。视图模型还包含用于执行图像选择和面部检测的命令。
using System.Drawing;using System.IO;using System.Threading.Tasks;using FaceDetection.Commands;using FaceDetection.Services.Interfaces;namespace FaceDetection.ViewModels{ public class MainWindowViewModel : ViewModelBase { private readonly IDialogService dialogService; private readonly IFaceDetectionService faceDetectionService; public MainWindowViewModel(IDialogService dialogSvc, IFaceDetectionService faceDetectionSvc) { dialogService = dialogSvc; faceDetectionService = faceDetectionSvc; } private string _selectedImage; public string SelectedImage { get => _selectedImage; set { _selectedImage = value; OnPropertyChanged(); } } #region Select Image Command private RelayCommand _selectImageCommand; public RelayCommand SelectImageCommand => _selectImageCommand ??= new RelayCommand(_ => SelectImage()); private void SelectImage() { var image = dialogService.PickFile("Select Image", "Image (*.jpg; *.jpeg; *.png)|*.jpg; *.jpeg; *.png"); if (string.IsNullOrWhiteSpace(image)) return; SelectedImage = image; } #endregion private Bitmap _facesBitmap; public Bitmap FacesBitmap { get => _facesBitmap; set { _facesBitmap = value; OnPropertyChanged(); } } #region Detect faces Command private RelayCommandAsync _detectFacesCommand; public RelayCommandAsync DetectFacesCommand => _detectFacesCommand ??= new RelayCommandAsync (DetectFaces, _ => CanDetectFaces()); private async Task DetectFaces() { await using FileStream fileStream = File.OpenRead(_selectedImage); var faces = await faceDetectionService.DetectFaces(fileStream); FacesBitmap = faceDetectionService.DetectedFacesBitmap (fileStream, faces, Color.GreenYellow); SelectedImage = null; } private bool CanDetectFaces() => !string.IsNullOrWhiteSpace(SelectedImage); #endregion }}
使用MainWindow.xaml中Image
控件的数据触发器在所选图像和已处理图像之间进行切换:
由于FacesBitmap
类型为Bitmap
,因此必须将其转换为BitmapSource
。这是使用转换器完成的。
public class BitmapToBitmapSourceConverter : IValueConverter{ public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is null) return null; using var bitmap = (Bitmap)value; using var stream = new MemoryStream(); bitmap.Save(stream, ImageFormat.Bmp); stream.Position = 0; var bmpImg = new BitmapImage(); bmpImg.BeginInit(); bmpImg.CacheOption = BitmapCacheOption.OnLoad; bmpImg.StreamSource = stream; bmpImg.EndInit(); bmpImg.Freeze(); return bmpImg; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return Binding.DoNothing; }}
如您所见,使用UWP人脸检测API是一个非常简单的过程。重要的是要注意,尽管该API确实非常擅长检测人脸,但由于像素可能不足以使人脸检测器正常工作,因此它可能无法检测到部分可见的人脸。
就是这样!如果您需要查看示例项目的其余代码,请使用本文顶部的下载链接来克隆或下载存储库。
转载地址:http://dpwhj.baihongyu.com/