【iOS ARKit】2D肢体动作捕捉

       人体肢体动作捕捉在动漫影视制作、游戏CG 动画、实时模型驱动中有着广泛的应用,利用 ARKit,无须额外的硬件设备即可实现 2D和3D人体一系列关节和骨骼的动态捕捉,由于移动AR 的便携性及低成本,必将促进相关产业的发展。

ARBody TrackingConfiguration

      ARKit 配置类 ARBodyTrackingConfiguration 专用于 2D、3D人体肢体检测捕捉,同时,该配置类也可以设置实现 2D 图像检测和平面检测,构建对现实环境的跟踪。为更真实地渲染虚拟元素,ARBodyTrackingConfiguration 还支持 HDR(High Dynamic Range Imaging,高动态范围成像)环境反射功能。其主要属性如下表所示。

属性名

描述

automaticSkeletonScaleEstimationEnabled

布尔值,指定 ARKit是否进行人体骨骼尺寸评估,设置为true 时,ARKit会根据人体距离摄像头的远近调整所驱动的模型大小,使其更匹配

isAutoFocusEnabled

设置是否自动对焦

planeDetection

在进行人体肢体检测跟踪时是否进行平面检测,可以设置为水平(horizontal)或者垂直(vertical),或者两者都设置。设置该值后就会启动平面检测功能

automaticImageScaleEstimationEnabled

自动评估检测到的2D图像的尺寸,这在设置2D 图像跟踪时有效

detectionImages

参考图像库

maximum NumberOfTrackedImages

最大可同时跟踪的2D 图像数量

wantsHDREnvironment Textures

是否使用HDR 环境纹理反射,使用后渲染的虚拟元素更真实

environment Texturing

环境纹理来源,可设置为自动(automatic)、手动(manual)、无(none)三者之一,当设置为手动时,需要提供环境纹理图

      通常,在实现人体肢体检测和人形遮挡功能时,还需要设置 frameSemantics 语义属性,使用ARBoodyTrackingConfiguration 配置类进行人体肢体检测和动作捕捉时,frameSemantics 语义属性值只能设置 bodyDetection(默认值)。frameSemantics 语义属性中 bodyDetection 用于肢体检测跟踪,后两个用于人形遮挡,personSegmentation现实屏幕空间的人形分离,而 personSegmentation WithDepth则是带有深度信息的人形分离。

2D人体姿态估计

      在ARKit 中,2D人体姿态估计是指对摄像头采集的视频图像中人像在屏幕空间中的姿态进行估计,通常使用人体骨骼关节点来描述人体姿态。近年来,随着深度学习技术的发展,人体骨骼关节点检测效率与效果不断提升,已经开始广泛应用于计算机视觉的相关领域。2D人体姿态检测估计在视频安防、动作分类、行为检测、人机交互、体育科学中有着广阔的应用前景。

人体骨骼关节点检测

     人体骨骼关节点检测(Pose Estimation)主要检测人体的一些关键节点,如关节、头部、手掌等,通过关节点描述人体骨骼及姿态信息。人体骨骼关节点检测在计算机视觉人体姿态检测相关领域的研究中起到了基础性的作用,是智能视频监控、病人监护系统、人机交互、虚拟现实、智能家居、智能安防、运动员辅助训练等应用的基础性算法。

      在实际应用中,由于人体具有相当的柔性,会出现各种姿态和形状,人体任何一个部位的微小变化都会产生一种新的姿态,同时其关节点的可见性受穿着、姿态、视角等影响非常大,而且还受到光照、遮挡等环境影响。除此之外,2D人体关节点和3D人体关节点在视觉上会有明显的差异,身体不同部位都会有视觉上的缩短效应(Fore Shortening),使得人体骨骼关节点检测成为计算机视觉领域中一个极具挑战性的课题。

使用2D 人体姿态估计

     在 ARKit 中,我们不必关心底层的人体骨骼关节点检测算法,也不必自己去调用这些算法,在运行使用ARBodyTrackingConfiguration 配置的ARSession 之后,基于摄像头图像的2D人体姿态估计任务就会启动。

      2D人体姿态检测基于屏幕空间,获取的人体姿态信息没有深度值。在 ARKit 检测到屏幕空间中的人形后,可以通过 ARFrame. detectedBody 获取一个 ARBody2D 对象,也就是说 ARKit 目前对屏幕空间中的2D人体,只支持单个人形检测。ARBody2D对象描述了检测到的人形结构信息,其结构如下图所示。

     通过图可以看到,在使用 session(_ session: ARSession,didUpdate frame: ARFrame)方法获取ARFrame 中表示 2D人体的 ARBody2D 对象后,就可以使用其 skeleton. jointLandmarks 获取所有关节点位置信息,也可以通过其 skeleton. definition.jointNames 获取所有关节点名称。jointLandmarks 是一个包含所有关节点位置信息的数组,我们可以通过索引值检索某个关节点的位置,也可以通过 skeleton.landmark(for: ARSkeleton. JointName(rawValue: jointName))方法取指定关节点名称的位置信息。

     2D人体姿态估计是在屏幕空间中对摄像头采集的图像进行逐帧分析,解算出的关节点位置也是在屏幕空间中的归一化坐标,以屏幕左上角(0,0)右下角为(1,1),如下图所示。

    为了描述人体骨骼关节点,ARKit 新建了一个 ARSkeleton 类,该类包含一个人体关节点(Joint)集合及关节之间关系的定义,该类预定义了8个关节点,分别是 head、 leftFoot、 left Hand、 leftShoulder.hannnt riahtHand.rightShoulder、root.这是在应用开发中使用最多的关节点,2D和3D人体肢体都包含这些关节点,因此我们可以通过这些预定义的节点名字快速找到骨骼节点位置。ARSkeleton 类是ARSkeleton2D 和 ARSkeleton3D类的父类。

      ARSkeleton2D 类继承自 ARSkeleton,其 jointLandmarks 包含了所有2D关节点的位置信息,也可以通过该类的landmark(forJointNamed:)方法获取某个名字关节点的位置,此方法需要传递关节点的原始名称(rawValue)而不是 ARSkeleton 预定义的关节点名(预定义关节点名可以通过其.rawValue 获取原始名称)。jointLandmarks 是 simd_float2 类型数组,因此我们也可以直接通过下标获取特定的关节点位置信息,下标方法取值比使用 landmark(forJointNamed:)快得多,特别是对每帧都要执行的循环操作,可以节省很多时间。获取特定节点名称的索引值可以通过 definition.index(for:)方法实现。除此之外,还可以通过 ARSkeleton2D的isJointTracked(_:)方法查询每一个关节点在当前帧的检测跟踪情况,还可以获取每一个节点的父节点。

骨骼关节点名称

索引

父节点名称

索引

invalid

-1

head_ joint

0

neck_1 joint

1

neck_ 1_joint

1

root

16

right_ shoulder_1 _joint

2

neck_1_joint

1

right_ forearm_joint

3

right_shoulder_1_joint

2

right_hand _joint

4

right_ forearm_joint

3

left_shoulder_1_joint

5

neck_1 _joint

1

left_forearm_joint

6

5

left_hand joint

7

left forearm_joint

6

right_upLeg_joint

8

root

16

right_leg joint

9

right_upLeg_joint

8

right_foot_ joint

10

right_leg joint

9

left_ upLeg_joint

11

root

16

left_leg joint

12

left_upLeg_joint

11

left_foot joint

13

left_leg joint

12

right_eye joint

14

head _joint

0

left_eye_joint

15

head_joint

0

root

16

Invalid

-1

right_ear_joint

17

right_eye joint

14

left-ear- joint

18

left_eye_joint

15

     ARKit 2D 人体骨骼关节点定义及它们之间的关联关系如上表所示,通过表可以看到,在ARKit 中,检测到的2D人体共包含19个关节点(root 节点代表了整个 ARBody2D 对象,不计算在内时包含18个关节点),这些关节点相互之间有很强的相关性,存在紧密的父子连接关系,通过节点之间的相互关系,就可以画出各骨骼节点之间的连结图。

     下面演示利用 ARKit 检测到的2D人体骨骼关节点信息,将每一个关节点用一个圆圈标示出来,具体代码如下

//
//  BodyTrackingView.swift
//  ARKitDeamo
//
//  Created by zhaoquan du on 2024/2/1.
//

import SwiftUI
import ARKit
import RealityKit


struct BodyTrackingView: View {
    var body: some View {
        BodyTrackingViewContainer().edgesIgnoringSafeArea(.all).navigationTitle("人体骨架2D检测")
    }
}

struct BodyTrackingViewContainer:UIViewRepresentable {
   
    
    
    func makeUIView(context: Context) ->ARView {
        let arView = ARView(frame: .zero)
        return arView
    }
    
    func updateUIView(_ uiView: UIViewType, context: Context) {
        
        guard ARBodyTrackingConfiguration.isSupported else {
            return
        }
        
        context.coordinator.arView = uiView
        let config = ARBodyTrackingConfiguration()
        
        config.frameSemantics = .bodyDetection
        config.automaticSkeletonScaleEstimationEnabled = true
        
        uiView.session.delegate = context.coordinator
        
        uiView.session.run(config)
        
        
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator()
    }
    
    class Coordinator: NSObject,ARSessionDelegate {
        var arView : ARView? = nil
        let circleWidth: CGFloat = 10
        let circleHeight: CGFloat = 10
        var isPrinted = false
        func session(_ session: ARSession, didUpdate frame: ARFrame) {
            guard let arView = arView else {
                return
            }
            //清除骨骼圆圈
            arView.layer.sublayers?.compactMap({
                $0 as? CAShapeLayer
            }).forEach({
                $0.removeFromSuperlayer()
            })
            guard let detectedBody =  frame.detectedBody else {
                return
            }
            
            guard let orientation = arView.window?.windowScene?.interfaceOrientation else {
                return
            }
            let transform = frame.displayTransform(for: orientation, viewportSize: arView.frame.size)
            
            detectedBody.skeleton.jointLandmarks.forEach { landmark in
                let normalizeCenter = CGPoint(x: CGFloat(landmark.x), y: CGFloat(landmark.y)).applying(transform)
                let center = normalizeCenter.applying(.identity.scaledBy(x: arView.frame.width, y: arView.frame.height))
                
                let rect = CGRect(x: center.x - circleWidth/2, y: center.y - circleWidth/2, width: circleWidth, height: circleHeight)
                
                let circleLayer = CAShapeLayer()
                
                circleLayer.path = UIBezierPath(ovalIn: rect).cgPath
                
                arView.layer.addSublayer(circleLayer)
                
            }
            
            if !isPrinted {
                let jointNames = detectedBody.skeleton.definition.jointNames
                for name in jointNames {
                    let landmark = detectedBody.skeleton.landmark(for: ARSkeleton.JointName(rawValue: name))
                    let index = detectedBody.skeleton.definition.index(for: ARSkeleton.JointName(rawValue: name))
                    
                    print("\(name),\(String(describing: landmark)),the index is \(index) parent index is  \(detectedBody.skeleton.definition.parentIndices[index])")
                }
                print("last: \(ARSkeleton2D.JointName.rightShoulder.rawValue)")
                isPrinted = true
            }
            
            
        }
        
    }
    
    
    
    
}

      代码中实现的主要功能是在每一个检测到的2D人体关节点位置画一个圆圈,效果如图所示。

     ​​​​​代码很多语句都是执行画图操作,但也演示了 ARKit 2D 人体检测使用的几个重要功能:

  (1)演示了如何获取屏幕空间中的 ARBody2D对象,为确保代码在没有检测到2D人体时也能正确执行,我们使用了 guard 语句。

  (2)演示了如何获取2D 人体所有骨骼关节点名字集合,以及各关节点索引及其父节点索引。

  (3)演示了如何利用关节点名字获取该关节点在屏幕空间中的位置信息。

    如前所述,使用索引值获取特定的关节点位置信息比使用关节点名字快得多,代码清演示了利用关节点名字获取对应索引值,在实际开发中,可以直接使用前表中各关节点的索引值以提高性能。

具体代码地址:GitHub - duzhaoquan/ARkitDemo

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

图片热区功能

一、需求描述及效果图 1.需求描述: 根据后端返回的坐标及人员信息,在图片上的相应位置添加图片热区功能,点击可展示出对应的人员信息。 图片可进行缩放 2.示例: (定位是随便写的,仅做示例) …

【Algorithms 4】算法(第4版)学习笔记 03 - 1.3 背包、队列和栈

文章目录 前言参考目录学习笔记0:预热1:栈1.1:栈的链表实现1.1.1 代码实现1.2:栈的数组实现1.2.1:定容栈1.2.2:可调整大小数组1.2.3:代码实现1.3:链表与数组的取舍2:队列…

MySQL原理(一)架构组成之逻辑模块(1)组成

总的来说,MySQL可以看成是二层架构,第一层我们通常叫做SQL Layer,在MySQL数据库系统处理底层数据之前的所有工作都是在这一层完成的,包括权限判断,sql解析,执行计划优化,query cache的处理等等&…

算法——A/算法通识

目录 一、复杂度分析 A/时间复杂度 B/空间复杂度 C/分析技巧 二、枚举分析 A/枚举算法介绍 B/解空间的类型 C/循环枚举解空间 三、模拟算法 四、递归 A/递归介绍 递归的两个关键要素: B/递归如何实现 C/递归和循环的比较 一、复杂度分析 A/时间复杂度…

AVL树

文章目录 AVL树平衡因子 AVL树结点的定义AVL树类和函数接口AVL树插入元素最小不平衡子树旋转 AVL树的验证参考源码 AVL树是对普通二叉搜索树的一种优化。当二叉搜索树插入的元素是有序的时候或者接近有序的时候,二叉搜索树的性能会大大降低。二叉搜索树可能会变成一…

中二少年工具箱(PC端)简介

同学们可以私信我加入学习群! 正文开始 简介一、功能模块1.node版本管理工具 总结 简介 中二少年开发的中二少年工具箱,相信博主,功能不孬。 辅助自己开发工作,帮助新人快速入门,提供交互式文档辅助学习……如果还不…

LDRA Testbed软件静态分析_Jenkins持续集成_(2)配置邮件自动发送静态分析结果

系列文章目录 LDRA Testbed软件静态分析_操作指南 LDRA Testbed软件静态分析_自动提取静态分析数据生成文档 LDRA Testbed软件静态分析_Jenkins持续集成_(1)自动进行静态分析的环境搭建 LDRA Testbed软件静态分析_Jenkins持续集成_(2)配置邮件自动发送静态分析结果 LDRA Testb…

arcgis自定义dem高程实现地形抬高 - 操作矢量,转tin、adf(tif),cesiumlab切高程服务

这次记录分享一下arcgis自定义高程全过程 /(ㄒoㄒ)/~~ 我的场景:前端实现地面抬高效果 自定义高程实现地形抬高 一、数据处理 - arcgis操作矢量1、准备工作(可选)2、绘制外围矢量(可选)3、操作矢量数据 二、创建tin - …

opencvb 十七 使用cmake配置opencv c++项目

1、cmake简介 1.1 cmake是什么 CMake是一个开源、跨平台的编译(Build)工具,是用来构建、测试和打包软件的。它能够用简单的语句来描述所有平台的编译过程。它能够输出各种各样的makefile或者project文件,能测试编译器所支持的C特…

记录一次k8s集群镜像恢复到harbor的过程

之前由于harbor的存储空间不够了,同事干掉了好多镜像,结果把现网生产的镜像也搞掉了。进行了找回操作,这里做下记录。 环境是k8s集群,容器引擎用的containerd。 最初发现这个问题是在增加节点的时候,发现有的节点主机…

【DPI(Direct Programming Interface)_2024.02.01】

DPI接口:实现SV与C的交互 ① DPI_svc test.sv文件: 从C import task/function到SV 从SV export task到C 利用DPI调用C code访问register test.c文件: C调用apb_write驱动 ② dpi_perl test.sv文件: 利用DPI调用c code间接调…

CKS1.28【1】kube-bench 修复不安全项

Context 针对 kubeadm 创建的 cluster 运行 CIS 基准测试工具时,发现了多个必须立即解决的问题。 Task 通过配置修复所有问题并重新启动受影响的组件以确保新的设置生效。 修复针对 API 服务器发现的所有以下违规行为: 1.2.7 Ensure that the --authoriz…

【华为】GRE Over IPsec 实验配置

【思科】GRE Over IPsec 实验配置 前言报文格式 实验需求配置拓扑GRE配置步骤IPsec 配置步骤R1基础配置GRE 配置IPsec 配置 ISP_R2基础配置 R3基础配置GRE 配置IPsec 配置 PCPC1PC2 抓包检查OSPF建立GRE隧道建立IPsec 隧道建立Ping 配置文档 前言 GRE over IPSec可利用GRE和IP…

echarts条形图添加滚动条

效果展示: 测试数据: taskList:[{majorDeptName:测试,finishCount:54,notFinishCount:21}, {majorDeptName:测试,finishCount:54,notFinishCount:21}, {majorDeptName:测试,finishCount:54,notFinishCount:21}, {majorDeptName:测试,finishCount:54,notFinishCount:21}, {maj…

关于JVM面试题汇总

JVM是如何运行的? JVM的执行流程如下: 程序再执行之前先要把Java代码转换成字节码(class文件),JVM首先需要把字节码通过一定的方式类加载器(ClassLoader)把文件加载到内存中运行时数据区&…

Weblogic反序列化漏洞分析之CVE-2021-2394

目录 简介 前置知识 Serializable示例 Externalizable示例 联系weblogic ExternalizableLite接口 ExternalizableHelperl类 JdbcRowSetImpl类 MethodAttributeAccessor类 AbstractExtractor类 FilterExtractor类 TopNAggregator$PartialResult类 SortedBag$Wrappe…

【A题完整论文】2024美赛完整论文+代码参考(无偿分享)

A题:资源可用性和性别比例 一、问题分析 1.1 问题一分析 针对该问题,若七鳃鮼的性别比例受到外部环境因素的影响,那么这可能会导致种群大小和结构的变化。如果雌性在某些环境条件下更为优势,种群的增加可能对其他物种的竞争和资源…

【Python】一个简单的小案例:实现批量修改图片格式

1.代码 import os from tkinter import Tk, Button from PIL import Imagedef check_and_create_folders():# 获取当前目录current_directory os.getcwd()# 定义文件夹名称folders_to_check ["JPG", "PNG"]for folder_name in folders_to_check:folder_…

nvm-windows的安装和配置

下载安装nvm-setup.zip用于切换node版本,旧项目用的是14版本,vue3需要的node版本要高些,所以运行vue3项目前需要用nvm切换node的版本先。 下载安装好nvm-setup.zip后检查是否配置好如下信息: 之后在 PATH 变量中添加 %NVM_HOME% 和 %NVM_SYM…

2024年美赛 (B题MCM)| 潜水艇 |数学建模完整代码+建模过程全解全析

当大家面临着复杂的数学建模问题时,你是否曾经感到茫然无措?作为2022年美国大学生数学建模比赛的O奖得主,我为大家提供了一套优秀的解题思路,让你轻松应对各种难题。 让我们来看看美赛的B题! 完整内容可以在文章末尾领…