WWDC Quick Look 💓 By SwiftGGTeam
Detect people, faces, and poses using Vision

Detect people, faces, and poses using Vision

观看原视频

Highlight

Vision 框架的 Face Detection 升级到 Revision 3,支持检测戴口罩的人脸并新增 pitch 姿态指标,所有姿态指标从离散值改为连续值;Person Segmentation API 新增语义人物分割,可在多平台实现虚拟背景和人物抠图。

核心内容

人脸检测的口罩时代升级

戴口罩成为日常后,原来的人脸检测算法会遇到挑战。WWDC2021 把人脸检测升级到 Revision 3(01:15),不仅能识别被口罩遮挡的脸,还保留了眼镜、帽子等遮挡物的识别能力。

人脸姿态指标也得到完善。之前只有 roll 和 yaw,今年新增了 pitch(点头动作)。更重要的是,所有指标从离散值(分桶)改为连续值(01:41)。以前 roll 只能返回 -90、-45、0、45、90 这几档,现在可以返回任意弧度值,使得姿态跟踪更流畅。

三个姿态指标的含义来自飞行力学(02:54):

  • Roll:头部左右歪斜(摇头)
  • Yaw:头部左右转动(回头)
  • Pitch:头部上下点头

这些指标通过 VNFaceObservationrollyawpitch 属性获取,单位是弧度。

人体姿态检测的改进

人体矩形检测升级到 Revision 2(05:17),新增全身检测支持。之前只能检测上半身,现在可以通过 upperBodyOnly 属性切换。默认仍是 true 保持向后兼容,设为 false 可以检测全身。

手部姿态检测新增 chirality 属性(06:16),可以判断检测到的手是左手还是右手。

Person Segmentation:语义人物分割

这是今年最大的新增功能(06:53)。VNGeneratePersonSegmentationRequest 可以生成一张分割掩码,把画面中的人物从背景中分离出来。与传统的前景背景分割不同,Vision 实现的是语义分割——它知道什么是「人」,会把画面中所有人合并到同一个掩码中。

API 提供三个质量级别(09:06):

  • accurate:最高质量,适合计算摄影
  • balanced:平衡,适合逐帧视频处理
  • fast:最快,适合实时流处理

质量越高,资源消耗越大。掩码的动态范围、分辨率、内存占用、处理时间都会随质量提升而增加。

多框架的人物分割能力

Person Segmentation 不仅在 Vision 中可用,还集成到了多个框架(14:15):

  • AVFoundation:拍照时可以获取 AVCapturePhoto.portraitEffectsMatte,部分新款设备支持
  • ARKitARFrame.segmentationBuffer 提供 AR 场景中的人物分割,需要 A12 仿生芯片及后续设备
  • Core ImageCIFilter.personSegmentation() 提供纯 Core Image 域的接口

详细内容

人物分割请求配置

08:13

// 创建请求
let request = VNGeneratePersonSegmentationRequest()

// 创建请求处理器
let requestHandler = VNImageRequestHandler(url: imageURL, options: options)

// 执行请求
try requestHandler.perform([request])

// 获取结果
let mask = request.results!.first!
let maskBuffer = mask.pixelBuffer

关键点:

  • 请求是状态对象,在视频流中需要复用同一个 request,有助于帧间平滑
  • 结果是 VNPixelBufferObservationpixelBuffer 属性包含掩码数据

08:33

let request = VNGeneratePersonSegmentationRequest()

// 设置 revision(明确指定以避免未来 SDK 更新行为变化)
request.revision = VNGeneratePersonSegmentationRequestRevision1

// 设置质量级别
request.qualityLevel = VNGeneratePersonSegmentationRequest.QualityLevel.accurate

// 设置输出像素格式
request.outputPixelFormat = kCVPixelFormatType_OneComponent8

关键点:

  • 显式设置 revision 保证行为确定性,否则 SDK 更新后会自动用最新 revision
  • 三种质量级别在不同场景下的推荐:accurate 用于计算摄影,balanced 用于视频,fast 用于实时流
  • 输出格式可选:8 位整数、32 位浮点、16 位浮点(half float)。16 位浮点可直接输入 GPU 处理

应用分割掩码替换背景

12:24

let input = CIImage(contentsOf: imageUrl)!
let mask = CIImage(cvPixelBuffer: maskBuffer)
let background = CIImage(contentsOf: backgroundImageUrl)!

// 缩放掩码到输入图像尺寸
let maskScaleX = input.extent.width / mask.extent.width
let maskScaleY = input.extent.height / mask.extent.height
let maskScaled = mask.transformed(by: CGAffineTransform(
    maskScaleX, 0, 0, maskScaleY, 0, 0
))

// 缩放背景到输入图像尺寸
let backgroundScaleX = input.extent.width / background.extent.width
let backgroundScaleY = input.extent.height / background.extent.height
let backgroundScaled = background.transformed(by: CGAffineTransform(
    backgroundScaleX, 0, 0, backgroundScaleY, 0, 0
))

// 使用混合滤镜
let blendFilter = CIFilter.blendWithRedMask()
blendFilter.inputImage = input
blendFilter.backgroundImage = backgroundScaled
blendFilter.maskImage = maskScaled

let blendedImage = blendFilter.outputImage

关键点:

  • 掩码和背景都需要缩放到与输入图像相同的尺寸
  • CIFilter.blendWithRedMask() 根据 red 通道掩码混合前景和背景
  • CIImage 初始化时如果是单通道 PixelBuffer,默认是 red 通道

AVCapture 中的分割掩码

14:37

private let photoOutput = AVCapturePhotoOutput()

if self.photoOutput.isPortraitEffectsMatteDeliverySupported {
    self.photoOutput.isPortraitEffectsMatteDeliveryEnabled = true
}

// AVCapturePhoto 的分割掩码属性
open class AVCapturePhoto {
    var portraitEffectsMatte: AVPortraitEffectsMatte? { get }
    // nil 表示场景中没有人
}

关键点:

  • isPortraitEffectsMatteDeliverySupported 检查设备是否支持
  • 启用后在拍照时自动计算分割掩码
  • AVPortraitEffectsMatte 可用于后期处理

ARKit 中的分割掩码

14:58

// 检查是否支持人物分割
if ARWorldTrackingConfiguration.supportsFrameSemantics(.personSegmentationWithDepth) {
    // 可以获取人物分割掩码
    // ...
}

open class ARFrame {
    var segmentationBuffer: CVPixelBuffer? { get }
}

关键点:

  • 需要 A12 仿生芯片或更新设备(iPhone Xs 及后续)
  • supportsFrameSemantics 检查特定设备是否支持
  • .personSegmentationWithDepth 同时提供分割掩码和深度信息

Core Image 中的分割

15:31

let input = CIImage(contentsOf: imageUrl)!

let segmentationFilter = CIFilter.personSegmentation()
segmentationFilter.inputImage = input

let mask = segmentationFilter.outputImage

关键点:

  • CIFilter.personSegmentation() 是 Vision API 的薄封装
  • 适合需要完全在 Core Image 域处理的场景
  • 输出是 CIImage,可以直接用于其他 Core Image 滤镜

核心启发

1. 虚拟背景视频通话 App

  • 做什么:类似 Zoom 的虚拟背景功能,让用户在视频通话时替换背景
  • 为什么值得做:Person Segmentation 支持多平台,balanced 质量级别可在实时视频流中运行
  • 怎么开始:用 AVCaptureVideoDataOutput 获取视频帧,每帧执行 VNGeneratePersonSegmentationRequestqualityLevel = .balanced),用掩码混合背景图像

2. 人脸姿态控制的交互界面

  • 做什么:用头部姿态控制 UI,比如转头翻页、点头确认
  • 为什么值得做:连续值的面部姿态指标让控制更精确,不像离散值那样跳跃
  • 怎么开始:用 VNDetectFaceRectanglesRequestrollyawpitch 属性,设置阈值触发对应动作

3. 智能照片编辑 App

  • 做什么:自动识别人物并提供人物专属的编辑效果(比如背景虚化、背景替换)
  • 为什么值得做:Person Segmentation 的 accurate 模式质量高,适合照片编辑场景
  • 怎么开始:用 VNGeneratePersonSegmentationRequestaccurate 质量,配合 Core Image 的 CIFilter.portraitEffect() 实现人物光效

4. AR 社交 App 的人物遮挡

  • 做什么:在 AR 场景中,真实人物可以遮挡虚拟物体,增强真实感
  • 为什么值得做:ARKit 的 personSegmentationWithDepth 同时提供掩码和深度,可实现更精确的遮挡效果
  • 怎么开始:检查 supportsFrameSemantics(.personSegmentationWithDepth),从 ARFrame.segmentationBuffer 获取掩码用于渲染

关联 Session

评论

GitHub Issues · utterances