首页 > 其他分享 >【iOS ARKit】2D肢体动作捕捉

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

时间:2024-02-02 15:33:49浏览次数:39  
标签:检测 关节点 iOS 2D joint ARKit 人体

     人体肢体动作捕捉在动漫影视制作、游戏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)演示了如何利用关节点名字获取该关节点在屏幕空间中的位置信息。

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

​具体代码地址:https://github.com/duzhaoquan/ARkitDemo.git

标签:检测,关节点,iOS,2D,joint,ARKit,人体
From: https://www.cnblogs.com/duzhaoquan/p/18003269

相关文章

  • luffy_12days
    前倾回顾1搜索功能-前端:搜索框,搜索结果页面-后端:一种类型课程-APIResponse(actual_course=res.data.get('results'),free_course=[],light_course=[])-搜索,如果数据量很大,直接使用mysql,效率非常低--》ElasticSearch-全文检索:分词,搜索......
  • Vue中如何对Axios进行二次封装
    作为一个前端开发者,你一定对Axios这个强大的HTTP库非常熟悉。它不仅简化了与后端API的通信,而且还提供了许多强大的功能,如拦截器、取消请求等。但是在实际开发中,我们经常需要对Axios进行二次封装,以便更好地适应我们的业务需求。今天,我将为大家分享一下如何在Vue中对Axios进行二次封......
  • CF292D Connexted Components
    原题传送门分析首先一眼看到这个题,第一个想到的肯定是dfs暴力每次询问时从左往右把边一条一条加进来,再从右往左加一遍,然后维护连通块个数。但是这样的复杂度显然是\(O(mk)\)的。所以我们需要一些优化。注意到在加边的时候有些边并不会改变连通块的个数。这些边我先称之为无......
  • Unity引擎2D游戏开发,滑铲功能实现总结
    滑铲到悬崖边下落时无法取消动画由于是使用的协程方式实现,所以当滑铲到悬崖边的时候,不能使用yieldbreak,因为该指令会直接退出当前的协程方法,无法执行到isSlide=false指令privateIEnumeratorTriggerSlide(Vector3target){do{yieldreturnnull;......
  • Deep3DFaceRecon 2D图像转3D模型实战
    本案例通过Deep3DFaceRecon_pytorch实现前置文档:https://github.com/sicxu/Deep3DFaceRecon_pytorchhttps://blog.csdn.net/flyfish1986/article/details/121861086本文是在本地没有gpu硬件的支持下的实现方案,并不具体描述部署过程,部署过程建议看上面两个文档地址准备工程文......
  • Bug记录 ontriggerstay2d 碰撞体中连续执行两次
    Bug描述ontriggerstay2d碰撞体中连续执行两次出现场景在OnTriggerStay2D中进行判定,按下指定按键(或判断需要执行单次逻辑的控制器)时,判定成功后执行两次或更多。问题分析1.多个碰撞器进入判定区域可能进入判定区域的物体上挂载多种碰撞器,导致在判定成功后,执行多次后续逻辑。......
  • 【iOS ARKit】环境反射
    环境反射  在使用iOSAR中渲染虚拟物体时,RealityKit默认使用了一个简单的天空盒(Skybox,即IBL环境资源贴图),所有带反射材质的物体默认会对天空盒产生反射。   但在AR中,使用IBL技术实现的天空盒反射有一个很大的问题,那就是不真实,因为天空盒由开发者在开发时设置,不能实......
  • Unity引擎2D游戏开发,滑墙及蹬墙跳的实现总结
    一、滑墙动画的实现执行动画的逻辑//在墙壁上onWall=(touchLeftWall||touchRightWall)&&!isGround;基本逻辑:紧贴墙壁并且不在地面上的时候执行滑墙动画但是实际上,紧贴墙壁原地跳起也会执行滑墙动画所以,需要额外添加一个条件。跳起离开地面,并施加与面朝X轴方向的力......
  • CF282D Yet Another Number Game
    题意简述有\(n\)堆石子,第\(i\)堆包含\(a_i\)个,每次可以选择任意一堆取出任意数量石子,也可以选择对于所有石子堆都拿走任意数量化石子。问先手必胜还是后手必胜。\(n\le3,a_i\le300\)。解法一:动态规划发现\(a_i^3=2.7\times10^7\),完全能压到状态里,直接做dp即可。但......
  • IOS自动化测试框架appium
    由于公司的产品坐落于不同的平台,如ios、mac、Android、windows、web。因此每次有新需求的时候,开发结束后,留给测试的时间也不多。此外,一些新的功能实现,偶尔会影响其他的模块功能正常的使用。网上的ios自动化方面的内容也是少之又少。由于本人对ios自动化初次接触,花了两天......