diff --git a/Wpf_AiSportsMicrospace/Common/SportOperate.cs b/Wpf_AiSportsMicrospace/Common/SportOperate.cs
index 13afba2..3335a80 100644
--- a/Wpf_AiSportsMicrospace/Common/SportOperate.cs
+++ b/Wpf_AiSportsMicrospace/Common/SportOperate.cs
@@ -5,6 +5,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
+using Wpf_AiSportsMicrospace.Enum;
using Yztob.AiSports.Inferences.Abstractions;
using Yztob.AiSports.Inferences.Things;
using Yztob.AiSports.Postures;
@@ -21,16 +22,17 @@ namespace Wpf_AiSportsMicrospace.Common
///
public class SportOperate
{
- private DateTime _lastSlideTime = DateTime.MinValue;
-
IPointTracker _leftTracker;
IPointTracker _rightTracker;
IPointTracker _leftElbow;
IPointTracker _rightElbow;
- WebcamClient _webcamClient;
- private Point? _lastWrist = null; // 上一帧的手腕位置
- private DateTime _lastActionTime = DateTime.MinValue; // 上次动作时间
- private readonly TimeSpan _cooldown = TimeSpan.FromMilliseconds(800); // 动作冷却,避免误触发
+ WebcamClient _webcamClient;
+
+ private Point? _lastLeftWrist = null;
+ private Point? _lastRightWrist = null;
+ private DateTime _lastActionTime = DateTime.MinValue;
+ // 记录举手开始时间
+ private DateTime? _raiseStartTime = null;
public SportOperate()
@@ -52,88 +54,120 @@ namespace Wpf_AiSportsMicrospace.Common
return _webcamClient;
}
- ///
- /// 验证挥手动作[0:无效,1:左,2:右]
- ///
- ///
public int VerifyWavingAction(Human human)
{
- var leftResult = _leftTracker.Tracking(human);
- var rightResult = _rightTracker.Tracking(human);
- var leftElbowResult = _leftElbow.Tracking(human);
- var rightElbowResult = _rightElbow.Tracking(human);
+ var leftWrist = human.Keypoints.FirstOrDefault(x => x.Name == "left_wrist");
+ var leftElbow = human.Keypoints.FirstOrDefault(x => x.Name == "left_elbow");
+ var rightWrist = human.Keypoints.FirstOrDefault(x => x.Name == "right_wrist");
+ var rightElbow = human.Keypoints.FirstOrDefault(x => x.Name == "right_elbow");
- // 节流:每 300ms 最多更新一次 UI
- //if ((DateTime.Now - _lastSlideTime).TotalMilliseconds < 500) return 0;
- //_lastSlideTime = DateTime.Now;
-
- // 根据手势结果选择滑动方向
- if (leftResult != 0 && leftElbowResult != 0) return 1;
- if (rightResult != 0 & rightElbowResult != 0)
+ // 左手逻辑
+ if (leftWrist != null && leftElbow != null)
{
- var wrist = human.Keypoints.Where(x => x.Name == "right_wrist").FirstOrDefault();
- var elbow = human.Keypoints.Where(x => x.Name == "right_elbow").FirstOrDefault();
- if (wrist == null || elbow == null) return 0;
- return RecognizeRightHandGesture(new Point(wrist.X, wrist.Y), new Point(elbow.X, elbow.Y));
+ var result = RecognizeLeftHandGesture(
+ new Point(leftWrist.X, leftWrist.Y),
+ new Point(leftElbow.X, leftElbow.Y));
+ if (result != 0) return result;
}
- return 0;
- }
-
- public int VerifyLiftHandAction(Human human)
- {
- var rightResult = _rightTracker.Tracking(human);
- var rightElbowResult = _rightElbow.Tracking(human);
-
- // 节流:每 300ms 最多更新一次 UI
- if ((DateTime.Now - _lastSlideTime).TotalMilliseconds < 500) return 0;
- _lastSlideTime = DateTime.Now;
-
- // 根据手势结果选择滑动方向
- if (rightResult != 0 & rightElbowResult != 0) return 1;
+ // 右手逻辑
+ if (rightWrist != null && rightElbow != null)
+ {
+ var result = RecognizeRightHandGesture(
+ new Point(rightWrist.X, rightWrist.Y),
+ new Point(rightElbow.X, rightElbow.Y));
+ if (result != 0) return result;
+ }
return 0;
}
- public int RecognizeRightHandGesture(Point wrist, Point elbow)
+ ///
+ /// 识别左手动作(左→右为 1)
+ ///
+ public int RecognizeLeftHandGesture(Point wrist, Point elbow)
{
- // 判断举手:手腕在肘部之上,且垂直距离超过一定阈值
- if (wrist.Y + 40 < elbow.Y) // 手腕比肘高 40 像素以上
+ if (_lastLeftWrist != null)
{
- if (CheckCooldown())
- return 3; // 举手
- }
+ double dx = wrist.X - _lastLeftWrist.Value.X;
+ double dy = Math.Abs(wrist.Y - _lastLeftWrist.Value.Y);
- // 需要至少两帧来判断水平移动方向
- if (_lastWrist != null)
- {
- double dx = wrist.X - _lastWrist.Value.X; // 水平位移
- double dy = Math.Abs(wrist.Y - _lastWrist.Value.Y);
-
- // 要求水平位移明显大于垂直位移,且超过一定阈值
if (Math.Abs(dx) > 30 && dy < 40)
{
if (CheckCooldown())
{
if (dx > 0)
- return 2; // 右挥手
- else
- return 1; // 左挥手
+ return 1; // 左手往右挥
}
}
}
- _lastWrist = wrist;
+ _lastLeftWrist = wrist;
return 0;
}
- private bool CheckCooldown()
+
+ ///
+ /// 识别右手动作(右→左为 2,举手为 3)
+ ///
+
+ public int RecognizeRightHandGesture(Point wrist, Point elbow)
{
- if (DateTime.Now - _lastActionTime > _cooldown)
+ // 判断手腕是否在肘部上方,并且达到高度阈值
+ //if (wrist.Y + 40 < elbow.Y && wrist.Y < minRaiseHeight)
+ if (wrist.Y + 40 < elbow.Y)
{
- _lastActionTime = DateTime.Now;
- return true;
+ if (_raiseStartTime == null)
+ {
+ _raiseStartTime = DateTime.Now;
+ return (int)WavingAction.FirstHand;
+ }
+
+ var duration = DateTime.Now - _raiseStartTime.Value;
+ if (duration.TotalSeconds >= 3)
+ {
+ _raiseStartTime = null;
+ return (int)WavingAction.RaiseHand; // 举手完成
+ }
+ else
+ {
+ return (int)WavingAction.Raising; // 举手中
+ }
}
- return false;
+ else
+ {
+ _raiseStartTime = null;
+ }
+
+ // 挥手逻辑
+ if (_lastRightWrist != null)
+ {
+ double dx = wrist.X - _lastRightWrist.Value.X;
+ double dy = Math.Abs(wrist.Y - _lastRightWrist.Value.Y);
+
+ if (Math.Abs(dx) > 30 && dy < 40)
+ {
+ if (CheckCooldown())
+ {
+ if (dx < 0)
+ return 2; // 右手往左挥
+ }
+ }
+ }
+
+ _lastRightWrist = wrist;
+ return 0;
+ }
+
+ ///
+ /// 冷却防抖(避免重复触发)
+ ///
+ private bool CheckCooldown(int cooldownMs = 500)
+ {
+ if ((DateTime.Now - _lastActionTime).TotalMilliseconds < cooldownMs)
+ return false;
+
+ _lastActionTime = DateTime.Now;
+ return true;
}
}
}
diff --git a/Wpf_AiSportsMicrospace/Enum/WavingAction.cs b/Wpf_AiSportsMicrospace/Enum/WavingAction.cs
new file mode 100644
index 0000000..323e2fd
--- /dev/null
+++ b/Wpf_AiSportsMicrospace/Enum/WavingAction.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Wpf_AiSportsMicrospace.Enum
+{
+ public enum WavingAction
+ {
+ None = 0, // 没动作
+ LeftWave = 1, // 左挥手
+ RightWave = 2, // 右挥手
+ RaiseHand = 3, // 举手完成
+ Raising = 4, // 举手中,未完成
+ FirstHand = 5,//首次举手
+ }
+}
+
diff --git a/Wpf_AiSportsMicrospace/Home.xaml.cs b/Wpf_AiSportsMicrospace/Home.xaml.cs
index e1afa20..2be5cdd 100644
--- a/Wpf_AiSportsMicrospace/Home.xaml.cs
+++ b/Wpf_AiSportsMicrospace/Home.xaml.cs
@@ -5,6 +5,7 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
+using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
@@ -14,6 +15,7 @@ using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;
using Wpf_AiSportsMicrospace.Common;
+using Wpf_AiSportsMicrospace.Enum;
using Wpf_AiSportsMicrospace.MyUserControl;
using Wpf_AiSportsMicrospace.Views;
using Yunzhi.Database;
@@ -33,11 +35,6 @@ namespace Wpf_AiSportsMicrospace
public partial class Home : Window
{
private IHumanPredictor _humanPredictor;
- private IObjectDetector _objectDetector;
- private HumanGraphicsRenderer _humanGraphicsRenderer;
- private readonly List _sports;
- private SportBase _sport;
- private readonly SportDetectionQueue _detectQueue;
private WebcamClient _webcamClient;
private ConcurrentQueue _frameQueue = new();
private CancellationTokenSource _cts = new();
@@ -47,12 +44,6 @@ namespace Wpf_AiSportsMicrospace
{
InitializeComponent();
_humanPredictor = HumanPredictorFactory.Create(HumanPredictorType.SingleHigh);
- _objectDetector = ObjectDetectorFactory.CreateSportGoodsDetector();
- _humanGraphicsRenderer = new HumanGraphicsRenderer();
- _humanGraphicsRenderer.DrawLabel = false;
-
- //_sports = SportBase.GetSports();
- //_detectQueue = new SportDetectionQueue();
string projectRoot = Path.Combine(AppContext.BaseDirectory, @"..\..\..");
string albumPath = Path.Combine(projectRoot, "Resources", "Img", "Album");
@@ -73,7 +64,7 @@ namespace Wpf_AiSportsMicrospace
coverFlow.SelectedIndex = 2;
// 监听进度条完成事件
- coverFlow.ProgressCompleted += CoverFlow_ProgressCompleted;
+ //coverFlow.ProgressCompleted += CoverFlow_ProgressCompleted;
}
private void Window_Loaded(object sender, RoutedEventArgs e)
@@ -93,36 +84,35 @@ namespace Wpf_AiSportsMicrospace
private void CoverFlow_ProgressCompleted(CoverFlowItem item)
{
- // 根据不同图片跳转不同页面
- if (item.ImageUri.ToString().EndsWith("1.jpg"))
+ // 停止抽帧线程/释放资源
+ try
{
- // 跳转到页面1
- Dispatcher.BeginInvoke(new Action(() =>
- {
- GroupJumpRope groupJumpRope = new GroupJumpRope();
- groupJumpRope.Owner = Application.Current.MainWindow;
- groupJumpRope.Show();
- }));
+ _webcamClient?.StopExtract(); // 停止抽帧
+ _webcamClient = null; // 释放引用
}
- else if (item.ImageUri.ToString().EndsWith("2.jpg"))
+ catch (Exception ex)
{
- // 跳转到页面2
- Dispatcher.BeginInvoke(new Action(() =>
- {
- GroupJumpRope groupJumpRope = new GroupJumpRope();
- groupJumpRope.Owner = Application.Current.MainWindow;
- groupJumpRope.Show();
- }));
+ Debug.WriteLine($"停止抽帧异常: {ex.Message}");
}
- else if (item.ImageUri.ToString().EndsWith("3.jpg"))
+
+ // 根据图片跳转新窗口
+ string uri = item.ImageUri.ToString();
+ Window newWindow = null;
+
+ if (uri.EndsWith("1.jpg"))
+ newWindow = new GroupJumpRope();
+ else if (uri.EndsWith("2.jpg"))
+ newWindow = new GroupJumpRope();
+ else if (uri.EndsWith("3.jpg"))
+ newWindow = new GroupJumpRope();
+
+ if (newWindow != null)
{
- // 跳转到页面3
- Dispatcher.BeginInvoke(new Action(() =>
+ Dispatcher.BeginInvoke(() =>
{
- GroupJumpRope groupJumpRope = new GroupJumpRope();
- groupJumpRope.Owner = Application.Current.MainWindow;
- groupJumpRope.Show();
- }));
+ newWindow.Show(); // 先显示新窗口
+ this.Close(); // 再关闭当前窗口
+ });
}
}
@@ -169,31 +159,27 @@ namespace Wpf_AiSportsMicrospace
//检测挥手动作
var wavingaction = _sportOperate.VerifyWavingAction(human);
-
switch (wavingaction)
{
- case 1:
+ case (int)WavingAction.LeftWave: // 1
Dispatcher.BeginInvoke(() => coverFlow.SlideLeft());
break;
- case 2:
+ case (int)WavingAction.RightWave: // 2
Dispatcher.BeginInvoke(() => coverFlow.SlideRight());
break;
- case 3:
+ case (int)WavingAction.RaiseHand: // 3 举手完成
+ coverFlow.ProgressCompleted += CoverFlow_ProgressCompleted;
+ break;
+ case (int)WavingAction.Raising: // 4 举手中
+ break;
+ case 5: // 如果还有其他动作
Dispatcher.BeginInvoke(() => coverFlow.StartSelectedProgress());
break;
default:
+ Dispatcher.BeginInvoke(() => coverFlow.CancelSelectedProgress());
break;
}
- ////检测举手动作
- //var liftHandAction = _sportOperate.VerifyLiftHandAction(human);
-
- //// 根据手势结果
- //if (liftHandAction == 1)
- //{
- // // 启动进度条动画;
- // Dispatcher.BeginInvoke(() => coverFlow.StartSelectedProgress());
- //}
}
catch (Exception ex)
{
diff --git a/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl1.xaml.cs b/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl1.xaml.cs
index b08cd03..2f791fa 100644
--- a/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl1.xaml.cs
+++ b/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl1.xaml.cs
@@ -81,11 +81,24 @@ namespace Wpf_AiSportsMicrospace.MyUserControl
{
if (SelectedIndex >= 0 && SelectedIndex < Images.Count)
{
- var current = Images[SelectedIndex];
+ var current = Images[SelectedIndex];
+ if (current.Progress >= 1) return; // 已完成,直接返回,不再启动
StartProgress(current);
}
}
+ public void CancelSelectedProgress()
+ {
+ if (SelectedIndex >= 0 && SelectedIndex < Images.Count)
+ {
+ var current = Images[SelectedIndex];
+ // 停止动画/计时
+ StopProgress();
+
+ // 清零当前的进度值
+ current.Progress = 0;
+ }
+ }
public void StartProgress(CoverFlowItem item)
{
StopProgress();
@@ -257,7 +270,15 @@ namespace Wpf_AiSportsMicrospace.MyUserControl
return null;
}
- public void SlideLeft() => SelectedIndex++;
- public void SlideRight() => SelectedIndex--;
+ public void SlideLeft()
+ {
+ StopProgress();
+ SelectedIndex++;
+ }
+ public void SlideRight()
+ {
+ StopProgress();
+ SelectedIndex--;
+ }
}
}