From 05f147c6ae13be7951550fe2f2545a335beff0c9 Mon Sep 17 00:00:00 2001 From: tanglong <842690096@qq.com> Date: Thu, 29 Jan 2026 17:18:22 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Wpf_AiSportsMicrospace/Views/Home.xaml.cs | 4 +- .../Views/JumpRope/GroupJumpRope.xaml.cs | 296 ++++++++---------- .../Views/JumpRope/MusicJumpRope.xaml.cs | 40 ++- 3 files changed, 166 insertions(+), 174 deletions(-) diff --git a/Wpf_AiSportsMicrospace/Views/Home.xaml.cs b/Wpf_AiSportsMicrospace/Views/Home.xaml.cs index d95b495..b07410c 100644 --- a/Wpf_AiSportsMicrospace/Views/Home.xaml.cs +++ b/Wpf_AiSportsMicrospace/Views/Home.xaml.cs @@ -159,11 +159,11 @@ namespace Wpf_AiSportsMicrospace if (coverFlow.SelectedIndex == 0) { - //var newPage = new GroupJumpRope(); + var newPage = new GroupJumpRope(); //mainWin?.SwitchPageWithMaskAnimation(newPage, true); //var newPage = new BambooDragonfly(); - var newPage = new WhackAMole(); + //var newPage = new WhackAMole(); mainWin?.SwitchPageWithMaskAnimation(newPage, true); } else if (coverFlow.SelectedIndex == 1) diff --git a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs index 982fef3..51c5bdb 100644 --- a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs +++ b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs @@ -43,7 +43,6 @@ using Yztob.AiSports.Postures; using Yztob.AiSports.Postures.Sports; using Yztob.AiSports.Sensors.Abstractions; using Yztob.AiSports.Sensors.Things; -using static HumanUtils; using static System.Formats.Asn1.AsnWriter; namespace Wpf_AiSportsMicrospace.Views @@ -66,7 +65,6 @@ namespace Wpf_AiSportsMicrospace.Views private readonly object _updateLock = new object(); private readonly Dictionary _jumpStatus = new Dictionary(); private GroupJumpRopeContext _groupJumpRopeContext; - private List _circles; public GroupJumpRope() { @@ -138,8 +136,8 @@ namespace Wpf_AiSportsMicrospace.Views }; // 增加图片的大小,调整比例 - tipImage.Width = AppSettings.Resolution_X * 0.9; - tipImage.Height = AppSettings.Resolution_Y * 0.6; + tipImage.Width = 1920 * 0.9; // 宽度为 Canvas 宽度的 90% + tipImage.Height = 1080 * 0.6; // 高度为 Canvas 高度的 60% // 将图片添加到 Overlay Canvas userBox.Children.Add(tipImage); @@ -186,42 +184,69 @@ namespace Wpf_AiSportsMicrospace.Views } private bool _isCountdownStarted = false; // 新增标记 - public void OnHumanFrameUpdated(object sender, List humans) + private void OnHumanFrameUpdated(object sender, List humans) { - if (humans == null || humans.Count == 0) return; - try { - int count = humans.Count; - var fastHumans = new HumanUtils.HumanFast[count]; - var fastToOriginal = new Human[count]; + if (humans == null || humans.Count == 0) return; - for (int i = 0; i < count; i++) + var human = humans.FirstOrDefault(h => { - fastHumans[i] = HumanUtils.ConvertToHumanFast(humans[i]); - fastToOriginal[i] = humans[i]; - } + var rightAnkle = h.Keypoints.FirstOrDefault(k => k.Name == "right_ankle"); + if (rightAnkle == null) + return false; - // 控制点检测 - var controlPoint = new Point( - (int)AppSettings.ControlPoint.X, - (int)AppSettings.ControlPoint.Y - ); - var areaSize = new Size( - (int)AppSettings.AreaSize.X, - (int)AppSettings.AreaSize.Y - ); + double xNorm = rightAnkle.X / 1920.0; + double yNorm = rightAnkle.Y / 1080.0; - var humanInControl = HumanUtils.FindHumanInControlPoint(fastHumans, controlPoint, areaSize); - if (humanInControl.HasValue) + return xNorm >= 0.44 && xNorm <= 0.57 && yNorm >= 0.81; + }); + + if (human != null) { - int index = Array.IndexOf(fastHumans, humanInControl.Value); - var originalHuman = fastToOriginal[index]; - HandleNotStarted(humanInControl.Value, originalHuman); - } + switch (_currentGameState) + { + case GameState.NotStarted: + if (!_isCountdownStarted) + { + int leftWaving = DetectLeftHandRaise(human); + if (leftWaving == 5) + { + _mainWin.HumanFrameUpdated -= OnHumanFrameUpdated; + _mainWin.WebcamClient.StopExtract(); - if (_currentGameState == GameState.Running) - UpdateCircleCounts(fastHumans, fastToOriginal); + // 举左手逻辑,例如结束动画或退出 + var newPage = new Home(); + _mainWin?.SwitchPageWithMaskAnimation(newPage, true); + return; // 提前退出 + } + } + + int rightWaving = DetectRightHandRaise(human); + if (rightWaving >= 3 && RankingGrid.Visibility != Visibility.Visible) + { + switch (rightWaving) + { + case (int)WavingAction.FirstHand: + StartCountdown(3); + _isCountdownStarted = true; + break; + case (int)WavingAction.Raising: + UpdateCountdown(); + break; + case (int)WavingAction.RaiseHand: + FinishCountdown(); + _currentGameState = GameState.Running; + break; + } + } + break; + + case GameState.Running: + UpdateCircleCounts(humans); + break; + } + } } catch (Exception ex) { @@ -229,139 +254,6 @@ namespace Wpf_AiSportsMicrospace.Views } } - private void HandleNotStarted(HumanUtils.HumanFast humanFast, Human human) - { - int leftWaving = DetectLeftHandRaise(humanFast); - if (leftWaving == (int)WavingAction.RaiseHand && !_isCountdownStarted) - { - _mainWin.HumanFrameUpdated -= OnHumanFrameUpdated; - _mainWin.WebcamClient.StopExtract(); - _mainWin.SwitchPageWithMaskAnimation(new Home(), true); - return; - } - - int rightWaving = DetectRightHandRaise(humanFast); - if (rightWaving < 3 || RankingGrid.Visibility == System.Windows.Visibility.Visible) - return; - - switch ((WavingAction)rightWaving) - { - case WavingAction.FirstHand: - StartCountdown(3); - _isCountdownStarted = true; - break; - case WavingAction.Raising: - UpdateCountdown(); - break; - case WavingAction.RaiseHand: - FinishCountdown(); - _currentGameState = GameState.Running; - break; - } - } - - private void UpdateCircleCounts(HumanUtils.HumanFast[] fastHumans, Human[] originalHumans) - { - for (int i = 0; i < _circles.Count; i++) - { - var circle = _circles[i]; - HumanUtils.HumanFast? hitHumanFast = null; - int hitIndex = -1; - - for (int j = 0; j < fastHumans.Length; j++) - { - var h = fastHumans[j]; - var ra = h.Get(HumanUtils.KeypointType.RightAnkle); - var la = h.Get(HumanUtils.KeypointType.LeftAnkle); - - double fx = (ra.X + la.X) * 0.5; - double fy = (ra.Y + la.Y) * 0.5; - - if (HumanUtils.IsInsideCircle(fx, fy, circle.CenterX, circle.CenterY, circle.RadiusX, circle.RadiusY)) - { - hitHumanFast = h; - hitIndex = j; - break; - } - } - - bool hasHuman = hitHumanFast.HasValue; - _groupJumpRopeContext.UserList[i].ImageState = GetJumpState(i, hasHuman); - - if (hasHuman && hitIndex >= 0) - { - _groupJumpRopeContext.Sports[i].Pushing(originalHumans[hitIndex]); - } - } - } - - // ---------- 左右手手势检测 ---------- - public int DetectLeftHandRaise(HumanUtils.HumanFast human) - { - var wrist = human.Get(HumanUtils.KeypointType.LeftWrist); - var elbow = human.Get(HumanUtils.KeypointType.LeftElbow); - var shoulder = human.Get(HumanUtils.KeypointType.LeftShoulder); - - bool pass = wrist.Y < elbow.Y && wrist.Y < shoulder.Y; - return pass ? (int)WavingAction.RaiseHand : (int)WavingAction.None; - } - - public int DetectRightHandRaise(HumanUtils.HumanFast human) - { - const double holdDuration = 1; - const int countdownSeconds = 3; - - var wrist = human.Get(HumanUtils.KeypointType.RightWrist); - var elbow = human.Get(HumanUtils.KeypointType.RightElbow); - var shoulder = human.Get(HumanUtils.KeypointType.RightShoulder); - - bool pass = wrist.Y < elbow.Y && wrist.Y < shoulder.Y; - - if (!_firstHandTriggered) - { - if (pass) - { - _raiseStartTime ??= DateTime.Now; - var holdElapsed = (DateTime.Now - _raiseStartTime.Value).TotalSeconds; - if (holdElapsed >= holdDuration) - { - _firstHandTriggered = true; - _countdownStartTime = DateTime.Now; - _lastCountdownSecond = countdownSeconds; - return (int)WavingAction.FirstHand; - } - } - else - { - _raiseStartTime = null; - } - return (int)WavingAction.None; - } - - if (_countdownStartTime.HasValue) - { - var elapsed = (DateTime.Now - _countdownStartTime.Value).TotalSeconds; - int currentSec = countdownSeconds - (int)Math.Floor(elapsed); - - if (currentSec > 0 && currentSec != _lastCountdownSecond) - { - _lastCountdownSecond = currentSec; - Console.WriteLine($"倒计时:{currentSec}"); - return (int)WavingAction.Raising; - } - - if (elapsed >= countdownSeconds) - { - ResetRaiseState(); - return (int)WavingAction.RaiseHand; - } - - return (int)WavingAction.Raising; - } - - return (int)WavingAction.None; - } - private double _currentCountdown = 3600; private DateTime _lastUpdateTime = DateTime.Now; private void StartCountdown(int start = 3) @@ -472,6 +364,78 @@ namespace Wpf_AiSportsMicrospace.Views private bool _firstHandTriggered; private int _lastCountdownSecond = 3; private DateTime? _countdownStartTime; + public int DetectRightHandRaise(Human human) + { + + var calculator = PostureCalculate.CreateCalculator(); + var rule = RaiseHand.RaiseRightHand(); + var pass = calculator.Calculating(human, rule); + + const double holdDuration = 1; // 持续时间(秒) + const int countdownSeconds = 3; // 倒计时长度 + + // ---------- 第一步:持续举手触发倒计时 ---------- + if (!_firstHandTriggered) + { + if (pass) + { + _raiseStartTime ??= DateTime.Now; + var holdElapsed = (DateTime.Now - _raiseStartTime.Value).TotalSeconds; + if (holdElapsed >= holdDuration) + { + // 举手达到指定时间,启动倒计时 + _firstHandTriggered = true; + _countdownStartTime = DateTime.Now; + _lastCountdownSecond = countdownSeconds; + return (int)WavingAction.FirstHand; + } + } + else + { + // 手放下,重置举手开始时间 + _raiseStartTime = DateTime.Now; + } + + // 没有任何中心区域内的人举手 + return (int)WavingAction.None; + } + + // ---------- 第二步:倒计时逻辑 ---------- + var countdownElapsed = (DateTime.Now - _countdownStartTime.Value).TotalSeconds; + int currentSecond = countdownSeconds - (int)Math.Floor(countdownElapsed); + + if (currentSecond > 0 && currentSecond != _lastCountdownSecond) + { + _lastCountdownSecond = currentSecond; + Console.WriteLine($"倒计时:{currentSecond}"); + return (int)WavingAction.Raising; // 倒计时中 + } + + if (countdownElapsed >= countdownSeconds) + { + ResetRaiseState(); + return (int)WavingAction.RaiseHand; // 举手完成 + } + + return (int)WavingAction.Raising; + } + + + public int DetectLeftHandRaise(Human human) + { + var calculator = PostureCalculate.CreateCalculator(); + var rule = RaiseHand.RaiseLeftHand(); + var pass = calculator.Calculating(human, rule); + + if (pass) + { + // 一旦检测到左手举起,立即返回 + return (int)WavingAction.RaiseHand; + } + + // 没有检测到举手 + return (int)WavingAction.None; + } private void ResetRaiseState() { @@ -522,8 +486,8 @@ namespace Wpf_AiSportsMicrospace.Views } private void UpdateCircleCounts(List humans) { - double radiusNormX = AppSettings.AreaSize.X; - double radiusNormY = AppSettings.AreaSize.Y; + double radiusNormX = 0.07; + double radiusNormY = 0.14; for (int i = 0; i < _groupJumpRopeContext.CirclePositions.Count; i++) { diff --git a/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml.cs b/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml.cs index 8e97426..fb71beb 100644 --- a/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml.cs +++ b/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml.cs @@ -134,8 +134,8 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope }; // 增加图片的大小,调整比例 - tipImage.Width = AppSettings.Resolution_X * 0.9; // 宽度为 Canvas 宽度的 90% - tipImage.Height = AppSettings.Resolution_Y * 0.6; // 高度为 Canvas 高度的 60% + tipImage.Width = 1920 * 0.9; // 宽度为 Canvas 宽度的 90% + tipImage.Height = 1080 * 0.6; // 高度为 Canvas 高度的 60% // 将图片添加到 Overlay Canvas userBox.Children.Add(tipImage); @@ -192,8 +192,8 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope if (rightAnkle == null) return false; - double xNorm = rightAnkle.X / AppSettings.Resolution_X; - double yNorm = rightAnkle.Y / AppSettings.Resolution_Y; + double xNorm = rightAnkle.X / 1920.0; + double yNorm = rightAnkle.Y / 1080.0; return xNorm >= 0.44 && xNorm <= 0.57 && yNorm >= 0.81; }); @@ -599,6 +599,34 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope } } + private void UpdateScore(double to, TextBlock score) + { + DoubleAnimation animation = new DoubleAnimation + { + From = double.Parse(score1.Text), + To = to, + Duration = TimeSpan.FromSeconds(0.2), + EasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseOut }, + FillBehavior = FillBehavior.HoldEnd + }; + score.BeginAnimation(TextBlock.TextProperty, animation); + } + + //private void ChangeImgState(int index , string state) + //{ + // if(index== 0) + // { + // left1.Visibility = state == "1" ? Visibility.Visible : Visibility.Hidden; + // left2.Visibility = state == "2" ? Visibility.Visible : Visibility.Hidden; + // left3.Visibility = state == "3" ? Visibility.Visible : Visibility.Hidden; + // }else if (index == 1) + // { + // right1.Visibility = state == "1" ? Visibility.Visible : Visibility.Hidden; + // right2.Visibility = state == "1" ? Visibility.Visible : Visibility.Hidden; + // right3.Visibility = state == "1" ? Visibility.Visible : Visibility.Hidden; + // } + //} + public void ShowMusicAnimation() { ImageBehavior.SetRepeatBehavior(leftm, RepeatBehavior.Forever); @@ -609,8 +637,8 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope private void UpdateCircleCounts(List humans) { - double radiusNormX = AppSettings.Resolution_X; - double radiusNormY = AppSettings.Resolution_Y; + double radiusNormX = 0.07; + double radiusNormY = 0.14; for (int i = 0; i < _musicJumpRopeContext.CirclePositions.Count; i++) {