diff --git a/Wpf_AiSportsMicrospace/Common/SportOperate.cs b/Wpf_AiSportsMicrospace/Common/SportOperate.cs index 936e7df..13afba2 100644 --- a/Wpf_AiSportsMicrospace/Common/SportOperate.cs +++ b/Wpf_AiSportsMicrospace/Common/SportOperate.cs @@ -27,7 +27,11 @@ namespace Wpf_AiSportsMicrospace.Common IPointTracker _rightTracker; IPointTracker _leftElbow; IPointTracker _rightElbow; - WebcamClient _webcamClient; + WebcamClient _webcamClient; + private Point? _lastWrist = null; // 上一帧的手腕位置 + private DateTime _lastActionTime = DateTime.MinValue; // 上次动作时间 + private readonly TimeSpan _cooldown = TimeSpan.FromMilliseconds(800); // 动作冷却,避免误触发 + public SportOperate() { @@ -41,6 +45,7 @@ namespace Wpf_AiSportsMicrospace.Common _leftElbow.Amplitude = 0.05f; _rightElbow.Amplitude = 0.05f; } + public WebcamClient CreateRTSP() { _webcamClient = WebcamClient.CreateRTSP("192.168.3.64", "admin", "yd708090", 554u); @@ -59,13 +64,18 @@ namespace Wpf_AiSportsMicrospace.Common var rightElbowResult = _rightElbow.Tracking(human); // 节流:每 300ms 最多更新一次 UI - if ((DateTime.Now - _lastSlideTime).TotalMilliseconds < 500) return 0; - _lastSlideTime = DateTime.Now; + //if ((DateTime.Now - _lastSlideTime).TotalMilliseconds < 500) return 0; + //_lastSlideTime = DateTime.Now; // 根据手势结果选择滑动方向 if (leftResult != 0 && leftElbowResult != 0) return 1; - if (rightResult != 0 & rightElbowResult != 0) return 2; - + if (rightResult != 0 & rightElbowResult != 0) + { + 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)); + } return 0; } @@ -84,5 +94,46 @@ namespace Wpf_AiSportsMicrospace.Common return 0; } + + public int RecognizeRightHandGesture(Point wrist, Point elbow) + { + // 判断举手:手腕在肘部之上,且垂直距离超过一定阈值 + if (wrist.Y + 40 < elbow.Y) // 手腕比肘高 40 像素以上 + { + if (CheckCooldown()) + return 3; // 举手 + } + + // 需要至少两帧来判断水平移动方向 + 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; // 左挥手 + } + } + } + + _lastWrist = wrist; + return 0; + } + private bool CheckCooldown() + { + if (DateTime.Now - _lastActionTime > _cooldown) + { + _lastActionTime = DateTime.Now; + return true; + } + return false; + } } } diff --git a/Wpf_AiSportsMicrospace/Home.xaml.cs b/Wpf_AiSportsMicrospace/Home.xaml.cs index 25e5f12..e1afa20 100644 --- a/Wpf_AiSportsMicrospace/Home.xaml.cs +++ b/Wpf_AiSportsMicrospace/Home.xaml.cs @@ -15,6 +15,7 @@ using System.Windows.Media; using System.Windows.Media.Animation; using Wpf_AiSportsMicrospace.Common; using Wpf_AiSportsMicrospace.MyUserControl; +using Wpf_AiSportsMicrospace.Views; using Yunzhi.Database; using Yztob.AiSports.Inferences.Abstractions; using Yztob.AiSports.Postures; @@ -96,14 +97,32 @@ namespace Wpf_AiSportsMicrospace if (item.ImageUri.ToString().EndsWith("1.jpg")) { // 跳转到页面1 + Dispatcher.BeginInvoke(new Action(() => + { + GroupJumpRope groupJumpRope = new GroupJumpRope(); + groupJumpRope.Owner = Application.Current.MainWindow; + groupJumpRope.Show(); + })); } else if (item.ImageUri.ToString().EndsWith("2.jpg")) { // 跳转到页面2 + Dispatcher.BeginInvoke(new Action(() => + { + GroupJumpRope groupJumpRope = new GroupJumpRope(); + groupJumpRope.Owner = Application.Current.MainWindow; + groupJumpRope.Show(); + })); } else if (item.ImageUri.ToString().EndsWith("3.jpg")) { // 跳转到页面3 + Dispatcher.BeginInvoke(new Action(() => + { + GroupJumpRope groupJumpRope = new GroupJumpRope(); + groupJumpRope.Owner = Application.Current.MainWindow; + groupJumpRope.Show(); + })); } } @@ -148,33 +167,33 @@ namespace Wpf_AiSportsMicrospace if (human == null) return; + //检测挥手动作 + var wavingaction = _sportOperate.VerifyWavingAction(human); - // 启动进度条动画; - //SlideCoverFlow(coverFlow.StartSelectedProgress); - - ////检测挥手动作 - //var wavingAction = _sportOperate.VerifyWavingAction(human); - //// 根据手势结果选择滑动方向 - //if (wavingAction == 1) - //{ - // SlideCoverFlow(coverFlow.SlideRight); - // return; - //} - //if (wavingAction == 2) - //{ - // SlideCoverFlow(coverFlow.SlideLeft); - // return; - //} - - //检测举手动作 - var liftHandAction = _sportOperate.VerifyLiftHandAction(human); - - // 根据手势结果 - if (liftHandAction == 1) + switch (wavingaction) { - // 启动进度条动画; - Dispatcher.BeginInvoke(() => coverFlow.StartSelectedProgress()); + case 1: + Dispatcher.BeginInvoke(() => coverFlow.SlideLeft()); + break; + case 2: + Dispatcher.BeginInvoke(() => coverFlow.SlideRight()); + break; + case 3: + Dispatcher.BeginInvoke(() => coverFlow.StartSelectedProgress()); + break; + default: + break; } + + ////检测举手动作 + //var liftHandAction = _sportOperate.VerifyLiftHandAction(human); + + //// 根据手势结果 + //if (liftHandAction == 1) + //{ + // // 启动进度条动画; + // Dispatcher.BeginInvoke(() => coverFlow.StartSelectedProgress()); + //} } catch (Exception ex) { diff --git a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml new file mode 100644 index 0000000..26ba7e6 --- /dev/null +++ b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml @@ -0,0 +1,12 @@ + + + + + diff --git a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs new file mode 100644 index 0000000..e26ef5a --- /dev/null +++ b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; + +namespace Wpf_AiSportsMicrospace.Views +{ + /// + /// GroupJumpRope.xaml 的交互逻辑 + /// + public partial class GroupJumpRope : Window + { + public GroupJumpRope() + { + InitializeComponent(); + } + } +} diff --git a/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml b/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml new file mode 100644 index 0000000..32f139b --- /dev/null +++ b/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml @@ -0,0 +1,12 @@ + + + + + diff --git a/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml.cs b/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml.cs new file mode 100644 index 0000000..3235a2d --- /dev/null +++ b/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; + +namespace Wpf_AiSportsMicrospace.Views +{ + /// + /// MusicJumpRope.xaml 的交互逻辑 + /// + public partial class MusicJumpRope : Window + { + public MusicJumpRope() + { + InitializeComponent(); + } + } +}