迷迷糊糊看了很多遍,对于比较核心的内容依然没有理解。今天稍微认真一些看了一遍,觉得大概懂了一些,仅作记录。
首先在代码外做简要说明.关于姿态对比原理,我的理解是:
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);
}
}