Detect people, faces, and poses using Vision
Machine Learning & AI 进阶 26m

使用 Vision 检测人物、面部和姿态

Detect people, faces, and poses using Vision

2021年6月11日

在 Apple 官方观看视频

一句话判断

Vision 框架在 iOS 15 把人体分析能力从「检测有没有人」升级到「分析人在干什么」——全身姿态检测和人体分割是最大的两个新能力。

这场 Session 讲了什么

Vision 框架是 Apple 在端侧视觉智能的核心框架。iOS 15 对人体分析能力做了全面升级,覆盖了从检测到理解的完整链路。

人体姿态检测(Body Pose Detection)是最大的新增功能。VNDetectHumanBodyPoseRequest 可以检测人体 19 个关键点(头、肩、肘、腕、髋、膝、踝等),支持多人同时检测。这个能力可以直接用于健身 app 的动作矫正、体感游戏的动作输入、或者运动分析。

人体分割(Human Segmentation)也有了改进。VNGeneratePersonSegmentationRequest 现在支持三种输出模式:前景掩码(二值图)、高质量抠图(带 Alpha 通道)和粗糙的深度图。这使得视频通话中的虚拟背景、AR 中的前景遮挡成为可能。

面部检测方面,VNDetectFaceCaptureQualityRequest 是新的 API,可以评估一张照片中面部的拍摄质量(对焦、曝光、表情),帮你自动筛选最佳照片。

值得深挖的点

全身姿态检测与手部姿态检测的协作

Body Pose 和 Hand Pose 可以组合使用。先检测全身姿态,定位手部区域,然后在手部区域上运行 Hand Pose Detection 获取手指级别的精度。这种级联方式比直接在全图上跑 Hand Pose 更高效——因为 Hand Pose 检测的计算量远大于 Body Pose。

Person Segmentation 在视频通话中的应用

视频通话中的虚拟背景需要实时分割前景人物。VNGeneratePersonSegmentationRequest 在 A14+ 芯片上可以跑到 30fps 以上,满足了实时性要求。但要注意,Vision 的 segmentation 是基于单帧的,不会做时域一致性处理。这意味着在帧与帧之间,边缘可能会闪烁。如果需要更平滑的效果,建议在输出掩码上应用简单的时域滤波。

代码片段

// 检测人体全身姿态
import Vision

class BodyPoseDetector {
    let request = VNDetectHumanBodyPoseRequest()
    
    func detect(image: CGImage) throws -> [VNHumanBodyPoseObservation] {
        let handler = VNImageRequestHandler(cgImage: image, options: [:])
        try handler.perform([request])
        return request.results ?? []
    }
    
    func analyzePose(observation: VNHumanBodyPoseObservation) {
        // 获取各部位的关键点
        let bodyParts: [VNHumanBodyPoseObservation.JointName] = [
            .nose, .leftShoulder, .rightShoulder,
            .leftElbow, .rightElbow,
            .leftWrist, .rightWrist,
            .leftHip, .rightHip,
            .leftKnee, .rightKnee
        ]
        
        for joint in bodyParts {
            if let point = try? observation.recognizedPoint(joint) {
                print("\(joint.rawValue): (\(point.location.x), \(point.location.y)) 置信度: \(point.confidence)")
            }
        }
    }
}
// 人体分割 - 生成前景掩码
class PersonSegmenter {
    let request = VNGeneratePersonSegmentationRequest()
    
    init() {
        request.qualityLevel = .accurate  // 高质量模式
        request.outputPixelFormat = kCVPixelFormatType_OneComponent8  // 灰度掩码
    }
    
    func segment(image: CGImage) throws -> CGImage? {
        let handler = VNImageRequestHandler(cgImage: image, options: [:])
        try handler.perform([request])
        
        guard let observation = request.results?.first else { return nil }
        return try? observation.generateScaledMaskForImage(
            forInstances: observation.allInstances,
            from: handler
        )
    }
    
    // 应用虚拟背景
    func applyVirtualBackground(
        original: CGImage,
        mask: CGImage,
        background: CGImage
    ) -> CGImage? {
        // 使用 CIImage 的 blendWithMask 滤镜合成
        let originalCI = CIImage(cgImage: original)
        let maskCI = CIImage(cgImage: mask)
        let backgroundCI = CIImage(cgImage: background)
            .cropped(to: originalCI.extent)
        
        let blended = backgroundCI.applyingFilter(
            "CIBlendWithMask",
            parameters: [
                kCIInputMaskImageKey: maskCI,
                kCIInputBackgroundImageKey: originalCI
            ]
        )
        
        let context = CIContext()
        return context.createCGImage(blended, from: blended.extent)
    }
}
// 评估面部拍摄质量
func evaluateFaceQuality(image: CGImage) {
    let request = VNDetectFaceCaptureQualityRequest()
    let handler = VNImageRequestHandler(cgImage: image, options: [:])
    
    try? handler.perform([request])
    
    if let result = request.results?.first {
        print("面部拍摄质量: \(result.faceCaptureQuality)")
        // 值在 0.0 - 1.0 之间,> 0.8 为高质量
    }
}

最佳实践

Body Pose Detection 在人物距离相机太远(画面中人物高度小于画面的 1/5)时,关键点检测的精度会显著下降。如果你的 app 需要精确的姿态分析,建议先用 VNDetectHumanRectanglesRequest 检测人物边界框,过滤掉太远的人。

Person Segmentation 的 qualityLevel 有三档:.fast(低精度高速度)、.balanced(平衡)、.accurate(高精度低速度)。视频通话用 .balanced,照片编辑用 .accurate.fast 模式的边缘质量太粗糙,几乎不可用于生产环境。

还有什么值得关注

  • VNTrackHumanBodyPoseRequest 可以在视频流中追踪特定人物的姿态,避免每帧重新检测。
  • Vision 框架的请求现在支持 async/await 封装,不再需要 completion handler。
  • 人体姿态数据可以直接导出为 JSON,方便与服务端的 ML 模型配合使用。
WWDC 2021