当前位置:网站首页>ThreeDPoseTracker项目解析
ThreeDPoseTracker项目解析
2022-07-06 01:08:00 【烫青菜】
目录
一、源码
Digital Standard Co., LTD. (github.com)
参考文章:
二、肢体驱动
1.算法模型
(1)数据说明
项目中算法模型预测数据的代码主要为VNectBarracudaRunner.cs。函数PredictPose()中更新的节点数据为JointPoint中的三个变量(也就是驱动时要用到的算法数据):
public class JointPoint
{
public Vector3 Pos3D = new Vector3();
public float score3D;
public bool Visibled;
}
JointPoint类中还有几个变量是预测过程中用于数据优化(防抖动等)的:
public class JointPoint
{
public Vector3 Now3D = new Vector3();
public Vector3[] PrevPos3D = new Vector3[6];
public Vector3 P = new Vector3();
public Vector3 X = new Vector3();
public Vector3 K = new Vector3();
}
JointPoint类中其他的数据需要在肢体驱动时自己推算:
public class JointPoint
{
public Transform Transform = null;
public Quaternion InitRotation;
public Quaternion Inverse;
public Quaternion InverseRotation;
public JointPoint Child = null;
public JointPoint Parent = null;
}
(2)算法理论解析
解决抖动:卡尔曼滤波+低通滤波: 关键点平滑方案
算法模型解析:模型解析 、 heatmap&offset
- 有三个input,其实都是一样,都要输入(448,448,3)的图片:
private void UpdateVNectAsync()
{
input = new Tensor(videoCapture.MainTexture, 3);
if (inputs[inputName_1] == null)
{
inputs[inputName_1] = input;
inputs[inputName_2] = new Tensor(videoCapture.MainTexture, 3);
inputs[inputName_3] = new Tensor(videoCapture.MainTexture, 3);
}
else
{
inputs[inputName_3].Dispose();
inputs[inputName_3] = inputs[inputName_2];
inputs[inputName_2] = inputs[inputName_1];
inputs[inputName_1] = input;
}
if (!Lock && videoCapture.IsPlay())
{
StartCoroutine(ExecuteModelAsync());
}
}
- 四个output,但我们只用后两个:
for (var i = 2; i < _model.outputs.Count; i++)
{
b_outputs[i] = _worker.PeekOutput(_model.outputs[i]);
}
offset3D = b_outputs[2].data.Download(b_outputs[2].shape);
heatMap3D = b_outputs[3].data.Download(b_outputs[3].shape);
用heatmap粗略定位关节位置,然后使用offset在heatmap结果上精确调整关节位置。
heatmap的 ( 672 , 28 , 28 ) 代表 24个关节的28个大小为(28,28)的特征图。而offset比heatmap的特征图多三倍,很明显就是刚才说的精确定位,只不过需要在offset中定位到x,y,z三个坐标,所以就是三倍关系了。
- heatmap的顺序是第1个关节的第1个特征图、第1个关节的第2个特征图、…、第2个关节的第1个特征图、第二个关节的第2个特征图、…、第24个关节的第28个特征图
- offsetmap的顺序是第1个关节的第1个特征图对应的x坐标偏移、第1个关节的第2个特征图对应的x坐标偏移、第1个关节的第3个特征图对应的x坐标偏移、…、第1个关节的第28个特征图对应的x坐标偏移、…、第2个关节的第1个特征图对应的x坐标偏移、…、第24个关节的第28个特征图对应的x坐标偏移、第1个关节的第1个特征图对应的y坐标偏移、第1个关节的第2个特征图对应的y坐标偏移、…、第24个关节的第28个特征图对应的y坐标偏移、第1个关节的第1个特征图对应的z坐标偏移、第1个关节的第2个特征图对应的z坐标偏移、…、第24个关节的第28个特征图对应的z坐标偏移。
2.Unity肢体驱动
项目中肢体驱动的代码主要为VNectModel.cs。
(1)相关知识
- 四元素的逆,⽐如⼀个四元数为(1,1,1,1)它的逆是(-1,-1,-1,1)。
Quaternion Inverse(Quaternion rotation);
返回⼀个相反的旋转。
- 注视旋转
public static Quaternion LookRotation(Vector3 forward, [DefaultValue("Vector3.up")] Vector3 upwards);
创建一个指定的forward 和upward方向的旋转,返回一个计算的四元数。如果用来确定一个transform:如果向量是正交的, z轴将和forward对齐,y轴将和upward对齐。如果forward方向是0将会报错。
(2)项目中的使用
由当前关节的lookrotation=初始旋转InitRotation×对齐矩阵 及可得出:
a. Quaternion.Inverse(对齐矩阵)=当前旋转Rotation*Quaternion.Inverse(当前关节的lookrotation)
hip.Inverse = Quaternion.Inverse(Quaternion.LookRotation(forward));
hip.InverseRotation = hip.Inverse * hip.InitRotation;
函数Init()中有大量类似的代码,目的是求中间矩阵,根据中间矩阵,我们可以通过算法数据得出当前object的旋转。VNectModel.cs中的hip.InverseRotation就是Quaternion.Inverse(对齐矩阵)。
b. 当前旋转Rotation=当前关节的lookrotation×Quaternion.Inverse(对齐矩阵)
//基于根关节和左右胯关节坐标计算出人体朝向,然后以此作为所有关节LookRotation的y方向
var forward = TriangleNormal(jointPoints[PositionIndex.hip.Int()].Pos3D, jointPoints[PositionIndex.lThighBend.Int()].Pos3D, jointPoints[PositionIndex.rThighBend.Int()].Pos3D);
jointPoints[***].Transform.rotation = Quaternion.LookRotation(Vector3.up, forward) * jointPoint[***].InverseRotation;
函数PoseUpdate()用于肢体驱动,上面这行代码就是用来计算关节的当前旋转的。
c. 对齐矩阵=当前关节的lookrotation*Quaternion.Inverse(当前旋转Rotation);
root = animator.GetBoneTransform(HumanBodyBones.Hips);
midRoot = Quaternion.Inverse(root.rotation) * Quaternion.LookRotation(forward);//midRoot 为对齐矩阵
这些代码在项目中不存在,只是为了更好的解释公式。
三、肢体驱动流程图
边栏推荐
- 程序员搞开源,读什么书最合适?
- Leetcode 44 Wildcard matching (2022.02.13)
- Cve-2017-11882 reappearance
- SAP Spartacus home 页面读取 product 数据的请求的 population 逻辑
- Spark AQE
- Cf:d. insert a progression [about the insert in the array + the nature of absolute value + greedy top-down]
- Overview of Zhuhai purification laboratory construction details
- Dynamic programming -- linear DP
- Leetcode study - day 35
- Finding the nearest common ancestor of binary tree by recursion
猜你喜欢
The growth path of test / development programmers, the problem of thinking about the overall situation
Idea remotely submits spark tasks to the yarn cluster
基于DVWA的文件上传漏洞测试
图解网络:TCP三次握手背后的原理,为啥两次握手不可以?
从 1.5 开始搭建一个微服务框架——调用链追踪 traceId
VSphere implements virtual machine migration
关于#数据库#的问题:(5)查询库存表中每本书的条码、位置和借阅的读者编号
How to extract MP3 audio from MP4 video files?
Spark AQE
关于softmax函数的见解
随机推荐
Differences between standard library functions and operators
Gartner released the prediction of eight major network security trends from 2022 to 2023. Zero trust is the starting point and regulations cover a wider range
[groovy] compile time metaprogramming (compile time method injection | method injection using buildfromspec, buildfromstring, buildfromcode)
KDD 2022 | EEG AI helps diagnose epilepsy
Mysql--- query the top 5 students
Cglib dynamic agent -- example / principle
[simple implementation of file IO]
Recoverable fuse characteristic test
面试必刷算法TOP101之回溯篇 TOP34
Promise
Synchronized and reentrantlock
MCU通过UART实现OTA在线升级流程
[Arduino syntax - structure]
[groovy] XML serialization (use markupbuilder to generate XML data | set XML tag content | set XML tag attributes)
Opinions on softmax function
Cf:c. the third problem
Recursive method to realize the insertion operation in binary search tree
几百行代码实现一个 JSON 解析器
How to extract MP3 audio from MP4 video files?
vSphere实现虚拟机迁移