Kinect用于姿态比对的PoseDetectorScript脚本解读(上)

迷迷糊糊看了很多遍,对于比较核心的内容依然没有理解。今天稍微认真一些看了一遍,觉得大概懂了一些,仅作记录。

 

首先在代码外做简要说明.关于姿态对比原理,我的理解是:

1.pose与avatar的骨骼数据对比

2.将骨骼joint生成有序列表,将列表里同一位置的两个节点相连,在空间中形成向量

3.求出pose和avatar的向量之间的夹角

4.将pose和avatar的向量之间的夹角累加(不大于90°。因为姿势完全一致时相邻节点连线所形成的向量角度应该为0),再除以最大误差夹角和(以90°最大误差乘以比对的向量数目),就是Average difference.1- diff  = match.

感觉应该是这样,没有再仔细看底层,因为做的项目姿态比对涉及到转体,明天再看一下关于rotation的内容.

 

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

public class PoseDetectorScript : MonoBehaviour 
{
    //user的Model骨骼数据等
	[Tooltip("User avatar model, who needs to reach the target pose.")]
	public PoseModelHelper avatarModel;

    //poseModel的Model骨骼数据等
	[Tooltip("Model in pose that need to be reached by the user.")]
	public PoseModelHelper poseModel;

    //需要比对的关节点
	[Tooltip("List of joints to compare.")]
	public List<KinectInterop.JointType> poseJoints = new List<KinectInterop.JointType>();

    //匹配阈值
	[Tooltip("Threshold, above which we consider the pose is matched.")]
	public float matchThreshold = 0.7f;

	[Tooltip("GUI-Text to display information messages.")]
	public UnityEngine.UI.Text infoText;

	// match percent (between 0 and 1)
	private float fMatchPercent = 0f;
	// whether the pose is matched or not
	private bool bPoseMatched = false;


	/// <summary>
	/// Gets the pose match percent.得到匹配度
	/// </summary>
	/// <returns>The match percent (value between 0 and 1).</returns>
	public float GetMatchPercent()
	{
		return fMatchPercent;
	}


	/// <summary>
	/// Determines whether the target pose is matched or not.是否匹配
	/// </summary>
	/// <returns><c>true</c> if the target pose is matched; otherwise, <c>false</c>.</returns>
	public bool IsPoseMatched()
	{
		return bPoseMatched;
	}


	void Update () 
	{
		KinectManager kinectManager = KinectManager.Instance;
		AvatarController avatarCtrl = avatarModel ? avatarModel.gameObject.GetComponent<AvatarController>() : null;

		if(kinectManager != null && kinectManager.IsInitialized() && 
		   avatarModel != null && avatarCtrl && kinectManager.IsUserTracked(avatarCtrl.playerId))
		{
			// get mirrored state
			bool isMirrored = avatarCtrl.mirroredMovement;
			
			// get the difference
			string sDiffDetails = string.Empty;
            //match为 1-diff 大于阈值则匹配
			fMatchPercent = 1f - GetPoseDifference(isMirrored, true, ref sDiffDetails);
			bPoseMatched = (fMatchPercent >= matchThreshold);

			string sPoseMessage = string.Format("Pose match: {0:F0}% {1}", fMatchPercent * 100f, 
			                                    (bPoseMatched ? "- Matched" : ""));
			if(infoText != null)
			{
				infoText.text = sPoseMessage + "\n\n" + sDiffDetails;
			}
		}
		else
		{
			// no user found
			if(infoText != null)
			{
				infoText.text = "Try to match the pose on the left.";
			}
		}
	}


	// gets angle or percent difference in pose 得到姿态diff
	public float GetPoseDifference(bool isMirrored, bool bPercentDiff, ref string sDiffDetails)
	{
		float fAngleDiff = 0f;
		float fMaxDiff = 0f;
		sDiffDetails = string.Empty;

		KinectManager kinectManager = KinectManager.Instance;
		if(!kinectManager || !avatarModel || !poseModel || poseJoints.Count == 0)
		{
			return 0f;
		}

		// copy model rotation  
        //猜测:因为poseModel会有base旋转的问题(base一般为腹部?)
		Quaternion poseSavedRotation = poseModel.GetBoneTransform(0).rotation;

        //Debug.Log(poseModel.GetBoneTransform(0).rotation);
        //Debug.Log(avatarModel.GetBoneTransform(0).rotation);

        poseModel.GetBoneTransform(0).rotation = avatarModel.GetBoneTransform(0).rotation;

		StringBuilder sbDetails = new StringBuilder();
		sbDetails.Append("Joint differences:").AppendLine();

		for(int i = 0; i < poseJoints.Count; i++)
		{
			KinectInterop.JointType joint = poseJoints[i];
			KinectInterop.JointType nextJoint = kinectManager.GetNextJoint(joint);

			if(nextJoint != joint && (int)nextJoint >= 0 && (int)nextJoint < KinectInterop.Constants.MaxJointCount)
			{
                //获得poseJoints这个list中将前一个节点与后一个节点的position相减,得到三维向量
                //并比较pose和avatar中这两个三维向量(姿态一致时理论上是平行的,degree为0)的角度.
				Transform avatarTransform1 = avatarModel.GetBoneTransform(avatarModel.GetBoneIndexByJoint(joint, isMirrored));
				Transform avatarTransform2 = avatarModel.GetBoneTransform(avatarModel.GetBoneIndexByJoint(nextJoint, isMirrored));

				Transform poseTransform1 = poseModel.GetBoneTransform(poseModel.GetBoneIndexByJoint(joint, isMirrored));
				Transform poseTransform2 = poseModel.GetBoneTransform(poseModel.GetBoneIndexByJoint(nextJoint, isMirrored));

				if(avatarTransform1 != null && avatarTransform2 != null && poseTransform1 != null && poseTransform2 != null)
				{
					Vector3 vAvatarBone = (avatarTransform2.position - avatarTransform1.position).normalized;
					Vector3 vPoseBone = (poseTransform2.position - poseTransform1.position).normalized;

					float fDiff = Vector3.Angle(vPoseBone, vAvatarBone);
					if(fDiff > 90f) fDiff = 90f;
                    //若两向量角度大于90度就记为90度
                    //fAngle为将每一次关节点连线比对的总角度之和
                    //fMaxDiff为最大可能角度偏差
                    //fAngleDiff / fMaxDiff就是diff值,用1-diff就为match
					fAngleDiff += fDiff;
					fMaxDiff += 90f;  // we assume the max diff could be 90 degrees

					sbDetails.AppendFormat("{0} - {1:F0} deg.", joint, fDiff).AppendLine();
				}
				else
				{
					sbDetails.AppendFormat("{0} - n/a", joint).AppendLine();
				}
			}
		}

		poseModel.GetBoneTransform(0).rotation = poseSavedRotation;

		// calculate percent diff
		float fPercentDiff = 0f;
		if(bPercentDiff && fMaxDiff > 0f)
		{
			fPercentDiff = fAngleDiff / fMaxDiff;
		}

		// details info
		sbDetails.AppendLine();
		sbDetails.AppendFormat("Sum-Diff: - {0:F0} deg out of {1:F0} deg", fAngleDiff, fMaxDiff).AppendLine();
		sbDetails.AppendFormat("Percent-Diff: {0:F0}%", fPercentDiff * 100).AppendLine();
		sDiffDetails = sbDetails.ToString();
		
		return (bPercentDiff ? fPercentDiff : fAngleDiff);
	}

}

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值