更新动作检测逻辑

This commit is contained in:
terric 2023-11-08 00:51:42 +08:00
parent f6c45303ad
commit d2bf122e56
16 changed files with 86 additions and 612 deletions

View File

@ -74,98 +74,6 @@ Animator:
m_AllowConstantClipSamplingOptimization: 1 m_AllowConstantClipSamplingOptimization: 1
m_KeepAnimatorStateOnDisable: 0 m_KeepAnimatorStateOnDisable: 0
m_WriteDefaultValuesOnDisable: 0 m_WriteDefaultValuesOnDisable: 0
--- !u!1 &1655379611402516801
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2246865126792962373}
- component: {fileID: 8261163955276643325}
- component: {fileID: 7348735772167593676}
- component: {fileID: 4493683514322913532}
m_Layer: 5
m_Name: ShowText
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &2246865126792962373
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1655379611402516801}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 4, y: 4, z: 4}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 38199016232350786}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: -1329, y: -444}
m_SizeDelta: {x: 200, y: 40}
m_Pivot: {x: 0, y: 1}
--- !u!222 &8261163955276643325
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1655379611402516801}
m_CullTransparentMesh: 1
--- !u!114 &7348735772167593676
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1655379611402516801}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 0, b: 0, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_FontData:
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
m_FontSize: 28
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 2
m_MaxSize: 40
m_Alignment: 4
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: "\u6D4B\u8BD5\u6587\u672C"
--- !u!114 &4493683514322913532
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1655379611402516801}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 7e87e8c67a3599740822141fa1e8a73f, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &2305242494350081140 --- !u!1 &2305242494350081140
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -197,8 +105,6 @@ RectTransform:
- {fileID: 8475079236000353301} - {fileID: 8475079236000353301}
- {fileID: 18963948842239410} - {fileID: 18963948842239410}
- {fileID: 5076069559660177782} - {fileID: 5076069559660177782}
- {fileID: 2246865126792962373}
- {fileID: 913300150706249764}
m_Father: {fileID: 475269767089658797} m_Father: {fileID: 475269767089658797}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0} m_AnchorMin: {x: 0, y: 0}
@ -291,114 +197,6 @@ CanvasGroup:
m_Interactable: 1 m_Interactable: 1
m_BlocksRaycasts: 1 m_BlocksRaycasts: 1
m_IgnoreParentGroups: 0 m_IgnoreParentGroups: 0
--- !u!1 &4494414620026654833
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 913300150706249764}
- component: {fileID: 3765446309826417366}
- component: {fileID: 2254883025463725799}
- component: {fileID: 1639543910360457363}
- component: {fileID: 4220982582391514376}
m_Layer: 5
m_Name: ShowHint
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &913300150706249764
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4494414620026654833}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 4, y: 4, z: 4}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 38199016232350786}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 1}
m_AnchorMax: {x: 0.5, y: 1}
m_AnchoredPosition: {x: 0, y: -50}
m_SizeDelta: {x: 400, y: 40}
m_Pivot: {x: 0.5, y: 1}
--- !u!222 &3765446309826417366
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4494414620026654833}
m_CullTransparentMesh: 1
--- !u!114 &2254883025463725799
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4494414620026654833}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_FontData:
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
m_FontSize: 28
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 2
m_MaxSize: 40
m_Alignment: 4
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: "\u6D4B\u8BD5\u6587\u672C"
--- !u!114 &1639543910360457363
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4494414620026654833}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: e19747de3f5aca642ab2be37e372fb86, type: 3}
m_Name:
m_EditorClassIdentifier:
m_EffectColor: {r: 0, g: 0, b: 0, a: 0.5}
m_EffectDistance: {x: 3, y: -1}
m_UseGraphicAlpha: 1
--- !u!114 &4220982582391514376
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4494414620026654833}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 8d1cb71f907bfec429b9020e43438c62, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &4557793384850939514 --- !u!1 &4557793384850939514
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

View File

@ -6,8 +6,6 @@ using UnityEngine;
public class BodyBendLeft : PoseBase public class BodyBendLeft : PoseBase
{ {
public BodyBendLeft(ModelType name) : base(name) { }
public override bool CheckPose(List<Point> points) public override bool CheckPose(List<Point> points)
{ {
if (!CheckPoint(points, "LHip") && if (!CheckPoint(points, "LHip") &&
@ -21,16 +19,4 @@ public class BodyBendLeft : PoseBase
return false; return false;
} }
public override void ShowHint()
{
}
public override void ProcessFailCallBack()
{
//YogaManager.Instance.UpdateStatus?.Invoke(string.Empty);
}
public override void ProcessSuccessCallBack(Action callback)
{
YogaManager.Instance.UpdateStatus?.Invoke("左弯腰");
}
} }

View File

@ -6,8 +6,6 @@ using UnityEngine;
public class BodyBendRight : PoseBase public class BodyBendRight : PoseBase
{ {
public BodyBendRight(ModelType name) : base(name) { }
public override bool CheckPose(List<Point> points) public override bool CheckPose(List<Point> points)
{ {
if (!CheckPoint(points, "RHip") && if (!CheckPoint(points, "RHip") &&
@ -20,18 +18,4 @@ public class BodyBendRight : PoseBase
} }
return false; return false;
} }
public override void ShowHint()
{
}
public override void ProcessFailCallBack()
{
//YogaManager.Instance.UpdateStatus?.Invoke(string.Empty);
}
public override void ProcessSuccessCallBack(Action callback)
{
YogaManager.Instance.UpdateStatus?.Invoke("右弯腰");
}
} }

View File

@ -6,8 +6,6 @@ using UnityEngine;
public class BodyTurnLeft : PoseBase public class BodyTurnLeft : PoseBase
{ {
public BodyTurnLeft(ModelType name) : base(name) { }
public override bool CheckPose(List<Point> points) public override bool CheckPose(List<Point> points)
{ {
if (!CheckPoint(points, "LShoulder") && if (!CheckPoint(points, "LShoulder") &&
@ -21,23 +19,4 @@ public class BodyTurnLeft : PoseBase
return false; return false;
} }
public override void ShowHint()
{
}
public override void ProcessFailCallBack()
{
//YogaManager.Instance.UpdateStatus?.Invoke(string.Empty);
}
public override void ProcessSuccessCallBack(Action callback)
{
YogaManager.Instance.UpdateStatus?.Invoke("左转身");
}
} }
//public class NodCheck : PoseBase
//{
//}

View File

@ -6,8 +6,6 @@ using UnityEngine;
public class BodyTurnRight : PoseBase public class BodyTurnRight : PoseBase
{ {
public BodyTurnRight(ModelType name) : base(name) { }
public override bool CheckPose(List<Point> points) public override bool CheckPose(List<Point> points)
{ {
if (!CheckPoint(points, "RShoulder") && if (!CheckPoint(points, "RShoulder") &&
@ -21,18 +19,4 @@ public class BodyTurnRight : PoseBase
return false; return false;
} }
public override void ShowHint()
{
}
public override void ProcessFailCallBack()
{
//YogaManager.Instance.UpdateStatus?.Invoke(string.Empty);
}
public override void ProcessSuccessCallBack(Action callback)
{
YogaManager.Instance.UpdateStatus?.Invoke("右转身");
}
} }

View File

@ -1,21 +0,0 @@
using UnityEngine;
using UnityEngine.UI;
public class CheckStatusUIController : MonoBehaviour
{
private void OnEnable()
{
YogaManager.Instance.UpdateStatus -= UpdateStatus;
YogaManager.Instance.UpdateStatus += UpdateStatus;
}
private void OnDisable()
{
YogaManager.Instance.UpdateStatus -= UpdateStatus;
}
private void UpdateStatus(string status)
{
this.GetComponent<Text>().text = status;
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 7e87e8c67a3599740822141fa1e8a73f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -8,8 +8,6 @@ public class HeadTurnLeft : PoseBase
{ {
private bool _isRunning = false; private bool _isRunning = false;
public HeadTurnLeft(ModelType name) : base(name) { }
public override bool CheckPose(List<Point> points) public override bool CheckPose(List<Point> points)
{ {
if (!CheckPoint(points, "Nose")) if (!CheckPoint(points, "Nose"))
@ -28,40 +26,4 @@ public class HeadTurnLeft : PoseBase
return false; return false;
} }
public override void ShowHint()
{
YogaManager.Instance.ShowHint?.Invoke("请左转头");
EventManager.Instance.Dispatch("PlayAnimation", AvatarAction.HeadTurnLeft);
}
public override void ProcessSuccessCallBack(Action callback)
{
if (_isRunning)
return;
YogaManager.Instance.StartCoroutine(SuccessAction(callback));
}
public override void ProcessFailCallBack()
{
//YogaManager.Instance.UpdateStatus?.Invoke(string.Empty);
}
private IEnumerator SuccessAction(Action callback)
{
_isRunning = true;
yield return new WaitForSeconds(3f);
if (!CheckPose(YogaManager.Instance.Points))
{
YogaManager.Instance.UpdateStatus?.Invoke("请左转头");
_isRunning = false;
yield break;
}
YogaManager.Instance.UpdateStatus?.Invoke("很好,你已经左转头了!");
yield return new WaitForSeconds(1f);
_isRunning = true;
callback?.Invoke();
}
} }

View File

@ -6,10 +6,6 @@ using UnityEngine;
public class HeadTurnRight : PoseBase public class HeadTurnRight : PoseBase
{ {
private bool _isRunning = false;
public HeadTurnRight(ModelType name) : base(name) { }
public override bool CheckPose(List<Point> points) public override bool CheckPose(List<Point> points)
{ {
if (!CheckPoint(points, "Nose")) if (!CheckPoint(points, "Nose"))
@ -26,39 +22,4 @@ public class HeadTurnRight : PoseBase
return false; return false;
} }
public override void ShowHint()
{
YogaManager.Instance.ShowHint?.Invoke("请右转头");
EventManager.Instance.Dispatch("PlayAnimation", AvatarAction.HeadTurnRight);
}
public override void ProcessFailCallBack()
{
//YogaManager.Instance.UpdateStatus?.Invoke(string.Empty);
}
public override void ProcessSuccessCallBack(Action callback)
{
if (_isRunning)
return;
YogaManager.Instance.StartCoroutine(SuccessAction(callback));
}
private IEnumerator SuccessAction(Action callback)
{
_isRunning = true;
yield return new WaitForSeconds(3f);
if (!CheckPose(YogaManager.Instance.Points))
{
YogaManager.Instance.UpdateStatus?.Invoke("请右转头");
_isRunning = false;
yield break;
}
YogaManager.Instance.UpdateStatus?.Invoke("很好,你已经右转头了!");
yield return new WaitForSeconds(1f);
_isRunning = true;
callback?.Invoke();
}
} }

View File

@ -8,7 +8,6 @@ public class IsReady : PoseBase
{ {
private bool _isRunning = false; private bool _isRunning = false;
public IsReady(ModelType name) : base(name) { }
public override bool CheckPose(List<Point> points) public override bool CheckPose(List<Point> points)
{ {
@ -24,39 +23,4 @@ public class IsReady : PoseBase
return true; return true;
} }
public override void ProcessFailCallBack()
{
YogaManager.Instance.UpdateStatus?.Invoke(string.Empty);
}
public override void ProcessSuccessCallBack(Action callback)
{
if (_isRunning)
return;
YogaManager.Instance.StartCoroutine(SuccessAction(callback));
}
public override void ShowHint()
{
YogaManager.Instance.ShowHint?.Invoke("请摆正姿势");
}
private IEnumerator SuccessAction(Action callback)
{
_isRunning = true;
yield return new WaitForSeconds(3f);
if (!CheckPose(YogaManager.Instance.Points))
{
YogaManager.Instance.UpdateStatus?.Invoke("请摆正姿势");
_isRunning = false;
yield break;
}
YogaManager.Instance.UpdateStatus?.Invoke("很好,你已经摆正了姿态!");
yield return new WaitForSeconds(1f);
_isRunning = true;
callback?.Invoke();
}
} }

View File

@ -51,11 +51,7 @@ namespace Yoga
private double threshold = 0.5; private double threshold = 0.5;
private float _involkCDTime = 0;
private Coroutine _objEstimation;
private Coroutine _actionEstimation;
private bool _isOnCamCapture = false; private bool _isOnCamCapture = false;
public bool IsOnCamCapture { get => _isOnCamCapture; internal set => _isOnCamCapture = value; } public bool IsOnCamCapture { get => _isOnCamCapture; internal set => _isOnCamCapture = value; }
private void OnEnable() private void OnEnable()
@ -72,11 +68,6 @@ namespace Yoga
EventManager.Instance.RemoveEventListener("ScoreUpdate", ScoreUpdate); EventManager.Instance.RemoveEventListener("ScoreUpdate", ScoreUpdate);
} }
private void EstimateAction()
{
//检测动作
}
private void OnStartMotionCapture() private void OnStartMotionCapture()
{ {
this.enabled = true; this.enabled = true;
@ -147,62 +138,75 @@ namespace Yoga
{ {
Mat img = _webCamTextureToMatHelper.GetMat(); Mat img = _webCamTextureToMatHelper.GetMat();
Imgproc.cvtColor(img, img, Imgproc.COLOR_BGR2RGB); Imgproc.cvtColor(img, img, Imgproc.COLOR_BGR2RGB);
_rgbaMat = img.clone();
_involkCDTime += Time.deltaTime;
if (_involkCDTime > SamplingRate)
{
if (_objEstimation != null)
StopCoroutine(_objEstimation);
_objEstimation = StartCoroutine(ObjectEstimation(img));
_involkCDTime = 0;
}
//#if DEBUG_MODE && UNITY_EDITOR
if (_net == null) if (_net == null)
{ {
Imgproc.putText(img, "model file is not loaded.", new Point(5, img.rows() - 30), Imgproc.FONT_HERSHEY_SIMPLEX, 0.7, new Scalar(255, 255, 255), 2, Imgproc.LINE_AA, false); Imgproc.putText(img, "model file is not loaded.", new Point(5, img.rows() - 30), Imgproc.FONT_HERSHEY_SIMPLEX, 0.7, new Scalar(255, 255, 255), 2, Imgproc.LINE_AA, false);
Imgproc.putText(img, "Please read console message.", new Point(5, img.rows() - 10), Imgproc.FONT_HERSHEY_SIMPLEX, 0.7, new Scalar(255, 255, 255), 2, Imgproc.LINE_AA, false); Imgproc.putText(img, "Please read console message.", new Point(5, img.rows() - 10), Imgproc.FONT_HERSHEY_SIMPLEX, 0.7, new Scalar(255, 255, 255), 2, Imgproc.LINE_AA, false);
} }
DebugPrintObjectLayout(img, _voloResult[0], _voloResult[1], _voloResult[2]); if (_voloResult.Count >= 2)
DebugPrintObjectLayout(img, _voloResult[0], _voloResult[1], _voloResult[2]);
List<Point> points = _personPoints; if (_personPoints.Count > 0)
for (int i = 0; i < YogaConfig.POSE_PAIRS.GetLength(0); i++)
{ {
string partFrom = YogaConfig.POSE_PAIRS[i, 0]; List<Point> points = _personPoints;
string partTo = YogaConfig.POSE_PAIRS[i, 1];
int idFrom = YogaConfig.BODY_PARTS[partFrom]; for (int i = 0; i < YogaConfig.POSE_PAIRS.GetLength(0); i++)
int idTo = YogaConfig.BODY_PARTS[partTo];
if (points[idFrom] == new Point(-1, -1) || points[idTo] == new Point(-1, -1))
continue;
if (points[idFrom] != null && points[idTo] != null)
{ {
Imgproc.line(img, points[idFrom], points[idTo], new Scalar(0, 255, 0), 3); string partFrom = YogaConfig.POSE_PAIRS[i, 0];
Imgproc.ellipse(img, points[idFrom], new Size(3, 3), 0, 0, 360, new Scalar(0, 0, 255), Core.FILLED); string partTo = YogaConfig.POSE_PAIRS[i, 1];
Imgproc.ellipse(img, points[idTo], new Size(3, 3), 0, 0, 360, new Scalar(0, 0, 255), Core.FILLED);
int idFrom = YogaConfig.BODY_PARTS[partFrom];
int idTo = YogaConfig.BODY_PARTS[partTo];
if (points[idFrom] == new Point(-1, -1) || points[idTo] == new Point(-1, -1))
continue;
if (points[idFrom] != null && points[idTo] != null)
{
Imgproc.line(img, points[idFrom], points[idTo], new Scalar(0, 255, 0), 3);
Imgproc.ellipse(img, points[idFrom], new Size(3, 3), 0, 0, 360, new Scalar(0, 0, 255), Core.FILLED);
Imgproc.ellipse(img, points[idTo], new Size(3, 3), 0, 0, 360, new Scalar(0, 0, 255), Core.FILLED);
}
} }
} }
//#endif //#endif
Utils.matToTexture2D(img, texture); Utils.matToTexture2D(img, texture);
} }
} }
private void EstimateAction(params object[] args)
private IEnumerator ObjectEstimation(Mat rgbaMat)
{ {
if (!_webCamTextureToMatHelper.IsPlaying() || !_webCamTextureToMatHelper.DidUpdateThisFrame()) //开启动作检测
yield break; var type = args.FirstOrDefault();
if (type == null)
{
Debug.LogError("EstimateAction type is null");
return;
}
AvatarAction actionType = (AvatarAction)args.FirstOrDefault();
ObjectEstimation(actionType);
}
private void ObjectEstimation(AvatarAction actionType)
{
Debug.LogWarning("Start Estimation");
Mat rgbaMat = _rgbaMat;
if (rgbaMat == null)
{
Debug.LogWarning("WebCamTexture is null. ");
return;
}
if (_objectDetector == null) if (_objectDetector == null)
yield break; {
Debug.LogWarning("ObjectDetector is not ready. ");
return;
}
Imgproc.cvtColor(rgbaMat, _bgrMat, Imgproc.COLOR_RGBA2BGR); Imgproc.cvtColor(rgbaMat, _bgrMat, Imgproc.COLOR_RGBA2BGR);
Mat results = _objectDetector.infer(_bgrMat); Mat results = _objectDetector.infer(_bgrMat);
var voloResultBox = new List<float[]>();
for (int i = results.rows() - 1; i >= 0; --i) for (int i = results.rows() - 1; i >= 0; --i)
{ {
@ -213,34 +217,20 @@ namespace Yoga
float[] cls = new float[1]; float[] cls = new float[1];
results.get(i, 5, cls); //类别 results.get(i, 5, cls); //类别
var rectResult = new List<float[]>() { box, conf, cls }; if (IsObjectValid(box, conf, cls, rgbaMat))
if (CheckResults(box, conf, cls, rgbaMat))
{ {
_voloResult.Clear(); voloResultBox.Clear();
_voloResult.Add(box); voloResultBox.Add(box);
_voloResult.Add(conf); voloResultBox.Add(conf);
_voloResult.Add(cls); voloResultBox.Add(cls);
break; break;
} }
} }
if (_actionEstimation != null)
StopCoroutine(_actionEstimation);
_actionEstimation = StartCoroutine(ActionEstimation(rgbaMat));
}
private IEnumerator ActionEstimation(Mat rgbaMat)
{
if (!_webCamTextureToMatHelper.IsPlaying() || !_webCamTextureToMatHelper.DidUpdateThisFrame())
yield break;
if (_voloResult == null)
yield break;
var box = _voloResult[0];
//对人体进行姿态检测 //对人体进行姿态检测
OpenCVForUnity.CoreModule.Rect rect = new OpenCVForUnity.CoreModule.Rect((int)box[0], (int)box[1], (int)(box[2] - box[0]), (int)(box[3] - box[1])); Debug.LogWarning("Start Body Estimation");
_voloResult = voloResultBox;
OpenCVForUnity.CoreModule.Rect rect = new OpenCVForUnity.CoreModule.Rect((int)voloResultBox[0][0], (int)voloResultBox[0][1], (int)(voloResultBox[0][2] - voloResultBox[0][0]), (int)(voloResultBox[0][3] - voloResultBox[0][1]));
Mat personRectImg = new Mat(_bgrMat, rect);//获取人体区域 Mat personRectImg = new Mat(_bgrMat, rect);//获取人体区域
_personPoints = _openPoseModel.estimate(personRectImg, (float)threshold).toList(); _personPoints = _openPoseModel.estimate(personRectImg, (float)threshold).toList();
@ -256,12 +246,17 @@ namespace Yoga
_personPoints[j].y += rect.y; _personPoints[j].y += rect.y;
} }
//打印所有点
for (int i = 0; i < _personPoints.Count; i++)
{
Debug.LogWarning("point " + i + " " + _personPoints[i]);
}
//检测动作 //检测动作
//YogaManager.Instance.ProcessPoints(_personPoints); _isCorrectAction = (_isCorrectAction || YogaManager.Instance.IsCorrectAction(_personPoints, actionType));
} }
private bool IsObjectValid(float[] box, float[] confidence, float[] classID, Mat rgbaMat)
private bool CheckResults(float[] box, float[] confidence, float[] classID, Mat rgbaMat)
{ {
if ((int)classID[0] != 0 || confidence[0] < 0.8f) //只检测人体且置信度大于80% if ((int)classID[0] != 0 || confidence[0] < 0.8f) //只检测人体且置信度大于80%
return false; return false;
@ -315,15 +310,11 @@ namespace Yoga
{ {
_webCamTextureToMatHelper.Dispose(); _webCamTextureToMatHelper.Dispose();
if (_net != null) if (_net != null)
_net.Dispose(); _net.Dispose();
_bgrMat.Dispose(); _bgrMat.Dispose();
//删除已加载的各种模型
_models.Clear(); _models.Clear();
//YogaManager.Instance.Dispose();
} }
public void OnWebCamTextureToMatHelperInitialized() public void OnWebCamTextureToMatHelperInitialized()
@ -381,6 +372,7 @@ namespace Yoga
private bool _isCorrectAction = false; private bool _isCorrectAction = false;
private int _maxActionCount = 3; private int _maxActionCount = 3;
private Mat _rgbaMat;
public void ScoreUpdate() public void ScoreUpdate()
{ {
@ -403,6 +395,8 @@ namespace Yoga
{ {
EventManager.Instance.Dispatch("ActionFailed"); EventManager.Instance.Dispatch("ActionFailed");
} }
_isCorrectAction = false;//重置
YogaManager.Instance.CurrentActionCount++; YogaManager.Instance.CurrentActionCount++;
} }
} }

View File

@ -6,18 +6,7 @@ using UnityEngine;
public abstract class PoseBase public abstract class PoseBase
{ {
public ModelType ModelName { get; internal set; }
public abstract bool CheckPose(List<Point> points); public abstract bool CheckPose(List<Point> points);
public abstract void ProcessSuccessCallBack(Action callback);
public abstract void ProcessFailCallBack();
public abstract void ShowHint();
public PoseBase(ModelType name)
{
ModelName = name;
}
public Dictionary<string, Point> GetVaildPoints(List<Point> points, List<string> pointName) public Dictionary<string, Point> GetVaildPoints(List<Point> points, List<string> pointName)
{ {

View File

@ -1,25 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using UnityEngine;
using UnityEngine.UI;
public class ShowHintUIController : MonoBehaviour
{
private void OnEnable()
{
YogaManager.Instance.ShowHint -= ShowHint;
YogaManager.Instance.ShowHint += ShowHint;
}
private void OnDisable()
{
YogaManager.Instance.ShowHint -= ShowHint;
}
private void ShowHint(string hintText)
{
this.GetComponent<Text>().text = hintText;
}
}

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 8d1cb71f907bfec429b9020e43438c62
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -84,6 +84,7 @@ public class GuideUI : UIPanelBase
{ {
base.OnEnter(); base.OnEnter();
_guide.SetActive(true); _guide.SetActive(true);
EventManager.Instance.Dispatch("StartMotionCapture");
EventManager.Instance.Dispatch("PlayAnimation", AvatarAction.HeadTurnLeft); EventManager.Instance.Dispatch("PlayAnimation", AvatarAction.HeadTurnLeft);
} }
} }

View File

@ -12,100 +12,40 @@ using UnityEngine;
public class YogaManager : MonoSingleton<YogaManager> public class YogaManager : MonoSingleton<YogaManager>
{ {
private bool _isInited = false;
private LinkedList<PoseBase> _poseChecks = new LinkedList<PoseBase>();
private PoseBase _currPose = null;
private double threshold = 0.1;
private List<Point> _points = new List<Point>(); private List<Point> _points = new List<Point>();
public List<Point> Points { get => _points; private set => _points = value; } public List<Point> Points { get => _points; private set => _points = value; }
public Action<string> UpdateStatus { get; internal set; } private int _currentActionCount; //当前动作计数
public Action<string> ShowHint { get; internal set; }
public int ActionIndex { get; internal set; }
public int CurrentActionCount { get => _currentActionCount; internal set => _currentActionCount = value; } public int CurrentActionCount { get => _currentActionCount; internal set => _currentActionCount = value; }
private int _currentSuccessActionCount; //当前成功动作计数
public int CurrentSuccessActionCount { get => _currentSuccessActionCount; internal set => _currentSuccessActionCount = value; } public int CurrentSuccessActionCount { get => _currentSuccessActionCount; internal set => _currentSuccessActionCount = value; }
//创建帧数据缓存 private int _actionIndex; //用户选择界面选择的动作索引
private Dictionary<int, List<List<Point>>> _framePoints = new (); // actionID, frameID, points public int ActionIndex { get => _actionIndex; internal set => _actionIndex = value; }
private int _currActionID;
private int _currentActionCount; private Dictionary<AvatarAction, PoseBase> _actions = new Dictionary<AvatarAction, PoseBase>();
private int _currentSuccessActionCount;
public void InitData() public void InitData()
{ {
_poseChecks.AddFirst(new IsReady(ModelType.OpenPose)); _actions[AvatarAction.HeadTurnLeft] = new HeadTurnLeft();
_poseChecks.AddLast(new HeadTurnLeft(ModelType.OpenPose)); _actions[AvatarAction.HeadTurnRight] = new HeadTurnRight();
_poseChecks.AddLast(new HeadTurnRight(ModelType.OpenPose));
ShowHint?.Invoke(string.Empty);
UpdateStatus?.Invoke(string.Empty);
_currPose = _poseChecks.First.Value;
_currPose.ShowHint();
_currActionID = 0;
_isInited = true;
_currentActionCount = 0; _currentActionCount = 0;
_currentSuccessActionCount = 0; _currentSuccessActionCount = 0;
} }
public void Dispose() public bool IsCorrectAction(List<Point> personPoints, AvatarAction actionType)
{ {
_currPose = null; if (!_actions.ContainsKey(actionType))
UpdateStatus = null;
_isInited = false;
_poseChecks.Clear();
}
public List<Point> Process(Mat img, Dictionary<ModelType, KeypointsModel> models)
{
List<Point> points = models[_currPose.ModelName].estimate(img, (float)threshold).toList();
//_framePoints[_currActionID].Add(points);
ProcessPoints(points);
return points;
}
public void ProcessPoints(List<Point> points)
{
if (!_isInited)
{ {
InitData(); Debug.LogError("ActionType is not exist");
return false;
} }
Points = points; var result = _actions[actionType].CheckPose(personPoints);
Debug.LogWarning("ActionType: " + actionType + " result: " + result);
if (_currPose == null) return result;
{
_currPose = _poseChecks.First.Value;
_currPose.ShowHint();
return;
}
if (_currPose.CheckPose(points))
{
_currPose.ProcessSuccessCallBack(() =>
{
SwitchNextPost();
});
}
else
{
_currPose.ProcessFailCallBack();
}
}
private void SwitchNextPost()
{
if (_currPose == _poseChecks.Last.Value)
{
Dispose();
return;
}
_currPose = _poseChecks.Find(_currPose).Next.Value;
_currPose.ShowHint();
} }
} }