diff --git a/Wpf_AiSportsMicrospace/Common/SportOperate.cs b/Wpf_AiSportsMicrospace/Common/SportOperate.cs index 3335a80..4c12a8a 100644 --- a/Wpf_AiSportsMicrospace/Common/SportOperate.cs +++ b/Wpf_AiSportsMicrospace/Common/SportOperate.cs @@ -28,11 +28,12 @@ namespace Wpf_AiSportsMicrospace.Common IPointTracker _rightElbow; WebcamClient _webcamClient; + private DateTime _lastActionTime = DateTime.MinValue; + private Point? _lastLeftWrist = null; private Point? _lastRightWrist = null; - private DateTime _lastActionTime = DateTime.MinValue; - // 记录举手开始时间 private DateTime? _raiseStartTime = null; + private DateTime? _wristStartTime = null; public SportOperate() @@ -42,10 +43,10 @@ namespace Wpf_AiSportsMicrospace.Common _leftElbow = PostureCalculate.CreatePointTracker("left_elbow", 0); _rightElbow = PostureCalculate.CreatePointTracker("right_elbow", 0); - _leftTracker.Amplitude = 0.05f; - _rightTracker.Amplitude = 0.05f; - _leftElbow.Amplitude = 0.05f; - _rightElbow.Amplitude = 0.05f; + //_leftTracker.Amplitude = 0.05f; + //_rightTracker.Amplitude = 0.05f; + //_leftElbow.Amplitude = 0.05f; + //_rightElbow.Amplitude = 0.05f; } public WebcamClient CreateRTSP() @@ -83,49 +84,82 @@ namespace Wpf_AiSportsMicrospace.Common } /// - /// 识别左手动作(左→右为 1) + /// 统一的水平挥手检测 /// - public int RecognizeLeftHandGesture(Point wrist, Point elbow) + private int DetectHorizontalWave(Point wrist, Point elbow, Point? lastWrist, bool isLeft) { - if (_lastLeftWrist != null) + if (lastWrist != null) { - double dx = wrist.X - _lastLeftWrist.Value.X; - double dy = Math.Abs(wrist.Y - _lastLeftWrist.Value.Y); + double dx = wrist.X - lastWrist.Value.X; + double dy = Math.Abs(wrist.Y - lastWrist.Value.Y); - if (Math.Abs(dx) > 30 && dy < 40) + // 挥手:水平位移明显,垂直位移小,且接近肘部水平 + if (Math.Abs(dx) > 30 && dy < 40 && Math.Abs(wrist.Y - elbow.Y) < 100) { if (CheckCooldown()) { - if (dx > 0) - return 1; // 左手往右挥 + if (isLeft && dx > 0) + return (int)WavingAction.LeftWave; // 左手往右挥 + if (!isLeft && dx < 0) + return (int)WavingAction.RightWave; // 右手往左挥 } } } - - _lastLeftWrist = wrist; - return 0; + return (int)WavingAction.None; } /// - /// 识别右手动作(右→左为 2,举手为 3) + /// 识别左手动作 /// + public int RecognizeLeftHandGesture(Point wrist, Point elbow) + { + int result = DetectHorizontalWave(wrist, elbow, _lastLeftWrist, true); + _lastLeftWrist = wrist; // 更新记录 + return result; + } + private bool _firstHandTriggered = false; + /// + /// 识别右手动作 + /// + /// + /// + /// public int RecognizeRightHandGesture(Point wrist, Point elbow) { - // 判断手腕是否在肘部上方,并且达到高度阈值 - //if (wrist.Y + 40 < elbow.Y && wrist.Y < minRaiseHeight) - if (wrist.Y + 40 < elbow.Y) + // --- 先判断水平挥手 --- + int waveResult = DetectHorizontalWave(wrist, elbow, _lastRightWrist, false); + _lastRightWrist = wrist; // 更新记录 + if (waveResult != (int)WavingAction.None) + return waveResult; + + // --- 举手逻辑 --- + double verticalRise = elbow.Y - wrist.Y; // 手腕在肘上方 → 正值 + if (verticalRise > 100) // 举手阈值 { + // 初始化计时 if (_raiseStartTime == null) - { _raiseStartTime = DateTime.Now; - return (int)WavingAction.FirstHand; + + if (_wristStartTime == null) + _wristStartTime = DateTime.Now; + + var wristDuration = DateTime.Now - _wristStartTime.Value; + + // 保持 >1 秒才触发一次 FirstHand + if (!_firstHandTriggered && wristDuration.TotalSeconds >= 1) + { + _firstHandTriggered = true; + return (int)WavingAction.FirstHand; // 举手开始,只触发一次 } + // 判断是否完成3秒举手 var duration = DateTime.Now - _raiseStartTime.Value; - if (duration.TotalSeconds >= 3) + if (duration.TotalSeconds >= 4) { _raiseStartTime = null; + _wristStartTime = null; + _firstHandTriggered = false; // 重置状态 return (int)WavingAction.RaiseHand; // 举手完成 } else @@ -135,33 +169,20 @@ namespace Wpf_AiSportsMicrospace.Common } else { + // 手放下,重置计时和状态 _raiseStartTime = null; + _wristStartTime = null; + _firstHandTriggered = false; } - // 挥手逻辑 - 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; + return (int)WavingAction.None; } + /// /// 冷却防抖(避免重复触发) /// - private bool CheckCooldown(int cooldownMs = 500) + private bool CheckCooldown(int cooldownMs = 1000) { if ((DateTime.Now - _lastActionTime).TotalMilliseconds < cooldownMs) return false; diff --git a/Wpf_AiSportsMicrospace/Enum/WavingAction.cs b/Wpf_AiSportsMicrospace/Enum/WavingAction.cs index 323e2fd..5a6058b 100644 --- a/Wpf_AiSportsMicrospace/Enum/WavingAction.cs +++ b/Wpf_AiSportsMicrospace/Enum/WavingAction.cs @@ -8,12 +8,12 @@ namespace Wpf_AiSportsMicrospace.Enum { public enum WavingAction { - None = 0, // 没动作 - LeftWave = 1, // 左挥手 - RightWave = 2, // 右挥手 - RaiseHand = 3, // 举手完成 - Raising = 4, // 举手中,未完成 - FirstHand = 5,//首次举手 + None = 0, + LeftWave = 1, + RightWave = 2, + FirstHand = 3, // 举手开始 + Raising = 4, // 举手中 + RaiseHand = 5 // 举手完成 } } diff --git a/Wpf_AiSportsMicrospace/Home.xaml b/Wpf_AiSportsMicrospace/Home.xaml index a152e2e..630bf8c 100644 --- a/Wpf_AiSportsMicrospace/Home.xaml +++ b/Wpf_AiSportsMicrospace/Home.xaml @@ -2,8 +2,8 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.MyUserControl" - Title="Home" Height="600" Width="800" Loaded="Window_Loaded"> - + Title="Home" Height="1080" Width="1920" Loaded="Window_Loaded"> + diff --git a/Wpf_AiSportsMicrospace/Home.xaml.cs b/Wpf_AiSportsMicrospace/Home.xaml.cs index dd8c1c6..7d32cff 100644 --- a/Wpf_AiSportsMicrospace/Home.xaml.cs +++ b/Wpf_AiSportsMicrospace/Home.xaml.cs @@ -80,6 +80,7 @@ namespace Wpf_AiSportsMicrospace _webcamClient.StartExtract(); StartFrameProcessing(); + coverFlow.ProgressCompleted += CoverFlow_ProgressCompleted; } private void CoverFlow_ProgressCompleted(CoverFlowItem item) @@ -90,6 +91,7 @@ namespace Wpf_AiSportsMicrospace _cts.Cancel(); // 停止后台处理线程 _webcamClient?.StopExtract(); // 停止摄像头抽帧 _webcamClient = null; + } catch (Exception ex) { @@ -97,7 +99,7 @@ namespace Wpf_AiSportsMicrospace } // 解绑事件,防止重复触发 - coverFlow.ProgressCompleted -= CoverFlow_ProgressCompleted; + //coverFlow.ProgressCompleted -= CoverFlow_ProgressCompleted; // 根据图片跳转新窗口 string uri = item.ImageUri.ToString(); @@ -132,6 +134,15 @@ namespace Wpf_AiSportsMicrospace } else { + //_webcamClient.OnExtractFrame += frame => + //{ + // if (frame != null) + // _frameQueue.Enqueue(frame); + //}; + //_webcamClient.StartExtract(); + + + _webcamClient.StartExtract(); Thread.Sleep(5); } } @@ -163,32 +174,33 @@ namespace Wpf_AiSportsMicrospace //检测挥手动作 var wavingaction = _sportOperate.VerifyWavingAction(human); - if (wavingaction == (int)WavingAction.Raising) + // 把低 8 位作为动作类型,高 8 位作为进度 + int actionType = wavingaction & 0xFF; + int progress = (wavingaction >> 8) & 0xFF; + + switch (actionType) { - return; - } - else - { - switch (wavingaction) - { - case (int)WavingAction.LeftWave: // 1 - Dispatcher.BeginInvoke(() => coverFlow.SlideLeft()); - break; - case (int)WavingAction.RightWave: // 2 - Dispatcher.BeginInvoke(() => coverFlow.SlideRight()); - break; - case (int)WavingAction.RaiseHand: // 3 举手完成 - coverFlow.ProgressCompleted -= CoverFlow_ProgressCompleted; - coverFlow.ProgressCompleted += CoverFlow_ProgressCompleted; - break; - case (int)WavingAction.Raising: // 4 举手中 - break; - case 5: // 如果还有其他动作 - Dispatcher.BeginInvoke(() => coverFlow.StartSelectedProgress()); - break; - default: - break; - } + case (int)WavingAction.LeftWave: // 左手挥动 + Dispatcher.BeginInvoke(() => coverFlow.SlideRight()); + break; + + case (int)WavingAction.RightWave: // 右手挥动 + Dispatcher.BeginInvoke(() => coverFlow.SlideLeft()); + break; + + case (int)WavingAction.FirstHand: // 举手开始 + Dispatcher.BeginInvoke(() => coverFlow.StartSelectedProgress()); + break; + + case (int)WavingAction.Raising: // 举手中,实时更新进度 + break; + + case (int)WavingAction.RaiseHand: // 举手完成 + _cts.Cancel(); + break; + default: // 没有动作 → 取消进度 + Dispatcher.BeginInvoke(() => coverFlow.CancelSelectedProgress()); + break; } } catch (Exception ex) diff --git a/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl1.xaml b/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl1.xaml index 3715957..abe1ca0 100644 --- a/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl1.xaml +++ b/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl1.xaml @@ -10,7 +10,7 @@ - + @@ -30,12 +30,12 @@ - - + + - + diff --git a/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl1.xaml.cs b/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl1.xaml.cs index 2f791fa..01fc9a0 100644 --- a/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl1.xaml.cs +++ b/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl1.xaml.cs @@ -193,9 +193,9 @@ namespace Wpf_AiSportsMicrospace.MyUserControl private void UpdateLayoutWithAnimation(bool instant = false) { double centerX = ActualWidth / 2; - double spacing = 180; - double sideScale = 0.8; - double centerScale = 1.2; + double spacing = 550; + double sideScale = 0.93; + double centerScale = 1.43; for (int i = 0; i < ItemsHost.Items.Count; i++) {