Health/Assets/Scripts/PoseCheck/MotionCaptureManager.cs

405 lines
14 KiB
C#
Raw Normal View History

2023-11-15 08:10:56 +00:00
using OpenCVForUnity.CoreModule;
2023-11-07 13:55:35 +00:00
using OpenCVForUnity.ImgprocModule;
using OpenCVForUnity.UnityUtils;
using OpenCVForUnity.UnityUtils.Helper;
2023-11-24 05:13:10 +00:00
2023-11-07 13:55:35 +00:00
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
2023-11-23 07:22:09 +00:00
using UnityEngine.UI;
2023-11-07 13:55:35 +00:00
2023-11-24 05:13:10 +00:00
#if UNITY_ANDROID && !UNITY_EDITOR
using Serenegiant.UVC;
#endif
2023-11-07 13:55:35 +00:00
namespace Yoga
{
2023-11-24 05:13:10 +00:00
public class MotionCaptureManager : CameraCaptureManagerBase
#if UNITY_ANDROID && !UNITY_EDITOR
, IUVCDrawer
#endif
2023-11-07 13:55:35 +00:00
{
2023-11-23 07:22:09 +00:00
public WebCamTextureToMatHelper _webCamTextureToMatHelper;
2023-11-07 13:55:35 +00:00
public float SamplingRate = 0.3f;
2023-11-23 07:22:09 +00:00
public RawImage TargetDisplayer;
2023-11-07 13:55:35 +00:00
2023-11-24 05:13:10 +00:00
private bool _isOnCamCapture = false;
2023-11-07 13:55:35 +00:00
private Mat _bgrMat;
2023-11-24 05:13:10 +00:00
private Texture2D _displayTexture;
private bool _isCorrectAction = false;
private Material _flipImg;
2023-11-07 13:55:35 +00:00
public bool IsOnCamCapture { get => _isOnCamCapture; internal set => _isOnCamCapture = value; }
2023-11-12 15:09:33 +00:00
public WebCamTextureToMatHelper WebCamTextureToMatHelper => _webCamTextureToMatHelper;
2023-11-07 13:55:35 +00:00
private void OnEnable()
{
2023-11-10 08:12:37 +00:00
EventManager.Instance.AddEventListener(YogaEventType.StartMotionCapture, OnStartMotionCapture);
EventManager.Instance.AddEventListener(YogaEventType.StopMotionCapture, OnStopMotionCapture);
EventManager.Instance.AddEventListener(YogaEventType.EstimateAction, EstimateAction);
EventManager.Instance.AddEventListener(YogaEventType.ScoreUpdate, ScoreUpdate);
EventManager.Instance.AddEventListener(YogaEventType.GetActionBasePoint, GetActionBasePoint);
2023-11-22 19:42:29 +00:00
EventManager.Instance.AddEventListener(YogaEventType.ChangeCaptureCameraDevice, ChangeCaptureCameraDevice);
2023-11-07 13:55:35 +00:00
}
2023-11-07 15:28:19 +00:00
private void OnDisable()
{
2023-11-10 08:12:37 +00:00
EventManager.Instance.RemoveEventListener(YogaEventType.StartMotionCapture, OnStartMotionCapture);
EventManager.Instance.RemoveEventListener(YogaEventType.StopMotionCapture, OnStopMotionCapture);
EventManager.Instance.RemoveEventListener(YogaEventType.EstimateAction, EstimateAction);
EventManager.Instance.RemoveEventListener(YogaEventType.ScoreUpdate, ScoreUpdate);
EventManager.Instance.RemoveEventListener(YogaEventType.GetActionBasePoint, GetActionBasePoint);
2023-11-22 19:42:29 +00:00
EventManager.Instance.RemoveEventListener(YogaEventType.ChangeCaptureCameraDevice, ChangeCaptureCameraDevice);
2023-11-07 15:28:19 +00:00
}
2023-11-23 07:22:09 +00:00
public void Awake()
2023-11-07 13:55:35 +00:00
{
2023-11-23 07:22:09 +00:00
if (_webCamTextureToMatHelper == null)
_webCamTextureToMatHelper = transform.GetComponent<WebCamTextureToMatHelper>();
2023-11-15 17:23:16 +00:00
#if UNITY_ANDROID && !UNITY_EDITOR
// Avoids the front camera low light issue that occurs in only some Android devices (e.g. Google Pixel, Pixel2).
2023-11-20 15:10:51 +00:00
_webCamTextureToMatHelper.avoidAndroidFrontCameraLowLightIssue = true;
2023-11-15 17:23:16 +00:00
#endif
2023-11-24 05:13:10 +00:00
//tool loading
_flipImg = Resources.Load<Material>("Materials/Unlit_FlipHorizontal");
2023-11-15 17:23:16 +00:00
2023-11-07 13:55:35 +00:00
_webCamTextureToMatHelper.Initialize();
2023-11-23 07:22:09 +00:00
Utils.setDebugMode(true); //打印日志
GlobalData.Instance.CameraDeviceType = CameraDeviceType.USB; //test
2023-11-24 05:13:10 +00:00
#if UNITY_ANDROID && !UNITY_EDITOR
2023-11-23 07:22:09 +00:00
var devices = UVCManager.Instance.GetAttachedDevices();
2023-11-24 05:13:10 +00:00
#endif
2023-11-23 07:22:09 +00:00
CVEstimator.Instance.Init();//初始化姿态检测
}
2023-11-07 13:55:35 +00:00
2023-11-24 05:13:10 +00:00
#if UNITY_ANDROID && !UNITY_EDITOR
2023-11-23 07:22:09 +00:00
#region UVC
public UVCFilter[] UVCFilters;
private Texture SavedTexture;
public bool OnUVCAttachEvent(UVCManager manager, UVCDevice device)
{
var result = !device.IsRicoh || device.IsTHETA;
2023-11-07 13:55:35 +00:00
2023-11-23 07:22:09 +00:00
result &= UVCFilter.Match(device, UVCFilters);
2023-11-07 13:55:35 +00:00
2023-11-23 07:22:09 +00:00
return result;
2023-11-07 13:55:35 +00:00
}
2023-11-23 07:22:09 +00:00
public void OnUVCDetachEvent(UVCManager manager, UVCDevice device)
2023-11-07 13:55:35 +00:00
{
2023-11-24 05:13:10 +00:00
LogPrint.Log("OnUVCDetachEvent " + device);
2023-11-23 07:22:09 +00:00
}
public bool CanDraw(UVCManager manager, UVCDevice device)
{
return UVCFilter.Match(device, UVCFilters);
}
public void OnUVCStartEvent(UVCManager manager, UVCDevice device, Texture tex)
{
HandleOnStartPreview(tex);
}
public void OnUVCStopEvent(UVCManager manager, UVCDevice device)
{
HandleOnStopPreview();
}
private void HandleOnStartPreview(Texture tex)
{
SavedTexture = TargetDisplayer.texture;
2023-11-24 05:13:10 +00:00
TargetDisplayer.texture = _displayTexture;
2023-11-23 07:22:09 +00:00
}
private void HandleOnStopPreview()
{
RestoreTexture();
}
private void RestoreTexture()
{
try
2023-11-07 13:55:35 +00:00
{
2023-11-23 07:22:09 +00:00
transform.GetComponent<Renderer>().material.mainTexture = SavedTexture;
2023-11-07 13:55:35 +00:00
}
2023-11-23 07:22:09 +00:00
catch (Exception e)
{
Debug.LogException(e);
}
SavedTexture = null;
}
#endregion
2023-11-24 05:13:10 +00:00
#endif
2023-11-22 19:42:29 +00:00
2023-11-24 05:13:10 +00:00
public Texture2D HorizontalFlipTexture(Texture2D texture)
2023-11-23 07:22:09 +00:00
{
//得到图片的宽高
2023-11-24 05:13:10 +00:00
Texture2D retVal = new Texture2D(texture.width, texture.height);
RenderTexture tmp = RenderTexture.GetTemporary(texture.width, texture.height, 0, RenderTextureFormat.ARGB32);
Graphics.Blit(texture, tmp, _flipImg);
RenderTexture.active = tmp;
retVal.ReadPixels(new UnityEngine.Rect(0, 0, texture.width, texture.height), 0, 0);
RenderTexture.ReleaseTemporary(tmp);
return retVal;
2023-11-23 07:22:09 +00:00
}
private Mat GetMat()
{
Mat img = null;
2023-11-24 05:13:10 +00:00
#if UNITY_ANDROID && !UNITY_EDITOR
2023-11-23 07:22:09 +00:00
if (GlobalData.Instance.CameraDeviceType == CameraDeviceType.USB &&
UVCManager.Instance != null &&
UVCManager.Instance.GetAttachedDevices() != null && UVCManager.Instance.GetAttachedDevices().Count > 0)
{
var devices = UVCManager.Instance.GetAttachedDevices();
2023-11-24 05:13:10 +00:00
for (int i = 0; i < devices.Count; i++)
{
UVCManager.CameraInfo device = devices[i];
LogPrint.Error($"id:{i},pid:{device.Pid},vid:{device.Vid},deviceName:{device.DeviceName}");
}
2023-11-23 07:22:09 +00:00
var formatRefMat = _webCamTextureToMatHelper.GetMat();
2023-11-24 05:13:10 +00:00
var picCaptured = devices.FirstOrDefault().previewTexture;
Texture2D tmpTex = new Texture2D(picCaptured.width, picCaptured.height);
2023-11-23 07:22:09 +00:00
Utils.textureToTexture2D(picCaptured, tmpTex);
tmpTex = HorizontalFlipTexture(tmpTex);//picCaptured texture水平反转
img = new Mat(formatRefMat.rows(), formatRefMat.cols(), formatRefMat.type());
Utils.texture2DToMat(tmpTex, img);
}
else
2023-11-24 05:13:10 +00:00
#endif
2023-11-23 07:22:09 +00:00
{
if (_webCamTextureToMatHelper.IsPlaying() && _webCamTextureToMatHelper.DidUpdateThisFrame())
{
img = _webCamTextureToMatHelper.GetMat();
Imgproc.cvtColor(img, img, Imgproc.COLOR_BGR2RGB);
}
}
return img;
}
private void Update()
{
if (!_isOnCamCapture)
2023-11-22 19:42:29 +00:00
{
2023-11-23 07:22:09 +00:00
return;
2023-11-22 19:42:29 +00:00
}
2023-11-07 13:55:35 +00:00
if (!transform.gameObject.activeSelf)
transform.gameObject.SetActive(true);
2023-11-23 07:22:09 +00:00
Mat img = GetMat();
2023-11-15 08:10:56 +00:00
2023-11-23 07:22:09 +00:00
if (img == null)
return;
2023-11-15 08:10:56 +00:00
2023-11-07 13:55:35 +00:00
2023-11-23 07:22:09 +00:00
YogaManager.Instance.RgbaMat = img.clone();
YogaManager.Instance.CurrentEstimator.Check(ref img);//检测模型,将错误信息打印在图片上
2023-11-07 13:55:35 +00:00
2023-11-23 07:22:09 +00:00
if (YogaManager.Instance.VoloResult.Count >= 2)
YogaManager.Instance.CurrentEstimator.DebugPrint(img);
2023-11-07 13:55:35 +00:00
2023-11-23 07:22:09 +00:00
if (YogaManager.Instance.CurrPersonPoints != null && YogaManager.Instance.CurrPersonPoints.Count > 0)
{
List<Point> points = YogaManager.Instance.CurrPersonPoints;
2023-11-07 13:55:35 +00:00
2023-11-23 07:22:09 +00:00
for (int i = 0; i < YogaConfig.POSE_PAIRS.GetLength(0); i++)
{
string partFrom = YogaConfig.POSE_PAIRS[i, 0];
string partTo = YogaConfig.POSE_PAIRS[i, 1];
int idFrom = YogaConfig.BODY_PARTS[partFrom];
int idTo = YogaConfig.BODY_PARTS[partTo];
2023-11-07 13:55:35 +00:00
2023-11-23 07:22:09 +00:00
if (points[idFrom] == new Point(-1, -1) || points[idTo] == new Point(-1, -1))
continue;
2023-11-07 16:51:42 +00:00
2023-11-23 07:22:09 +00:00
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);
2023-11-07 13:55:35 +00:00
}
}
}
2023-11-23 07:22:09 +00:00
2023-11-24 05:13:10 +00:00
Utils.matToTexture2D(img, _displayTexture);
2023-11-07 13:55:35 +00:00
}
2023-11-12 15:09:33 +00:00
#region Event Func
private void OnStartMotionCapture()
{
this.enabled = true;
_isOnCamCapture = true;
CVEstimator.Instance.StartEstimation();//开始姿态检测
}
private void OnStopMotionCapture()
{
this.enabled = false;
_isOnCamCapture = false;
}
2023-11-13 02:53:34 +00:00
private void GetActionBasePoint()
2023-11-12 15:09:33 +00:00
{
2023-11-13 02:53:34 +00:00
var startTime = DateTime.Now;
while (true)
{
2023-11-23 07:22:09 +00:00
if (YogaManager.Instance.CurrPersonPoints != null && YogaManager.Instance.CurrPersonPoints.Count != 0)
2023-11-13 02:53:34 +00:00
{
2023-11-23 07:22:09 +00:00
YogaManager.Instance.Points = YogaManager.Instance.CurrPersonPoints;
2023-11-13 02:53:34 +00:00
break;
}
if (startTime.AddMilliseconds(100) < DateTime.Now)
{
2023-11-24 05:13:10 +00:00
LogPrint.Error("GetActionBasePoint timeout");
2023-11-13 02:53:34 +00:00
break;
}
}
2023-11-12 15:09:33 +00:00
}
2023-11-13 02:53:34 +00:00
private void EstimateAction(params object[] args)
2023-11-07 13:55:35 +00:00
{
2023-11-07 16:51:42 +00:00
var type = args.FirstOrDefault();
if (type == null)
{
2023-11-24 05:13:10 +00:00
LogPrint.Error("EstimateAction type is null");
2023-11-07 16:51:42 +00:00
return;
}
AvatarAction actionType = (AvatarAction)args.FirstOrDefault();
2023-11-12 15:09:33 +00:00
2023-11-14 17:01:48 +00:00
2023-11-12 15:09:33 +00:00
//检测动作
2023-11-13 02:53:34 +00:00
var startTime = DateTime.Now;
2023-11-07 13:55:35 +00:00
2023-11-13 02:53:34 +00:00
while (true)
2023-11-07 13:55:35 +00:00
{
2023-11-23 07:22:09 +00:00
if (YogaManager.Instance.ActionCheckPoints(YogaManager.Instance.CurrPersonPoints))
2023-11-07 13:55:35 +00:00
{
2023-11-23 07:22:09 +00:00
_isCorrectAction = (_isCorrectAction || YogaManager.Instance.IsCorrectAction(YogaManager.Instance.CurrPersonPoints, actionType));
2023-11-13 02:53:34 +00:00
break;
2023-11-07 13:55:35 +00:00
}
2023-11-13 02:53:34 +00:00
if (startTime.AddMilliseconds(100) < DateTime.Now)
2023-11-12 15:09:33 +00:00
{
2023-11-24 05:13:10 +00:00
LogPrint.Warning("请摆正姿势");
LogPrint.Warning("EstimateAction timeout");
2023-11-13 02:53:34 +00:00
break;
2023-11-12 15:09:33 +00:00
}
2023-11-07 13:55:35 +00:00
}
}
2023-11-22 19:42:29 +00:00
private void ChangeCaptureCameraDevice()
{
var deviceName = WebCamTexture.devices[GlobalData.Instance.CameraIndex].name;
var width = _webCamTextureToMatHelper.GetWidth();
var height = _webCamTextureToMatHelper.GetHeight();
var fps = _webCamTextureToMatHelper.GetFPS();
if (fps > 0)
{
_webCamTextureToMatHelper.Initialize(deviceName, width, height, requestedFPS: fps);
}
else
{
_webCamTextureToMatHelper.Initialize(deviceName, width, height);
}
}
private void ChangeToUSBCaptureCamera()
{
}
2023-11-13 02:53:34 +00:00
#endregion
2023-11-07 13:55:35 +00:00
/// <summary>
/// Raises the destroy event.
/// </summary>
void OnDestroy()
{
_webCamTextureToMatHelper.Dispose();
2023-11-15 08:10:56 +00:00
YogaManager.Instance.CurrentEstimator.Dispose();
2023-11-07 13:55:35 +00:00
_bgrMat.Dispose();
2023-11-12 15:09:33 +00:00
CVEstimator.Instance.Dispose();
2023-11-07 13:55:35 +00:00
}
public void OnWebCamTextureToMatHelperInitialized()
{
2023-11-24 05:13:10 +00:00
LogPrint.Log("OnWebCamTextureToMatHelperInitialized");
2023-11-07 13:55:35 +00:00
Mat webCamTextureMat = _webCamTextureToMatHelper.GetMat();
2023-11-24 05:13:10 +00:00
_displayTexture = new Texture2D(webCamTextureMat.cols(), webCamTextureMat.rows(), TextureFormat.RGB24, false);
Utils.matToTexture2D(webCamTextureMat, _displayTexture);
2023-11-07 13:55:35 +00:00
2023-11-23 07:22:09 +00:00
//gameObject.GetComponent<Renderer>().material.mainTexture = texture;
2023-11-24 05:13:10 +00:00
TargetDisplayer.texture = _displayTexture;
2023-11-07 13:55:35 +00:00
gameObject.transform.localScale = new Vector3(webCamTextureMat.cols() / 10, webCamTextureMat.rows() / 10, 1);
2023-11-24 05:13:10 +00:00
LogPrint.Log("Screen.width " + Screen.width + " Screen.height " + Screen.height + " Screen.orientation " + Screen.orientation);
2023-11-07 13:55:35 +00:00
float width = webCamTextureMat.width();
float height = webCamTextureMat.height();
float widthScale = (float)Screen.width / width;
float heightScale = (float)Screen.height / height;
if (widthScale < heightScale)
{
Camera.main.orthographicSize = (width * (float)Screen.height / (float)Screen.width) / 2;
}
else
{
Camera.main.orthographicSize = height / 2;
}
_bgrMat = new Mat(webCamTextureMat.rows(), webCamTextureMat.cols(), CvType.CV_8UC3);
}
//event call
public void OnWebCamTextureToMatHelperDisposed()
{
2023-11-24 05:13:10 +00:00
LogPrint.Log("OnWebCamTextureToMatHelperDisposed");
2023-11-07 13:55:35 +00:00
if (_bgrMat != null)
_bgrMat.Dispose();
2023-11-24 05:13:10 +00:00
if (_displayTexture != null)
2023-11-07 13:55:35 +00:00
{
2023-11-24 05:13:10 +00:00
Texture2D.Destroy(_displayTexture);
_displayTexture = null;
2023-11-07 13:55:35 +00:00
}
}
public void OnWebCamTextureToMatHelperErrorOccurred(WebCamTextureToMatHelper.ErrorCode errorCode)
{
2023-11-24 05:13:10 +00:00
LogPrint.Log("OnWebCamTextureToMatHelperErrorOccurred " + errorCode);
}
2023-11-07 13:55:35 +00:00
public void ScoreUpdate()
{
2023-11-07 15:28:19 +00:00
if (_isCorrectAction)
{
2023-11-10 08:12:37 +00:00
EventManager.Instance.Dispatch(YogaEventType.ActionSuccess);
2023-11-07 13:55:35 +00:00
}
else
{
2023-11-10 08:12:37 +00:00
EventManager.Instance.Dispatch(YogaEventType.ActionFailed);
2023-11-07 13:55:35 +00:00
}
2023-11-07 16:51:42 +00:00
_isCorrectAction = false;//重置
2023-11-07 13:55:35 +00:00
}
}
2023-11-23 07:22:09 +00:00
public abstract class CameraCaptureManagerBase : MonoBehaviour
{
}
2023-11-07 13:55:35 +00:00
}