【iOS ARKit】人脸追踪之挂载虚拟元素

        人脸跟踪(Face Tracking)是指将人脸检测扩展到视频序列,跟踪同一张人脸在视频序列中的位置。是论上讲,任何出现在视频中的人险都可以被跟踪,也即是说,在连续视频帧中检测到的人脸可以被识别为同一个人。人脸跟踪不是人脸识别的一种形式,它是根据视频序列中人脸的位置和运动推断不同视频帧中的人脸是否同一人的技术。

  • 挂载虚拟元素

      在iOS Realitykit 中,在检测到的人脸面部挂载虚拟元素的实现方式有两种:一种是通过遵循ARSesionDelegate 协议,执行 session(_ session: ARSession, didAdd anchors: LARAnchor」)方法,在获取的ARPaceAnchor 上挂载虚拟元素;另一种是与 Reality Composer结合使用。在使用第一种方式时,可以利用 ARFaceAnchor 初始化一个 AnchorEntity 类型实例,这样,ARFaceAnehor的姿态信息就可以直接被使用,典型的使用代码如下:

  public func session(_ session: ARSession, didAdd anchors: [ARAnchor]){guard let pAnchor = anchors[0] as? ARObjectAnchor else {return}let objectName =  pAnchor.referenceObject.name == "jinhua" ? "toy_drummer" : "toy_robot_vintage"DispatchQueue.main.async {do{let myModeEntity = try Entity.load(named: objectName)let objectEntity = AnchorEntity(anchor: pAnchor)objectEntity.addChild(myModeEntity)myModeEntity.playAnimation(myModeEntity.availableAnimations[0].repeat())self.arView?.scene.addAnchor(objectEntity)} catch {print("加载失败")}}}

      在检测到的人脸上挂载虚拟元素使用 RealityKit 与Reality Composer 结合的方式更方便直观,特别是需要在很多虚拟元素之间进行切换时,可以大大简化代码逻辑。使用第二种方式的操作步骤如下:

 (1) 打开 Reality Composer,并创建一个锚定到人脸的工程(Reality Composer 具体操作参阅第10章),如图5-5所示。

 (2)导入需要挂载的 USDZ 或者 Reality 模型文件并调整到参考人脸理想的位置,然后给场景命名(命名时建议使用英文字母或者英文字母与数字组合,方便在RealityKit 中调用),如图5-6所示。

(3)在Reality Composer 菜单中依次选择“文件”—“保存”(或者使用快捷键 Command+S)保存工程为FaceMask. rcproject 文件(工程名根据需要自行命名)。

(4)使用 RealityKit 加载工程文件到内存,直接获取工程文件中的锚点信息并将其作为 ARAnchor 添加到 ARVeiw.scene 场景中即可。这里需要注意的是,ARKit会在检测到人脸后自动在指定的位置挂载虚拟元素,但 ARKit 并不会自动运行人脸检测的 ARSession,因此,需要手动运行人脸检测的 ARSession 以开启人脸检测功能,典型代码如代码下:

struct FaceMaskContainer : UIViewRepresentable{func makeUIView(context: Context) -> ARView {let arView = ARView(frame: .zero)return arView}func updateUIView(_ uiView: ARView, context: Context) {guard ARFaceTrackingConfiguration.isSupported else {return}let config = ARFaceTrackingConfiguration()config.isWorldTrackingEnabled = falseconfig.providesAudioData = falseconfig.maximumNumberOfTrackedFaces =  1config.isLightEstimationEnabled = true
//        uiView.session = context.coordinatorif let faceAnchor = try? FaceMask.loadGlass1() {uiView.scene.addAnchor(faceAnchor)}uiView.session.run(config,options: [.resetTracking, .removeExistingAnchors])context.coordinator.arView = uiViewlet gesture = UISwipeGestureRecognizer()gesture.direction = [.left,.right]gesture.addTarget(context.coordinator, action: #selector(context.coordinator.changeGlass(gesture:)))uiView.addGestureRecognizer(gesture)}func makeCoordinator() -> FaceMaskContainerCoordinator {FaceMaskContainerCoordinator()}class FaceMaskContainerCoordinator: NSObject {var arView :ARView?var faceMaskCount = 0let numberOfMasks = 5@MainActor @objc func changeGlass(gesture: UISwipeGestureRecognizer){guard let arView = arView else {return}let jian = gesture.direction == .leftjian ?  (faceMaskCount -= 1) : (faceMaskCount += 1)if faceMaskCount < 0 {faceMaskCount = 5}faceMaskCount %= numberOfMasksswitch faceMaskCount {case 0:if let g = try? FaceMask.loadGlass2(){arView.scene.anchors.removeAll()arView.scene.addAnchor(g)}case 1:if let g = try? FaceMask.loadIndian() {arView.scene.anchors.removeAll()arView.scene.addAnchor(g)}case 2:if let g = try? FaceMask.loadRabbit() {arView.scene.anchors.removeAll()arView.scene.addAnchor(g)}case 3:if let g = try? FaceMask.loadHelicopterPilot() {arView.scene.anchors.removeAll()arView.scene.addAnchor(g)}case 4:if let g = try? FaceMask.loadGlass1() {arView.scene.anchors.removeAll()arView.scene.addAnchor(g)}default:break}}}}
struct  FaceCheckingContainer: UIViewRepresentable {@Binding var faceMetre: Boolfunc makeUIView(context: Context) -> ARSCNView {let arView = ARSCNView(frame: .zero)return arView}func updateUIView(_ uiView: ARSCNView, context: Context) {guard ARFaceTrackingConfiguration.isSupported else {return}if faceMetre {}let config = ARFaceTrackingConfiguration()config.isWorldTrackingEnabled = falseconfig.providesAudioData = falseconfig.maximumNumberOfTrackedFaces =  1config.isLightEstimationEnabled = trueuiView.delegate = context.coordinatoruiView.session.run(config,options: [.resetTracking, .removeExistingAnchors])}func makeCoordinator() -> FaceCheckingContainerCoordinator {FaceCheckingContainerCoordinator(self)}class FaceCheckingContainerCoordinator: NSObject, ARSessionDelegate,ARSCNViewDelegate {var parent : FaceCheckingContainerinit(_ parent: FaceCheckingContainer) {self.parent = parent}func renderer(_ renderer: SCNSceneRenderer, nodeFor anchor: ARAnchor) -> SCNNode? {guard  let device = renderer.device  else {return nil}let faceGeometry = ARSCNFaceGeometry(device: device)let node = SCNNode(geometry: faceGeometry)if parent.faceMetre {//显示图片面具let matrial = node.geometry?.firstMaterialmatrial?.diffuse.contents =  "face.scnassets/face.png"node.geometry?.firstMaterial?.fillMode = .fill}else {//显示网格node.geometry?.firstMaterial?.fillMode = .lines}return node}func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) {guard let faceanchor = anchor as? ARFaceAnchor,let facegeometry = node.geometry as? ARSCNFaceGeometry else {return}facegeometry.update(from: faceanchor.geometry)}}}

   在代码中,首先检查设备对人脸检测的支持情况,在设备支持时运行人脸检测配置开启测功能,然后加载由 Reality Composer 配置好的虚拟模型。本示例我们在 Reality Composer 中创建场景,每一个场景使用了一个虚拟元素,为方便切换不同的虚拟元素,我们使用了滑动手势控制场实现的效果如下图所示。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/647455.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ActiveMQ|01-ClassicArtemis功能介绍

接上篇-MQ消息队列主流消息服务规范及代表产品&#xff0c;ActiveMQ就是基于JMS消息服务规范的消息中间件组件&#xff0c;主要应用在分布式系统架构中&#xff0c;帮助构建高可用、 高性能、可伸缩的企业级面向消息服务的系统 本文速览&#xff1a; JMS对象模型ActiveMQ的功…

import tensorflow.contrib.slim as slim中contrib报红,显示没有导入contrib

本人环境&#xff1a; python 3.6 tensorflow 1.13 问题如下图&#xff1a; 解决方法&#xff1a; 找到包的位置&#xff0c;查看tensorflow中是否下载了contrib包&#xff0c;如果有的话&#xff0c;建议重新装一次TensorFlow 如果没有找找&#xff0c;可以在搜索栏搜一下…

【Web前端实操15】利用Grid布局完成九宫格

相关知识点&#xff1a; 创建多列 column-count 属性指定了需要分割的列数 列与列之间的间隙 column-gap 属性指定了列与列间的间隙 列边框 column-rule-style 属性指定了列与列间的边框样式 column-rule-width 属性指定了两列的边框厚度 column-rule-color 属性指定了…

【GitHub项目推荐--不错的Flutter项目】【转载】

01 可定制的图表库 FL Chart是一个高度可定制的 Flutter 图表库&#xff0c;支持折线图、条形图、饼图、散点图和雷达图 。 项目地址&#xff1a;https://github.com/imaNNeoFighT/fl_chart LineChart BarChart PieChart Sample1 Sample2 Sample3 …

哪吒汽车与经纬恒润合作升级,中央域控+区域域控将于2024年落地

近日&#xff0c;在2024哪吒汽车价值链大会上&#xff0c;哪吒汽车与经纬恒润联合宣布合作升级&#xff0c;就中央域控制器和区域域控制器展开合作&#xff0c;合作成果将在山海平台新一代车型上发布。 哪吒汽车首席技术官戴大力、经纬恒润副总裁李伟 经纬恒润在智能驾驶领域拥…

百度Apollo | 实车自动驾驶:感知、决策、执行的无缝融合

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏:《linux深造日志》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! ⛳️ 推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下…

多维时序 | Matlab实现DBO-BiLSTM蜣螂算法优化双向长短期记忆神经网络多变量时间序列预测

多维时序 | Matlab实现DBO-BiLSTM蜣螂算法优化双向长短期记忆神经网络多变量时间序列预测 目录 多维时序 | Matlab实现DBO-BiLSTM蜣螂算法优化双向长短期记忆神经网络多变量时间序列预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab实现DBO-BiLSTM多变量时间序…

Ubuntu 申请 SSL证书并搭建邮件服务器

文章目录 Log 一、域名连接到泰坦&#xff08;Titan&#xff09;电子邮件二、NameSilo Hosting 避坑三、Ubuntu 搭建邮件服务器1. 环境准备2. 域名配置3. 配置 Postfix 和 Dovecot① 安装 Nginx② 安装 Tomcat③ 申请 SSL 证书&#xff08;Lets Encrypt&#xff09;④ 配置 pos…

链表分割(新的错误:开头赋值)

1.单向链表&#xff1a;含有链表内容和下个链表的指针 2.双向链表&#xff1a;含有链表内容和上下两个链表的指针 3.带头和不带头&#xff1a;哨兵位的头结点&#xff08;不存储有效数据&#xff09;&#xff0c;主要区别在于链表为空时会存在一个哨兵位节点&#xff0c;优点…

【C#】基础巩固

最近写代码的时候各种灵感勃发&#xff0c;有了灵感&#xff0c;就该实现了&#xff0c;可是&#xff0c;实现起来有些不流畅&#xff0c;总是有这样&#xff0c;那样的卡壳&#xff0c;总结下来发现了几个问题。 1、C#基础内容不是特别牢靠&#xff0c;理解的不到位&#xff…

WebSocket实现HTML+SpringBoot聊天功能,小程序+SpringBoot聊天功能

目录 一、认识WebSocket 二、HTML实现聊天 三、微信小程序实现聊天 一、认识WebSocket 1.首先博主在初学Java时自我感觉走了很多弯路&#xff0c;因为以前见识短&#xff0c;在接触聊天功能时根本就没能想到有WebSocket这个聊天框架&#xff0c;就只能用底层的UDP或TCP实现聊…

2.Kubernetes基础-1

Kubernetes基础-1 掌握Kubernetes&#xff0c;需要我们有扎实的docker基础。 深入了解pods之前&#xff0c;我们需要&#xff1a; 应用程序已经开发并打包成Docker镜像&#xff0c;并且在Docker存储库&#xff08;如Docker Hub&#xff09;中可用&#xff0c;可下载Kubernet…

【GPU】深入理解GPU硬件架构及运行机制

深入理解GPU硬件架构及运行机制 作者&#xff1a;Tim在路上​ 曾看到有一篇名为《The evolution of a GPU: from gaming to computing》的文章。 这篇文章非常热烈的讨论了这些年GPU的进步&#xff0c;这引发了我们的一些思考: 为什么我们总说GPU比CPU要强大&#xff0c;既然…

unity学习笔记----游戏练习07

一、僵尸攻击和植物的掉血和销毁 当僵尸接触到植物开始攻击时会持续削减植物的血量&#xff0c;当植物血量为零时就销毁当前植物。 在plantManager中&#xff0c; 为植物添加一个血量HP 100&#xff0c; public int HP 100; 在写一个减少血量的方法&#xff0c;来减少血…

心理学大纲

简介 psychology&#xff0c;“psyche”(ψυχή):意为"soul"(灵魂)&#xff0c;即对我们灵魂的研究 我的学习的目的 了解人精神世界的模型&#xff0c;人格的形成]&#xff0c;作为观察分析他人内心的理论指导&#xff0c;便于我实践了解情绪的机理&#xff0c;…

Java面试题(6)

28.创建线程池有哪几种方式 newFixedThreadPool(int nThreads) &#xff1a;创建一个固定长度的线程池&#xff0c;如果有线程发生错误而结束&#xff0c; 线程池会补充一个新线程。 newCachedThreadPool() &#xff1a;创建一个可缓存的线程池&#xff0c;会自动回收和创建空…

OpenHarmony—TypeScript到ArkTS约束说明

对象的属性名必须是合法的标识符 规则&#xff1a;arkts-identifiers-as-prop-names 级别&#xff1a;错误 在ArkTS中&#xff0c;对象的属性名不能为数字或字符串。通过属性名访问类的属性&#xff0c;通过数值索引访问数组元素。 TypeScript var x { name: x, 2: 3 };c…

WWDG喂狗

3F 是0111111 40 是1000000 0X7F 127 0X5F 95 127-9532 注意:中断是在0x40,在0x40喂狗则程序不会复位 在0x5F之前喂狗会复位,减小到63以下也会复位 在0x5F与0x3F之间喂狗会继续执行,不会复位 WWDG_HandleTypeDef WWDG_Handler; //窗口看门狗句柄//初始化窗口看门狗…

项目解决方案:非执法视频监控系统项目设计方案

目 录 一、概述 &#xff08;一&#xff09;前言 &#xff08;二&#xff09;设计思路 &#xff08;三&#xff09;设计原则 1、实用性 2、可靠性 3、安全性 4、先进性 5、开放性 6、易管理、易维护 &#xff08;四&#xff09;设计依据 二、方案总…

【MySQL】阿里云服务器卸载MySQL流程

使用该命令查询当前安装的MySQL rpm -qa | grep mysql使用rpm -ev接上相应名称删除这些项目&#xff0c;推荐从下往上逐个卸载 接下来使用find / -name mysql查询系统内剩余的MySQL文件 最后使用rm -rf接对应文件目录删除 收尾再次使用find / -name mysql查询&#xff0c;No…