Openpose2d转换3d姿态识别

最近笔者遇到一个问题就是openpose在对于姿态识别的时候,识别出的人体姿态是一个2d平面姿态。对于AR交互应用来说,2d姿态是不如3d姿态的。当然可以使用kinect深度摄像头或者开源项目vnect实现3d的实时姿态识别。但是如果能够对于openpose做一些改动,可以达到近似的效果。

首先openpose的body_25模型输出如图:
在这里插入图片描述
为了做出一个近似效果 ,我们可以先假定
1.躯干是面对摄像头不会偏移(旋转的)【关节点 5 2 1 8】。
2. 肢体的倾斜只有左倾 右倾 和 前倾 , 没有向后倾。
然后首先我们的目标是做一个如图上的伸展姿势(肢体在2d平面内),测定每块肢体的长度。

接下来 ,我们以 1 2 和 2 3 关节点为例,做一个3d姿态识别。
首先我们假定了 5 2 1 8 始终与摄像头保持平行,所以可以以此为参照。
在这里插入图片描述
对于2d平面来说 这个角度我们是已知的,可以通过计算向量之间的夹角得出。
那么当3进行前倾的时候, 得到的2d 输出其实是 2 3'。我们已知 2 3'的长度和 2 3的长度。
2 3' = 2 3 * cos Θ。 这样可以计算得出 前倾角θ的角度。得到了 两张图中的角度 ,即可得到关节点3的空间位置

在这里插入图片描述

对于OpenPose的unity插件而言,是将得到的姿态信息在屏幕上进行标定,然后使用LineRenderer进行绘制。笔者在此基础上添加了肢体模型
在这里插入图片描述
在这里插入图片描述
脚本在lsfather lsfather为空物体 lshoulder为实际模型,这样方便于角度和模型的调校。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class To3DBlog : MonoBehaviour
{
    
    
    [SerializeField] RectTransform Joint0;
    [SerializeField] RectTransform Joint1;
    Vector3 direction;
    bool enabledstate;

    GameObject Renderobj;
    [SerializeField]  float MaxSize = 0;
    [SerializeField]  float curLength;
    float curHeight;
    [SerializeField] GameObject childobj;

    // Start is called before the first frame update
    void Start()
    {
    
    
        Renderobj = this.gameObject;
        childobj = this.gameObject.transform.GetChild(0).gameObject;
    }

    // Update is called once per frame
    void Update()
    {
    
    
        if (Joint0 && Joint1)
        {
    
    
            bool enabled = Joint0.gameObject.activeInHierarchy && Joint1.gameObject.activeInHierarchy;
            enabledstate = enabled;
            childobj.SetActive(enabled);
            if (enabled)
            {
    
    
                //进行
                direction = (Joint0.transform.localPosition - Joint1.transform.localPosition);
                curLength = direction.magnitude;

                //向量的模
                if (curLength > MaxSize)
                {
    
    
                    MaxSize = direction.magnitude;
                }
                //求Joint1 的 z 值

                //curHeight = MaxSize * Mathf.Sin(Mathf.Acos(curLength/MaxSize));
                curHeight = Mathf.Sqrt(Mathf.Pow(MaxSize,2)- Mathf.Pow(curLength,2));
                //面前方向是 -z 轴方向 但是 考虑镜像 
                direction = (Joint1.transform.localPosition + new Vector3(0, 0, curHeight) - Joint0.transform.localPosition);
                Renderobj.transform.localPosition = (Joint1.transform.localPosition + Joint0.transform.localPosition + new Vector3(0,0,-curHeight)) / 2;
                Renderobj.transform.up = direction;
                
                Renderobj.transform.localScale = new Vector3(MaxSize, MaxSize, MaxSize);
                //scale的问题
            }

        }
    }
}

算法解释如图:其中curLength 是openpose识别出两个关节点间的距离(也是该肢体在z轴的投影),MaxSize是该肢体实际长度,以此可以求出当前Joint1的高度。
在这里插入图片描述
对于右肩适用结果
在这里插入图片描述
对于右手臂适用结果 左2d 右3d 效果如图
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_35649669/article/details/99713839