2026/9/25 13:42:34

Windows-universal-samples 中的 BasicFaceDetection 示例:使用 FaceDetector 在 UWP 应用中实现静态人脸检测

Windows-universal-samples 中的 BasicFaceDetection 示例:使用 FaceDetector 在 UWP 应用中实现静态人脸检测 示例工程【免费下载链接】Windows-universal-samplesAPI samples for the Universal Windows Platform.项目地址https://gitcode.com/gh_mirrors/wi/Windows-universal-samples点击查看免费下载本指南以 Windows-universal-samples 仓库中的 BasicFaceDetection 示例为蓝本系统讲解 UWP 应用中如何使用Windows.Media.FaceAnalysis.FaceDetector类在一张静态照片或单帧视频中定位人脸并完成像素格式转换、检测结果可视化与界面缩放同步。读完本文你将掌握FaceDetector的初始化与复用策略、SoftwareBitmap/VideoFrame两种输入路径的构建方法以及如何用 XAMLCanvas绘制人脸框并在窗口缩放时保持位置准确。示例概览与目录结构示例位于 Samples/BasicFaceDetection包含两个并列的实现语言目录与一个共享 UI 目录目录说明csC# 实现Scenario1_DetectInPhoto.xaml.cs、Scenario2_DetectInWebcam.xaml.cs、SampleConfiguration.cscppwinrtC/WinRT 实现Scenario1_DetectInPhoto.cpp、Scenario2_DetectInWebcam.cpp、SampleConfiguration.cppshared两个场景共享的 XAML 页面Scenario1_DetectInPhoto.xaml与Scenario2_DetectInWebcam.xaml两个场景通过 SampleConfiguration.cs 中的场景列表注册到示例框架Detect Faces in Photos从文件选择器中挑选一张图片jpg/jpeg/png/bmp解码后执行人脸检测Detect Faces in Webcam启动摄像头实时预览抓取单帧快照后执行人脸检测。从源码结构看两个场景的差异仅在于输入源照片场景把解码后的SoftwareBitmap交给FaceDetector网络摄像头场景则把MediaCapture抓取到的VideoFrame中的SoftwareBitmap交给同一个检测器后续的检测调用与可视化逻辑完全一致。FaceDetector 的初始化与复用创建检测器实例FaceDetector位于Windows.Media.FaceAnalysis命名空间只能通过异步工厂方法创建FaceDetector detector await FaceDetector.CreateAsync();照片场景的源码Scenario1_DetectInPhoto.xaml.cs特别注释了这一点FaceDetector初始化可能耗时较长在大多数情况下应当创建成员变量并复用该对象本场景为了演示简洁性每次点击按钮时新建实例。因此实际项目中推荐的模式是在页面或服务对象中保存一个FaceDetector字段在首次使用时惰性创建后续检测直接复用避免反复承担初始化开销。检测前的格式校验FaceDetector只接受有限的像素格式检测前必须用静态方法校验if (FaceDetector.IsBitmapPixelFormatSupported(InputPixelFormat)) { // 执行检测 }示例在两个场景中分别校验了两种典型格式照片场景使用BitmapPixelFormat.Gray88 位灰度因为人脸检测本质上不需要彩色信息灰度图体积小、检测更快网络摄像头场景使用BitmapPixelFormat.Nv12这是摄像头预览流常见的 YUV 格式MediaCapture.GetPreviewFrameAsync会把原生帧转换为此格式。校验失败时会通过rootPage.NotifyUser输出错误提示例如 PixelFormat Gray8 is not supported by FaceDetector。场景一从照片文件检测人脸文件选择与位图解码照片场景通过 FileOpenPicker 提供的按钮触发选择器限制为图片扩展名FileOpenPicker photoPicker new FileOpenPicker(); photoPicker.ViewMode PickerViewMode.Thumbnail; photoPicker.SuggestedStartLocation PickerLocationId.PicturesLibrary; photoPicker.FileTypeFilter.Add(.jpg); photoPicker.FileTypeFilter.Add(.jpeg); photoPicker.FileTypeFilter.Add(.png); photoPicker.FileTypeFilter.Add(.bmp);选中文件后用BitmapDecoder解码位图并制作两份副本——一份交给检测器一份用于显示using (IRandomAccessStream fileStream await photoFile.OpenAsync(Windows.Storage.FileAccessMode.Read)) { BitmapDecoder decoder await BitmapDecoder.CreateAsync(fileStream); BitmapTransform transform this.ComputeScalingTransformForSourceImage(decoder); using (SoftwareBitmap originalBitmap await decoder.GetSoftwareBitmapAsync( decoder.BitmapPixelFormat, BitmapAlphaMode.Ignore, transform, ExifOrientationMode.IgnoreExifOrientation, ColorManagementMode.DoNotColorManage)) { const BitmapPixelFormat InputPixelFormat BitmapPixelFormat.Gray8; if (FaceDetector.IsBitmapPixelFormatSupported(InputPixelFormat)) { using (SoftwareBitmap detectorInput SoftwareBitmap.Convert(originalBitmap, InputPixelFormat)) { // 显示用副本 WriteableBitmap displaySource new WriteableBitmap(originalBitmap.PixelWidth, originalBitmap.PixelHeight); originalBitmap.CopyToBuffer(displaySource.PixelBuffer); FaceDetector detector await FaceDetector.CreateAsync(); IListDetectedFace faces await detector.DetectFacesAsync(detectorInput); this.SetupVisualization(displaySource, faces); } } } }关键点有三个格式转换用SoftwareBitmap.Convert把原始位图转为Gray8这是检测器输入显示副本WriteableBitmap不支持灰度图因此显示时仍使用原始像素格式的位图通过CopyToBuffer拷贝到WriteableBitmap.PixelBuffer检测调用DetectFacesAsync(detectorInput)返回IListDetectedFace其中DetectedFace.FaceBoxBitmapBounds结构给出了每个人脸的包围矩形坐标。大图降采样1280 像素高度限制FaceDetector在超大图片上的性能会显著下降示例因此设置了一个输入高度上限。C# 与 C/WinRT 两侧的常量完全一致private readonly uint sourceImageHeightLimit 1280;static constexpr uint32_t sourceImageHeightLimit 1280;ComputeScalingTransformForSourceImage在解码时按比例降采样当PixelHeight超过 1280 时按1280 / 原始高度的比例同时缩放宽高返回一个BitmapTransform交给GetSoftwareBitmapAsync。源码注释明确说明这是为兼顾检测精度与性能而选择的任意值实际应用应根据自身性能/精度需求调整。场景二从摄像头快照检测人脸摄像头初始化与预览网络摄像头场景的状态机Idle → Streaming → Snapshot由 Scenario2_DetectInWebcam.xaml.cs 管理。启动流式传输时依次完成创建FaceDetector→ 初始化MediaCapture→ 缓存视频属性 → 开始预览this.faceDetector await FaceDetector.CreateAsync(); MediaCaptureInitializationSettings settings new MediaCaptureInitializationSettings(); settings.StreamingCaptureMode StreamingCaptureMode.Video; // 仅视频不申请麦克风 await this.mediaCapture.InitializeAsync(settings); this.mediaCapture.CameraStreamStateChanged this.MediaCapture_CameraStreamStateChanged; var deviceController this.mediaCapture.VideoDeviceController; this.videoProperties deviceController.GetMediaStreamProperties(MediaStreamType.VideoPreview) as VideoEncodingProperties; this.CamPreview.Source this.mediaCapture; // CaptureElement 的 Source 必须在启动前设置 await this.mediaCapture.StartPreviewAsync();这里有两个值得注意的工程细节能力声明匹配初始化设置只声明了StreamingCaptureMode.Video与 Package.appxmanifest 中仅声明的webcam设备能力对应。源码注释特别警告如果改用包含麦克风的默认构造函数则必须同时在清单中补充microphone能力否则初始化会失败异常处理如果用户在隐私设置中禁用了摄像头InitializeAsync会抛出UnauthorizedAccessException示例会给出明确提示Webcam is disabled or access to the webcam is disabled for this app. Ensure Privacy Settings allow webcam usage.。UWP 应用中相机访问需要用户在系统设置中授予隐私权限这是实际部署时最常见的失败点之一。抓帧并执行检测点击 Take Snapshot 后用VideoFrame指定 NV12 目标格式再调用GetPreviewFrameAsync让系统把摄像头原生帧转换为该格式const BitmapPixelFormat InputPixelFormat BitmapPixelFormat.Nv12; using (VideoFrame previewFrame new VideoFrame(InputPixelFormat, (int)this.videoProperties.Width, (int)this.videoProperties.Height)) { await this.mediaCapture.GetPreviewFrameAsync(previewFrame); if (FaceDetector.IsBitmapPixelFormatSupported(previewFrame.SoftwareBitmap.BitmapPixelFormat)) { IListDetectedFace faces await this.faceDetector.DetectFacesAsync(previewFrame.SoftwareBitmap); // WriteableBitmap 不支持 NV12转换为 32 位 BGRA 用于显示 using (SoftwareBitmap convertedSource SoftwareBitmap.Convert(previewFrame.SoftwareBitmap, BitmapPixelFormat.Bgra8)) { displaySource new WriteableBitmap(convertedSource.PixelWidth, convertedSource.PixelHeight); convertedSource.CopyToBuffer(displaySource.PixelBuffer); } this.SetupVisualization(displaySource, faces); } }注意这里的格式选择与照片场景相反检测输入保持 NV12摄像头预览原生格式避免额外转换开销而显示副本转为 BGRA8因为WriteableBitmap不支持 NV12。抓帧完成后立即关闭摄像头并释放MediaCapture进入Snapshot状态展示结果点击 Clear Display 则回到Idle。应用挂起Suspending事件时示例通过延迟SuspendingOperation.GetDeferral确保先回到Idle状态、释放摄像头资源再完成挂起流程。检测结果的可视化与缩放同步用黄色边框框出人脸两个场景共享同一套可视化逻辑。共享 XAML 中定义了一个DataTemplate见 Scenario1_DetectInPhoto.xamlPage.Resources DataTemplate x:NameHighlightedFaceBox Border BorderBrushYellow BorderThickness2/ /DataTemplate /Page.ResourcesC# 侧的MainPage.HighlightFacesSampleConfiguration.cs把检测结果逐个渲染到Canvas上public static void HighlightFaces(WriteableBitmap displaySource, IListDetectedFace foundFaces, Canvas canvas, DataTemplate template) { double widthScale canvas.ActualWidth / displaySource.PixelWidth; double heightScale canvas.ActualHeight / displaySource.PixelHeight; foreach (DetectedFace face in foundFaces) { var box (FrameworkElement)template.LoadContent(); box.Tag face.FaceBox; // 保存原始包围盒供后续缩放 ApplyScale(box, widthScale, heightScale); canvas.Children.Add(box); } // 输出 Found N human faces in the image 等状态消息 }C/WinRT 的SampleHelpers::HighlightFacesSampleConfiguration.cpp逻辑完全对应仅把 C# 的box.Tag换成了box.Tag(box_value(face.FaceBox()))。缩放自适应Tag 保存原始坐标由于图片尺寸与Canvas的实际显示尺寸往往不同示例把face.FaceBox的原始值存入元素的Tag再按缩放比例换算宽高与边距static void ApplyScale(FrameworkElement box, double widthScale, double heightScale) { BitmapBounds faceBox (BitmapBounds)box.Tag; box.Width faceBox.Width * widthScale; box.Height faceBox.Height * heightScale; box.Margin new Thickness(faceBox.X * widthScale, faceBox.Y * heightScale, 0, 0); }当窗口尺寸变化触发Canvas.SizeChanged时RepositionFaces重新计算缩放因子并对所有子元素重新应用ApplyScale从而保证人脸框始终与图像内容对齐。这是 UWP 自适应布局中处理图像坐标系 ↔ 控件坐标系映射的通用手法。构建与运行系统要求按 README.md 的说明示例需要硬件摄像头仅用于视频捕获场景照片场景不需要客户端Windows 10服务端Windows Server 2016 Technical Preview手机Windows 10。Package.appxmanifest中声明TargetDeviceFamily的MinVersion10.0.10240.0即首个 Windows 10 正式版本即可运行。构建步骤若下载的是整个示例集合的 ZIP务必解压整个归档文件而不仅是目标示例所在文件夹——示例依赖共享的SharedContent目录启动 Visual Studio选择File Open Project/Solution定位到示例的cs或cppwinrt子目录双击其中的解决方案文件BasicFaceDetection.sln按CtrlShiftB或选择Build Build Solution。运行步骤仅部署选择Build Deploy Solution调试运行按F5或选择Debug Start Debugging免调试运行按CtrlF5或选择Debug Start Without Debugging。重要边界FaceDetector 与 FaceTracker 的选型README 明确给出了一条关键的设计约束FaceDetector面向静态图像或视频单帧并非为视频播放或实时摄像头流优化。如果需要实时跟踪人脸无论是直播流还是视频片段应改用FaceTrackerAPI。仓库中的相关示例可直接对照学习BasicFaceTracking实时人脸跟踪示例C/C#/C/WinRTHolographicFaceTracking基于 C 的混合现实人脸跟踪FilePicker照片场景依赖的文件选择器用法CameraStarterKit摄像头初始化与预览的完整示例SimpleImaging位图解码与SoftwareBitmap基础操作。小结BasicFaceDetection 示例完整演示了 UWP 人脸检测的四个核心环节FaceDetector的创建与复用、输入位图的获取与像素格式转换、DetectFacesAsync的调用以及基于Canvas的检测结果可视化。其源码还包含两个值得迁移到实际项目的工程细节用 1280 像素高度上限对大图降采样以平衡性能与精度以及用Tag保存原始包围盒坐标实现窗口缩放时的人脸框自适应。理解这些实现后你可以快速为自己的 UWP 应用接入静态图片/单帧视频的人脸检测能力并在需要连续跟踪时平滑切换到FaceTracker方案。赞分享示例工程【免费下载链接】Windows-universal-samplesAPI samples for the Universal Windows Platform.项目地址https://gitcode.com/gh_mirrors/wi/Windows-universal-samples点击查看免费下载相关推荐提升研究质量Awesome Claude Skills学术写作助手提升研究质量Awesome Claude Skills学术写作助手 Awesome Claude Skills是一个精心策划的Claude技能、资源和工具列表AI 技能AI 插件人工智能工作流自动化技术栈迁移指南从国际标准到国密算法的完整实施路径技术栈迁移指南从国际标准到国密算法的完整实施路径 面对日益严峻的网络安全挑战和技术自主可控要求企业级应用正在加速从传统国际加密算法向国密算法技术栈迁移。Op密码学网络安全通信UWP 应用数据存储实战Windows-universal-samples 之 ApplicationData 示例深度解析UWP 应用数据存储实战Windows universal samples 之 ApplicationData 示例深度解析 导读 本文以 Windows u示例工程上一篇5个步骤掌握Audiveris免费开源乐谱识别软件的终极指南下一篇Semantica store migrate 命令详解FAISS、SQLite 与 pgvector 之间迁移向量库创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考