当前位置: 首页 > news >正文

(十二)深入了解AVFoundation-采集:人脸识别与元数据处理

(一)深入了解AVFoundation:框架概述与核心模块解析-CSDN博客

(二) 深入了解AVFoundation - 播放:AVFoundation 播放基础入门-CSDN博客

(三)深入了解AVFoundation-播放:AVPlayer 进阶 播放状态 & 进度监听全解析_avplayer 播放状态-CSDN博客

(四)深入理解AVFoundation-播放:高度自定义视频播放器 UI-CSDN博客

(五)深入了解AVFoundation-播放:多音轨、字幕、倍速播放与横竖屏切换-CSDN博客

(六)深入了解AVFoundation-播放:AirPlay、画中画后台播放_air.av-CSDN博客

(七)深入了解AVFoundation-采集:采集系统架构与 AVCaptureSession 全面梳理_avcapturesession startrunning子线程调用-CSDN博客

(八)深入了解AVFoundation-采集:拍照功能的实现_ios avcapturephotooutput-CSDN博客

(九)深入了解AVFoundation-采集:拍照 摄像头切换、拍照参数和照片数据EXIF 信息-CSDN博客

(十)深入了解AVFoundation-采集:录制视频功能的实现-CSDN博客

(十一)深入了解AVFoundation-采集:二维码识别-CSDN博客

(十二)深入了解AVFoundation-采集:人脸识别与元数据处理-CSDN博客

引言

在 AVFoundation 的采集体系中,元数据输出(AVCaptureMetadataOutput)不仅可用于识别二维码等图像信息,也支持对特定对象的实时检测与追踪,其中就包括人脸识别功能。与二维码扫描相比,人脸识别在逻辑处理和 UI 显示方面更具互动性和复杂性,也更贴近实际产品需求,如人脸识别登录、镜头跟踪拍摄、美颜滤镜等功能。

本篇将基于前文二维码采集的基础,深入讲解如何利用 AVFoundation 实现人脸的实时识别、坐标转换、识别框绘制与多人追踪。我们将粗略概括重复的输入与权限设置,聚焦在 元数据处理的核心逻辑 和 UI 动态响应机制,帮助你构建一个功能清晰、体验流畅的人脸识别系统。

配置回顾:输入与输出设置

在本节中,我们简要回顾用于人脸识别的输入与输出配置流程。由于人脸识别同样基于 AVCaptureMetadataOutput,因此整体结构与二维码扫描的配置几乎一致。我们无需重复搭建会话、添加输入等流程,只需在输出中指定不同的元数据类型即可完成切换。

下面我们快速回顾相关代码配置,并重点指出区别所在。

输入

输入部分与二维码识别完全相同。我们使用设备的摄像头作为输入源,添加到会话中用于实时视频采集:

import UIKit
import AVFoundationclass PHCaptureFaceController: NSObject,AVCaptureMetadataOutputObjectsDelegate {/// 会话let session = AVCaptureSession()/// 输出private let metadataOutput = AVCaptureMetadataOutput()/// 输入private var captureDeviceInput: AVCaptureDeviceInput?/// 队列private let sessionQueue = DispatchQueue(label: "com.example.captureSession")/// 代理weak var delegate: PHCaptureProtocol?/// 配置会话func setupConfigureSession() {session.beginConfiguration()// 1.设置会话预设setupSessionPreset()// 2.设置会话输入if !setupSessionInput(device: self.getDefaultCameraDevice()) {delegate?.captureError(NSError(domain: "PHCaptureQRController", code: 1001, userInfo: [NSLocalizedDescriptionKey: "Failed to add input"]))return}// 3.设置会话输出if !setupSessionOutput() {delegate?.captureError(NSError(domain: "PHCaptureQRController", code: 1002, userInfo: [NSLocalizedDescriptionKey: "Failed to add output"]))return}session.commitConfiguration()}/// 设置会话话预设private func setupSessionPreset() {session.sessionPreset = .photo}/// 设置会话输入private func setupSessionInput(device: AVCaptureDevice? = nil) -> Bool {// 1.获取摄像头guard let device = device else { return false }do {captureDeviceInput = try AVCaptureDeviceInput(device: device)if session.canAddInput(captureDeviceInput!) {session.addInput(captureDeviceInput!)} else {return false}} catch {delegate?.captureError(error)return false}return true}/// 设置会话输出private func setupSessionOutput() -> Bool {}/// 启动会话func startSession() {sessionQueue.async {if !self.session.isRunning {self.session.startRunning()}}}/// 停止会话func stopSession() {sessionQueue.async {if self.session.isRunning {self.session.stopRunning()}}}//MARK: - AVCaptureMetadataOutputObjectsDelegatefunc metadataOutput(_ output: AVCaptureMetadataOutput,didOutput metadataObjects: [AVMetadataObject],from connection: AVCaptureConnection) {delegate?.captureFace(metadataObjects)}/// 获取默认摄像头private func getDefaultCameraDevice() -> AVCaptureDevice? {return getCameraDevice(position: .back)}/// 获取指定摄像头private func getCameraDevice(position: AVCaptureDevice.Position) -> AVCaptureDevice? {let devices = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: .video, position: position).devicesreturn devices.first}}

输出配置

输出依然使用 AVCaptureMetadataOutput,但这里我们将 metadataObjectTypes 设置为人脸识别类型 .face。

    /// 设置会话输出private func setupSessionOutput() -> Bool {if session.canAddOutput(metadataOutput) {session.addOutput(metadataOutput)metadataOutput.metadataObjectTypes = [.face]// 设置 代理及输出队列metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)} else {return false}return true}

在设置完成后,只要摄像头画面中检测到人脸,系统就会将人脸对象作为 AVMetadataFaceObject 回调到代理方法中,供后续处理。

元数据处理核心逻辑

关于这部分的内容我们分成三个小结来介绍一下:

  • 实现代理方法与人脸识别回调。
  • 坐标准话与画面映射。
  • 绘制人脸框与多人识别支持。

实现代理方法与人脸识别回调

同样我们实现 AVCaptureMetadataOutputObjectsDelegate 中定义的代理方法,将识别到的元数据传递到视图控制来处理。

    //MARK: - AVCaptureMetadataOutputObjectsDelegatefunc metadataOutput(_ output: AVCaptureMetadataOutput,didOutput metadataObjects: [AVMetadataObject],from connection: AVCaptureConnection) {delegate?.captureFace(metadataObjects)}

在 captureFace() 方法中,我们可以读取到人脸信息包括人脸所在的区域以及人脸id:

坐标转换与画面映射

在二维码识别中,我们已经进行过了一次坐标转换,同样在获取到人脸元数据对象后,我们也需要进行坐标转换,将人脸在摄像头图像中的位置坐标,准确映射到实际的 UI 预览图层中,用于绘制人脸框或进行其他界面响应。

AVFoundation 中使用的是摄像头原始坐标系(以图像像素为基础,左上角为 (0,0),右下为 (1,1) 的比例坐标),而我们在界面上使用的却是 UIKit 的坐标系,因此需要进行一次坐标系转换

AVCaptureVideoPreviewLayer 提供了现成的方法来进行这一转换:

            if let faceObject = face as? AVMetadataFaceObject {// 获取人脸的矩形区域let transformedMetadataObject = previewLayer.transformedMetadataObject(for: faceObject)if let transformedFace = previewLayer.transformedMetadataObject(for: faceObject) {// transformedFace.bounds 就是可以直接用于绘图的 CGRect(相对于界面的坐标系)let faceFrame = transformedFace.bounds// 后续用于添加 UIView 或 CAShapeLayerdrawFaceBoundingBox(in: faceFrame)}}

绘制人脸框与多人识别支持

将人脸元数据转换为 UI 坐标后,我们可以将其用于实际的界面反馈,例如在人脸区域绘制可视化边框,提升识别体验。由于摄像头中可能出现多个面孔,绘制逻辑需要支持动态增减人脸框,并根据系统识别结果不断更新。

创建与更新人脸框

每一个被识别到的人脸对象都包含一个唯一的 faceID,我们可以用它作为字典的 Key,将其与对应的 CALayer一一对应。

以下是一个标准的绘制流程:

  1. 遍历所有识别到的人脸;
  2. 对每个 faceID 判断是否已有对应图层,没有则创建;
  3. 更新图层的 frame 与角度;
  4. 对丢失的人脸进行清除。
func didDetectFaces(_ faces: [AVMetadataFaceObject]) {let transformedFaces = faces.compactMap { face inreturn previewLayer.transformedMetadataObject(for: face) as? AVMetadataFaceObject}var lostFaceIDs = Set(faceLayers.keys)for face in transformedFaces {let faceID = face.faceIDlostFaceIDs.remove(faceID)let layer: CALayerif let existingLayer = faceLayers[faceID] {layer = existingLayer} else {layer = makeFaceLayer()overlayLayer.addSublayer(layer)faceLayers[faceID] = layer}layer.transform = CATransform3DIdentitylayer.frame = face.boundsif face.hasRollAngle {let rollTransform = transformForRollAngle(face.rollAngle)layer.transform = CATransform3DConcat(layer.transform, rollTransform)}if face.hasYawAngle {let yawTransform = transformForYawAngle(face.yawAngle)layer.transform = CATransform3DConcat(layer.transform, yawTransform)}}for faceID in lostFaceIDs {faceLayers[faceID]?.removeFromSuperlayer()faceLayers.removeValue(forKey: faceID)}
}

图层样式与角度旋转

我们可以使用 CALayer 来绘制矩形边框,并通过角度信息使其旋转对齐面部朝向。

func makeFaceLayer() -> CALayer {let layer = CALayer()layer.borderColor = UIColor.red.cgColorlayer.borderWidth = 2.0layer.cornerRadius = 4.0return layer
}

人脸元数据中的 rollAngle 表示绕 Z 轴(平面内)旋转,而 yawAngle 表示绕 Y 轴(前后方向)旋转:

func transformForRollAngle(_ degrees: CGFloat) -> CATransform3D {let radians = degrees * .pi / 180.0return CATransform3DMakeRotation(radians, 0.0, 0.0, 1.0)
}func transformForYawAngle(_ degrees: CGFloat) -> CATransform3D {let radians = degrees * .pi / 180.0let yawTransform = CATransform3DMakeRotation(radians, 0.0, -1.0, 0.0)return CATransform3DConcat(yawTransform, orientationTransform())
}func orientationTransform() -> CATransform3D {let orientation = UIDevice.current.orientationlet angle: CGFloatswitch orientation {case .landscapeLeft:angle = .pi / 2case .landscapeRight:angle = -.pi / 2case .portraitUpsideDown:angle = .pidefault:angle = 0}return CATransform3DMakeRotation(angle, 0.0, 0.0, 1.0)
}

支持多人识别与人脸移除

在每一帧中,我们根据当前返回的面孔数组来判断有哪些 faceID 不再出现,从而动态移除对应的图层。这样既保持了界面的同步性,也避免了残留 UI 的问题。

结语

本篇我们聚焦于 AVFoundation 中人脸识别的实现方式,从元数据输出类型的设置出发,详细讲解了识别流程、坐标转换,以及如何支持多人识别与人脸框绘制。借助系统提供的 AVMetadataFaceObject,我们可以较为轻松地将摄像头中的面孔在界面上实时呈现,为人脸相关的 UI 效果打下基础。

尽管 AVFoundation 的人脸识别功能较为基础,但对于实时展示、面部 UI 跟随等需求已经足够。更复杂的面部关键点检测、情绪识别等功能,则可以结合 Vision 框架进一步拓展,我们将在后续章节中继续探索。

http://www.xdnf.cn/news/346321.html

相关文章:

  • gitee推送更新失败问题记录:remote: error: hook declined to update refs/heads/master
  • 代码随想录第38天:动态规划11(编辑距离)
  • Babylon.js学习之路《一、初识 Babylon.js:什么是 3D 开发与 WebGL 的完美结合?》
  • JavaScript中数组和对象不同遍历方法的顺序规则
  • 使用chrome浏览器截长图
  • 端口转发与跨域处理
  • 电商平台的流量秘密:代理IP在用户行为分析中的角色
  • WordPress插件:WPJAM Basic优化设置
  • HPE Primera 600 全闪存阵列,添加控制器教程!
  • DBeaver查询PostgreSQL的只读模式
  • RocketMQ的事务消息机制
  • 云平台搭建
  • SATA SSD 与 NVMe PCIe SSD 性能差距有多大?
  • python中的数据封装
  • 【银河麒麟高级服务器操作系统】服务器外挂存储ioerror分析及处理分享
  • vue中操作dom,实现元素的拖拉拽
  • 网络基础入门第6-7集(抓包技术)
  • PHM领域的两个阶段:状态监测与故障诊断
  • SAM详解2.1(好题1)
  • Azure Databricks:数据创新与智能决策的云端利器
  • 生成数论:三生原理与中国数学的多点突破态势?
  • 基础 Python 编程的部分公式和概念总结
  • sherpa:介绍
  • LeetCode:翻转二叉树
  • DLMS协议 —— System title 详解(作用及结构一览)
  • C——操作符详解
  • 广州AI数字人:从“虚拟”走向“现实”的变革力量
  • HOW - 在 Mac 上的 Chrome 浏览器中调试 Windows 场景下的前端页面
  • 《React Native热更新实战:用Pushy打造无缝升级体验》
  • systemd vs crontab:Linux 自动化运行系统的全面对比