(十二)深入了解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.pswp.cn/web/79466.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/79466.shtml
英文地址,請注明出處:http://en.pswp.cn/web/79466.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Kafka 與 RabbitMQ、RocketMQ 有何不同?

一、不同的誕生背景,塑造了不同的“性格” 名稱 背景與目標 產品定位 Kafka 為了解決 LinkedIn 的日志收集瓶頸,強調吞吐與持久化 更像一個“可持久化的分布式日志系統” RabbitMQ 出自金融通信協議 AMQP 的實現,強調協議標準與廣泛適…

配置 Web 服務器練習

一、要求 1.通過https://ip 可以訪問到網站首頁 2.通過 https://ip/private/ 實現用戶訪問控制,僅允許已經添加的 tom,jerry 能夠訪問到 private 子路徑的界面 3.通過 https://ip/vrit/ 實現能夠訪問到將系統 /nginx/virt 目錄下的網頁文件&#xff0…

MySQL索引詳解(下)(SQL性能分析,索引使用)

索引是MySQL性能優化的核心,但如何精準分析查詢瓶頸、合理設計索引,是開發者必須掌握的技能。本文結合實戰案例,系統講解SQL性能分析工具鏈與索引使用技巧,幫助讀者構建高性能數據庫系統。 一、SQL性能分析:從宏觀到微…

招行數字金融挑戰賽數據賽道賽題一

賽題描述:根據提供的用戶行為數據,選手需要分析用戶行為特征與廣告內容的匹配關系,準確預測用戶對測試集廣告的點擊情況,通過AUC計算得分。 得分0.6120,排名60。 嘗試了很多模型都沒有能夠提升效果,好奇大…

ORB-SLAM3和VINS-MONO的對比

直接給總結,整體上orbslam3(僅考慮帶imu)在初始化階段是松耦合,localmap和全局地圖優化是緊耦合。而vins mono則是全程緊耦合。然后兩者最大的區別就在于vins mono其實沒有對地圖點進行優化,為了輕量化,它一…

安裝typescript時,npm install -g typescript報錯

刪除C:\Users\用戶\下的.npmrc文件,如果你的沒有,看是不是因為將隱藏的項目勾選上了,然后去掉勾選。 重新輸入

[GESP202503 四級] 二階矩陣c++

題目描述 小 A 有一個 n 行 m 列的矩陣 A。 小 A 認為一個 22 的矩陣 D 是好的,當且僅當 。其中 表示矩陣 D 的第 i 行第 j 列的元素。 小 A 想知道 A 中有多少個好的子矩陣。 輸入 第一行,兩個正整數 n,m。 接下來 n 行,每行 m 個整數…

基于flask+pandas+csv的報表實現

基于大模型根據提示詞去寫SQL執行SQL返回結果輸出報表技術上可行的,但為啥還要基于pandas去實現呢? 原因有以下幾點: 1、大模型無法滿足實時性輸出報表的需求; 2、使用大模型比較適合數據量比較大的場景,大模型主要…

Java學習筆記(對象)

一、對象本質 狀態(State):通過成員變量(Field)描述 行為(Behavior):通過成員方法(Method)實現 class Person {String name;int age;void eat() {System.o…

Qt學習Day0:Qt簡介

0. 關于Qt Qt是C的實踐課,之前在C中學習的語法可以有具體的應用場景。Qt的代碼量很大,不要死記硬背,學會查詢文檔的能力更加重要。 建議提升一下相關單詞的儲備量: 1. Qt是什么? Qt是一個基于C語言的圖形用戶界面&a…

React知識框架

一、核心概念 1. 組件化開發 核心思想:將 UI 拆分為獨立、可復用的組件(函數組件/類組件)。組件特性:props(接收參數)、state(組件狀態)、生命周期(類組件特有&#xf…

Django之賬號登錄及權限管理

賬號登錄及權限管理 目錄 1.登錄功能 2.退出登錄 3.權限管理 4.代碼展示合集 這篇文章, 會講到如何實現賬號登錄。賬號就是我們上一篇文章寫的賬號管理功能, 就使用那里面已經創建好的賬號。這一次登錄, 我們分為三種角色, 分別是員工, 領導, 管理員。不同的角色, 登錄進去…

[學習]RTKLib詳解:convkml.c、convrnx.c與geoid.c

本文是 RTKLlib詳解 系列文章的一篇,目前該系列文章還在持續總結寫作中,以發表的如下,有興趣的可以翻閱。 [學習] RTKlib詳解:功能、工具與源碼結構解析 [學習]RTKLib詳解:pntpos.c與postpos.c [學習]RTKLib詳解&…

java 破解aspose.words 18.6 使用

資源包&#xff1a;https://download.csdn.net/download/qq_36598111/90787167 jar包是破解過的&#xff0c;直接可以使用。 引入jar&#xff0c;要引入本地的&#xff0c;不要直接引入倉庫的 <dependency><groupId>com.aspose</groupId><artifactId>…

vue使用rules實現表單校驗——校驗用戶名和密碼

編寫校驗規則 常規校驗 const rules {username: [{ required: true, message: 請輸入用戶名, trigger: blur },{ min: 5, max: 16, message: 長度在 5 到 16 個字符, trigger: blur }],password: [{ required: true, message: 請輸入密碼, trigger: blur },{ min: 5, max: 1…

寶塔服務安裝使用的保姆級教程

寶塔介紹&#xff1a; 寶塔面板&#xff08;BT Panel&#xff09; 是一款 國產的服務器運維管理面板&#xff0c;主要用于簡化 Linux/Windows 服務器的網站、數據庫、FTP、防火墻等管理操作。它通過圖形化界面&#xff08;Web端&#xff09;和命令行工具&#xff08;bt 命令&a…

數字化轉型-4A架構之數據架構

4A架構系列文章 數字化轉型-4A架構&#xff08;業務架構、應用架構、數據架構、技術架構&#xff09; 數字化轉型-4A架構之業務架構 數字化轉型-4A架構之應用架構 數字化轉型-4A架構之數據架構 數字化轉型-4A架構之技術架構 數據架構 Data Architecture&#xff08;DA&…

每日腳本 5.11 - 進制轉換和ascii字符

前置知識 python中各個進制的開頭 二進制 &#xff1a; 0b 八進制 &#xff1a; 0o 十六進制 : 0x 進制轉換函數 &#xff1a; bin() 轉為2進制 oct() 轉換為八進制的函數 hex() 轉換為16進制的函數 ascii碼和字符之間的轉換 &#xff1a; chr(97) 碼轉為字符 …

Vulnhub Lazysysadmin靶機攻擊實戰(一)

導語 ??靶機下載地址 https://download.vulnhub.com/lazysysadmin/Lazysysadmin.zip ??靶機信息地址 https://www.vulnhub.com/entry/lazysysadmin-1,205/ 文章目錄 信息收集掃描路徑提權其他思路探索其他方式找密碼總結下載安裝好靶機之后啟動虛擬機如下所示。 信息收集 我…

【DB2】DB2啟動失敗報錯SQL1042C

在本地某次啟動db2時報錯SQL1042C&#xff0c;具體報錯如下 [db2inst1standby ~]$ db2start 05/07/2025 16:32:53 0 0 SQL1042C An unexpected system error occurred. SQL1032N No start database manager command was issued. SQLSTATE57019在網上百度到說是需要…