From d5733d08f9af8219fb4b347a5f656dce6bc05537 Mon Sep 17 00:00:00 2001
From: tanglong <842690096@qq.com>
Date: Thu, 5 Feb 2026 14:48:49 +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/Common/SportOperate.cs | 53 ++--
.../Dto/MusicJumpRopeContext.cs | 8 +-
Wpf_AiSportsMicrospace/Views/Home.xaml.cs | 4 +-
.../Views/JumpLong/StandingLeap.xaml.cs | 42 ++-
.../Views/JumpRope/GroupJumpRope.xaml.cs | 165 ++----------
.../Views/JumpRope/MusicJumpRope.xaml.cs | 247 ++++--------------
.../Views/Setting/LongSetting.xaml.cs | 52 +++-
7 files changed, 189 insertions(+), 382 deletions(-)
diff --git a/Wpf_AiSportsMicrospace/Common/SportOperate.cs b/Wpf_AiSportsMicrospace/Common/SportOperate.cs
index d3e8a4a..f48371c 100644
--- a/Wpf_AiSportsMicrospace/Common/SportOperate.cs
+++ b/Wpf_AiSportsMicrospace/Common/SportOperate.cs
@@ -1,6 +1,7 @@
using AiSportsMicrospaceDB.DBContext;
using Common;
using HandyControl.Controls;
+using Microsoft.EntityFrameworkCore.Storage.Json;
using Microsoft.Extensions.DependencyInjection;
using SportExpand;
using System;
@@ -74,17 +75,17 @@ namespace Wpf_AiSportsMicrospace.Common
///
/// 验证右手动作(右手举手优先,然后左右挥手)
///
- public int VerifyRightWavingAction(List humans)
+ public int VerifyRightWavingAction(List humans)
{
if (humans == null || humans.Count == 0)
return (int)WavingAction.None;
// 先找到控制点区域的人
Human target = null;
- double cx = AppSettings.ControlPoint.X ;
- double cy = AppSettings.ControlPoint.Y ;
- double halfW = AppSettings.AreaSize.X ;
- double halfH = AppSettings.AreaSize.Y ;
+ double cx = AppSettings.ControlPoint.X;
+ double cy = AppSettings.ControlPoint.Y;
+ double halfW = AppSettings.AreaSize.X;
+ double halfH = AppSettings.AreaSize.Y;
for (int i = 0; i < humans.Count; i++)
{
@@ -93,7 +94,7 @@ namespace Wpf_AiSportsMicrospace.Common
{
if (k.Name == "right_ankle")
{
- double x = k.X;
+ double x = k.X;
double y = k.Y;
if (x >= cx - halfW && x <= cx + halfW &&
y >= cy - halfH && y <= cy + halfH)
@@ -199,20 +200,12 @@ namespace Wpf_AiSportsMicrospace.Common
for (int i = 0; i < humans.Count; i++)
{
var h = humans[i];
- foreach (var k in h.Keypoints)
+
+ if (IsAnyFootInCircle(h, cx, cy, halfW, halfH))
{
- if (k.Name == "right_ankle")
- {
- double x = k.X;
- double y = k.Y;
- if (x >= cx - halfW && x <= cx + halfW &&
- y >= cy - halfH && y <= cy + halfH)
- {
- target = h;
- break;
- }
- }
+ target = h;
}
+
if (target != null) break;
}
@@ -222,7 +215,6 @@ namespace Wpf_AiSportsMicrospace.Common
// ---- 右手举手优先 ----
int rightHandAction = DetectLeftHandRaise(target);
return rightHandAction;
-
}
@@ -232,9 +224,28 @@ namespace Wpf_AiSportsMicrospace.Common
var ruleLeft = RaiseHand.RaiseLeftHand();
bool pass = calculator.Calculating(human, ruleLeft);
-
- return pass ? (int)WavingAction.Raising : (int)WavingAction.None;
+
+ return pass ? (int)WavingAction.Raising : (int)WavingAction.None;
}
+ public bool IsAnyFootInCircle(Human h, double cx, double cy, double halfW, double halfH)
+ {
+ foreach (var k in h.Keypoints)
+ {
+ if (k.Name != "right_ankle" && k.Name != "left_ankle")
+ continue;
+
+ double x = k.X;
+ double y = k.Y;
+
+ if (Math.Abs(x - cx) <= halfW &&
+ Math.Abs(y - cy) <= halfH)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
}
}
diff --git a/Wpf_AiSportsMicrospace/Dto/MusicJumpRopeContext.cs b/Wpf_AiSportsMicrospace/Dto/MusicJumpRopeContext.cs
index 13317b0..bc1a575 100644
--- a/Wpf_AiSportsMicrospace/Dto/MusicJumpRopeContext.cs
+++ b/Wpf_AiSportsMicrospace/Dto/MusicJumpRopeContext.cs
@@ -55,10 +55,10 @@ namespace Dto
public MusicJumpRopeContext()
{
CirclePositions = new List<(double XNorm, double YNorm)>
- {
- (0.50, 0.88),
- (0.78, 0.88),
- };
+ {
+ (0.50, 0.88),
+ (0.78, 0.88),
+ };
MusicBeatsDic = MusicBeats["1"].GroupBy(b => (int)Math.Ceiling(b) - 1).ToDictionary(g => g.Key, g => g.ToList());
diff --git a/Wpf_AiSportsMicrospace/Views/Home.xaml.cs b/Wpf_AiSportsMicrospace/Views/Home.xaml.cs
index c926cf0..7e03476 100644
--- a/Wpf_AiSportsMicrospace/Views/Home.xaml.cs
+++ b/Wpf_AiSportsMicrospace/Views/Home.xaml.cs
@@ -10,6 +10,7 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Threading;
+using Views.JumpLong;
using Views.JumpRope;
using Views.SquatFu;
using Wpf_AiSportsMicrospace.Common;
@@ -173,7 +174,8 @@ namespace Wpf_AiSportsMicrospace
}
else
{
- var newPage = new TrainingRecords();
+ //var newPage = new TrainingRecords();
+ var newPage = new StandingLeap();
mainWin?.SwitchPageWithMaskAnimation(newPage, true);
}
}
diff --git a/Wpf_AiSportsMicrospace/Views/JumpLong/StandingLeap.xaml.cs b/Wpf_AiSportsMicrospace/Views/JumpLong/StandingLeap.xaml.cs
index 02f2167..bf0f642 100644
--- a/Wpf_AiSportsMicrospace/Views/JumpLong/StandingLeap.xaml.cs
+++ b/Wpf_AiSportsMicrospace/Views/JumpLong/StandingLeap.xaml.cs
@@ -1,4 +1,5 @@
using AiSportsMicrospaceDB.DBContext;
+using AiSportsMicrospaceDB.Entities;
using Common;
using Dto;
using Enum;
@@ -49,6 +50,8 @@ namespace Views.JumpLong
private MediaPlayer _mediaPlayer = new MediaPlayer();
private readonly SportDetectionQueue _detectQueue;
+ private JumpLongPoints _Points;
+
private int _sportType = 0; // 0:未开始 1:运动中 2:运动结束展示排行榜
#endregion
@@ -66,7 +69,6 @@ namespace Views.JumpLong
_sport = SportBase.Create("standing-long-jump");
_sport.OnTicked += this.OnSportTick;
- _mainWin.HumanFrameUpdated += this.OnFrameUpdated;
_measureApparatus = new ApparatusLongJumpDelineation();
_measureApparatus.MeasureLength = 300;
var _isCalibrated = this.ReactangleCalibrating(1920, 1080);
@@ -79,6 +81,14 @@ namespace Views.JumpLong
{
// 播放音乐
PlayMusic("raisehand.mp3");
+
+ var app = (App)Application.Current;
+ using var scope = App.AppHost.Services.CreateScope();
+ var db = scope.ServiceProvider.GetRequiredService();
+
+ _Points = db.JumpLongPoints.FirstOrDefault(x => x.Code == AppSettings.Code);
+
+ _mainWin.HumanFrameUpdated += OnFrameUpdated;
}
@@ -279,21 +289,6 @@ namespace Views.JumpLong
// 关闭跳远抽帧线程
}
- //关闭成绩展示 显示跳远页面
- private void closRope()
- {
- //关闭动画
- //var fadeInAnimation = new DoubleAnimation
- //{
- // From = 1,
- // To = 0,
- // Duration = TimeSpan.FromSeconds(1)
- //};
- // RankingGrid.BeginAnimation(UIElement.OpacityProperty, fadeInAnimation);
- RankingGrid.Opacity = 0;
- _sportType = 0;
- PlayMusic("raisehand.mp3");
- }
private bool ReactangleCalibrating(int frameWidth, int frameHeight)
{
@@ -429,23 +424,16 @@ namespace Views.JumpLong
if (rightAnkle == null)
continue;
- //double xNorm = rightAnkle.X / 1920;
- //double yNorm = rightAnkle.Y / 1080;
- var app = (App)Application.Current;
- using var scope = App.AppHost.Services.CreateScope();
- var db = scope.ServiceProvider.GetRequiredService();
- var points = db.JumpLongPoints.FirstOrDefault(x => x.Code == AppSettings.Code);
-
// 检测起跳区域的人
- var isinx = (rightAnkle.X < points.TopPoint3.X && rightAnkle.X > points.TopPoint2.X) || (rightAnkle.X < points.BottomPoint3.X && rightAnkle.X > points.BottomPoint2.X);
- if (points.TopPoint3.X < points.TopPoint2.X)
+ var isinx = (rightAnkle.X < _Points.TopPoint3.X && rightAnkle.X > _Points.TopPoint2.X) || (rightAnkle.X < _Points.BottomPoint3.X && rightAnkle.X > _Points.BottomPoint2.X);
+ if (_Points.TopPoint3.X < _Points.TopPoint2.X)
{
- isinx = (rightAnkle.X > points.TopPoint3.X && rightAnkle.X < points.TopPoint2.X) || (rightAnkle.X > points.BottomPoint3.X && rightAnkle.X < points.BottomPoint2.X);
+ isinx = (rightAnkle.X > _Points.TopPoint3.X && rightAnkle.X < _Points.TopPoint2.X) || (rightAnkle.X > _Points.BottomPoint3.X && rightAnkle.X < _Points.BottomPoint2.X);
}
- var isiny = (rightAnkle.Y > points.TopPoint3.Y && rightAnkle.X < points.BottomPoint3.Y) || (rightAnkle.Y < points.TopPoint2.Y && rightAnkle.X > points.BottomPoint2.Y);
+ var isiny = (rightAnkle.Y > _Points.TopPoint3.Y && rightAnkle.X < _Points.BottomPoint3.Y) || (rightAnkle.Y < _Points.TopPoint2.Y && rightAnkle.X > _Points.BottomPoint2.Y);
if (!isinx || !isiny) continue;
diff --git a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs
index cf9c04f..0509e06 100644
--- a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs
+++ b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs
@@ -84,8 +84,6 @@ namespace Wpf_AiSportsMicrospace.Views
using var scope = App.AppHost.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService();
var cfg = await db.GroupPoints.FirstOrDefaultAsync(x => x.Code == AppSettings.Code);
- //var pointlist = JsonSerializer.Deserialize>(cfg!.PointsJson);
-
List<(double XNorm, double YNorm)> pointlist = new List<(double XNorm, double YNorm)>();
var points = new[] { cfg.Point1, cfg.Point2, cfg.Point3,
@@ -101,6 +99,8 @@ namespace Wpf_AiSportsMicrospace.Views
}
_groupJumpRopeContext.CirclePositions = pointlist;
+ _mainWin.HumanFrameUpdated += OnHumanFrameUpdated;
+
DrawCirclesWithText();
// 播放音乐
@@ -350,90 +350,6 @@ namespace Wpf_AiSportsMicrospace.Views
_mainWin.WebcamClient.StartExtract();
}
- private DateTime? _raiseStartTime;
- 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()
- {
- _raiseStartTime = null;
- _countdownStartTime = null;
- _firstHandTriggered = false;
- _lastCountdownSecond = 3;
- }
private void DrawCirclesWithText()
{
userBox.Children.Clear();
@@ -445,8 +361,8 @@ namespace Wpf_AiSportsMicrospace.Views
for (int i = 0; i < _groupJumpRopeContext.CirclePositions.Count; i++)
{
var pos = _groupJumpRopeContext.CirclePositions[i];
- double x = pos.XNorm ;
- double y = pos.YNorm ;
+ double x = pos.XNorm;
+ double y = pos.YNorm;
// 绘制发光圆
var userItem = AddUserItem(x, y, i);
@@ -473,54 +389,46 @@ namespace Wpf_AiSportsMicrospace.Views
}
private void UpdateCircleCounts(List humans)
{
- double radiusNormX = 150;
- double radiusNormY = 150;
+ double halfW = AppSettings.AreaSize.X;
+ double halfH = AppSettings.AreaSize.Y;
- for (int i = 0; i < _groupJumpRopeContext.CirclePositions.Count; i++)
+ int circleCount = _groupJumpRopeContext.CirclePositions.Count;
+
+ for (int i = 0; i < circleCount; i++)
{
- var circleX = _groupJumpRopeContext.CirclePositions[i].XNorm;
- var circleY = _groupJumpRopeContext.CirclePositions[i].YNorm;
+ var circle = _groupJumpRopeContext.CirclePositions[i];
+ double cx = circle.XNorm;
+ double cy = circle.YNorm;
- Human humanInCircle = null;
+ Human targetHuman = null;
- // 找圈内的人
- foreach (var hu in humans)
+ // 1️⃣ 找圈内的人(单脚命中即可)
+ foreach (var h in humans)
{
- var rightFoot = hu.Keypoints.FirstOrDefault(k => k.Name == "right_ankle");
- var leftFoot = hu.Keypoints.FirstOrDefault(k => k.Name == "left_ankle");
- if (rightFoot == null || leftFoot == null)
- continue;
-
- double xRightNorm = rightFoot.X ;
- double xLeftNorm = leftFoot.X ;
- double yRightNorm = rightFoot.Y ;
- double yLeftNorm = leftFoot.Y ;
-
- bool outOfCircle =
- xRightNorm < (circleX - radiusNormX) || xRightNorm > (circleX + radiusNormX) ||
- xLeftNorm < (circleX - radiusNormX) || xLeftNorm > (circleX + radiusNormX) ||
- yRightNorm < (circleY - radiusNormY) || yRightNorm > (circleY + radiusNormY) ||
- yLeftNorm < (circleY - radiusNormY) || yLeftNorm > (circleY + radiusNormY);
-
- if (!outOfCircle)
+ if (sportOperate.IsAnyFootInCircle(h, cx, cy, halfW, halfH))
{
- humanInCircle = hu;
- break; // 每圈只处理一个人
+ targetHuman = h;
+ break; // 每个圈只认一个人
}
}
- // 根据是否有人和跳绳数字判断状态
- bool hasHuman = humanInCircle != null;
+ bool hasHuman = targetHuman != null;
+
+ // 2️⃣ 更新视觉状态
lock (_updateLock)
{
- _groupJumpRopeContext.UserList[i].ImageState = GetJumpState(i, hasHuman);
+ _groupJumpRopeContext.UserList[i].ImageState =
+ GetJumpState(i, hasHuman);
}
- // 推送计数
+ // 3️⃣ 推送跳绳计数
if (hasHuman)
- _groupJumpRopeContext.Sports[i].Pushing(humanInCircle);
+ {
+ _groupJumpRopeContext.Sports[i].Pushing(targetHuman);
+ }
}
}
+
private string GetJumpState(int circleIndex, bool humanInCircle)
{
if (!humanInCircle)
@@ -567,7 +475,7 @@ namespace Wpf_AiSportsMicrospace.Views
userItem.HorizontalAlignment = HorizontalAlignment.Left;
userItem.ImageState = "1";
//userItem.Margin = new Thickness(centerX - (index == 0 ? 80 : index == 6 ? 190 : 135), centerY - 540, 0, 0);
- userItem.Margin = new Thickness(centerX - 25 - 100, centerY - 490 , 0, 0);
+ userItem.Margin = new Thickness(centerX - 25 - 100, centerY - 490, 0, 0);
userBox.Children.Add(userItem);
_groupJumpRopeContext.UserList.Add(userItem);
_groupJumpRopeContext.UserNumberList.Add("0");
@@ -645,21 +553,6 @@ namespace Wpf_AiSportsMicrospace.Views
//rankingGrid.BeginAnimation(UIElement.OpacityProperty, fadeIn);
}
- /*
- * 控制元素隐藏(渐隐动画
- * time: 动画持续时间(毫秒)
- * name: 元素名称
- */
- public void HideElement(string name, int time)
- {
- var Element = FindName(name) as Grid;
- if (Element == null) return;
-
- var fadeOut = new DoubleAnimation(1, 0, TimeSpan.FromMilliseconds(time));
- fadeOut.Completed += (s, e) => Element.Visibility = Visibility.Collapsed;
- Element.BeginAnimation(UIElement.OpacityProperty, fadeOut);
- }
-
/*
* 控制元素限时(渐隐动画
* time: 动画持续时间(毫秒)
diff --git a/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml.cs b/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml.cs
index 90b1eff..1e251ee 100644
--- a/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml.cs
+++ b/Wpf_AiSportsMicrospace/Views/JumpRope/MusicJumpRope.xaml.cs
@@ -23,7 +23,7 @@ using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
-using System.Windows.Threading;
+using System.Windows.Threading;
using Wpf_AiSportsMicrospace.Common;
using Wpf_AiSportsMicrospace.Dto;
using Wpf_AiSportsMicrospace.Enum;
@@ -75,26 +75,16 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope
popSilder1.MusicBeats = _musicJumpRopeContext.MusicBeats["1"];
popSilder2.MusicBeats = _musicJumpRopeContext.MusicBeats["1"];
- //Random rnd = new Random();
-
- //// 模拟 20 次随机更新
- //for (int i = 0; i < 200; i++)
- //{
- // // 随机左右进度变化,保证总和=1
- // double left = rnd.NextDouble(); // 0~1
- // PkBar.LeftProgress = left; // RightProgress 自动 1-left
-
- // await Task.Delay(1000); // 200ms 间隔,不卡UI线程
- //}
-
var app = (App)Application.Current;
using var scope = App.AppHost.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService();
var cfg = await db.GroupPoints.FirstOrDefaultAsync(x => x.Code == AppSettings.Code);
//var pointlist = JsonSerializer.Deserialize>(cfg!.PointsJson);
- List<(double XNorm, double YNorm)> pointlist = [(cfg.Point3.X, cfg.Point3.Y), (cfg.Point5.X, cfg.Point5.Y)];
+ List<(double XNorm, double YNorm)> pointlist = [(cfg.ControlPoint.X, cfg.ControlPoint.Y), (cfg.Point3.X, cfg.Point3.Y)];
_musicJumpRopeContext.UpdateCirclePositions(pointlist);
+
+ _mainWin.HumanFrameUpdated += OnHumanFrameUpdated;
}
private void UserControl_Unloaded(object sender, RoutedEventArgs e)
@@ -187,50 +177,49 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope
{
if (humans == null || humans.Count == 0) return;
-
- switch (_currentGameState)
- {
- case GameState.NotStarted:
- if (!_isCountdownStarted)
+ switch (_currentGameState)
+ {
+ case GameState.NotStarted:
+ if (!_isCountdownStarted)
+ {
+ int leftWaving = sportOperate.VerifyLeftWavingAction(humans);
+ if (leftWaving == 5)
{
- int leftWaving = sportOperate.VerifyLeftWavingAction(humans);
- if (leftWaving == 5)
- {
- _mainWin.HumanFrameUpdated -= OnHumanFrameUpdated;
- _mainWin.WebcamClient.StopExtract();
+ _mainWin.HumanFrameUpdated -= OnHumanFrameUpdated;
+ _mainWin.WebcamClient.StopExtract();
- // 举左手逻辑,例如结束动画或退出
- var newPage = new Home();
- _mainWin?.SwitchPageWithMaskAnimation(newPage, true);
- return; // 提前退出
- }
+ // 举左手逻辑,例如结束动画或退出
+ var newPage = new Home();
+ _mainWin?.SwitchPageWithMaskAnimation(newPage, true);
+ return; // 提前退出
}
+ }
- int rightWaving = sportOperate.VerifyRightWavingAction(humans);
- if (rightWaving >= 3 && RankingGrid.Visibility != Visibility.Visible)
+ int rightWaving = sportOperate.VerifyRightWavingAction(humans);
+ if (rightWaving >= 3 && RankingGrid.Visibility != Visibility.Visible)
+ {
+ switch (rightWaving)
{
- 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;
- }
+ 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;
+ }
+ break;
+
+ case GameState.Running:
+ UpdateCircleCounts(humans);
+ break;
+ }
- case GameState.Running:
- UpdateCircleCounts(humans);
- break;
- }
-
}
catch (Exception ex)
{
@@ -428,88 +417,6 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope
Element.BeginAnimation(UIElement.OpacityProperty, fadeIn);
}
- private DateTime? _raiseStartTime;
- 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()
- {
- _raiseStartTime = null;
- _countdownStartTime = null;
- _firstHandTriggered = false;
- _lastCountdownSecond = 3;
- }
private void DrawCirclesWithText()
{
@@ -579,7 +486,6 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope
//UpdateScore(right, score2);
score1.Text = (right * 10).ToString();
}
-
}
};
@@ -588,33 +494,6 @@ 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()
{
@@ -626,54 +505,40 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope
private void UpdateCircleCounts(List humans)
{
- double radiusNormX = 0.07;
- double radiusNormY = 0.14;
+ double halfW = AppSettings.AreaSize.X;
+ double halfH = AppSettings.AreaSize.Y;
for (int i = 0; i < _musicJumpRopeContext.CirclePositions.Count; i++)
{
- var circleX = _musicJumpRopeContext.CirclePositions[i].XNorm;
- var circleY = _musicJumpRopeContext.CirclePositions[i].YNorm;
+ var circle = _musicJumpRopeContext.CirclePositions[i];
+ double cx = circle.XNorm;
+ double cy = circle.YNorm;
Human humanInCircle = null;
- // 找圈内的人
- foreach (var hu in humans)
+ // 1️⃣ 找圈内的人(单脚命中即可)
+ foreach (var h in humans)
{
- var rightFoot = hu.Keypoints.FirstOrDefault(k => k.Name == "right_ankle");
- var leftFoot = hu.Keypoints.FirstOrDefault(k => k.Name == "left_ankle");
- if (rightFoot == null || leftFoot == null)
- continue;
-
- double xRightNorm = rightFoot.X / userBox.ActualWidth;
- double xLeftNorm = leftFoot.X / userBox.ActualWidth;
- double yRightNorm = rightFoot.Y / userBox.ActualHeight;
- double yLeftNorm = leftFoot.Y / userBox.ActualHeight;
-
- bool outOfCircle =
- xRightNorm < (circleX - radiusNormX) || xRightNorm > (circleX + radiusNormX) ||
- xLeftNorm < (circleX - radiusNormX) || xLeftNorm > (circleX + radiusNormX) ||
- yRightNorm < (circleY - radiusNormY) || yRightNorm > (circleY + radiusNormY) ||
- yLeftNorm < (circleY - radiusNormY) || yLeftNorm > (circleY + radiusNormY);
-
- if (!outOfCircle)
+ if (sportOperate.IsAnyFootInCircle(h, cx, cy, halfW, halfH))
{
- humanInCircle = hu;
- break; // 每圈只处理一个人
+ humanInCircle = h;
+ break; // 每个圈只认一个人
}
}
+
// 根据是否有人和跳绳数字判断状态
bool hasHuman = humanInCircle != null;
lock (_updateLock)
{
_musicJumpRopeContext.UserList[i].ImageState = GetJumpState(i, hasHuman);
- //var state = GetJumpState(i, hasHuman);
- //ChangeImgState(i, state);
}
- // 推送计数
- //if (hasHuman)
- _musicJumpRopeContext.Sports[i].Pushing(humanInCircle);
+ // 3️⃣ 推送计数
+ if (hasHuman)
+ {
+ _musicJumpRopeContext.Sports[i].Pushing(humanInCircle);
+ }
}
}
private string GetJumpState(int circleIndex, bool humanInCircle)
diff --git a/Wpf_AiSportsMicrospace/Views/Setting/LongSetting.xaml.cs b/Wpf_AiSportsMicrospace/Views/Setting/LongSetting.xaml.cs
index 1965960..b8391d3 100644
--- a/Wpf_AiSportsMicrospace/Views/Setting/LongSetting.xaml.cs
+++ b/Wpf_AiSportsMicrospace/Views/Setting/LongSetting.xaml.cs
@@ -63,7 +63,7 @@ namespace Wpf_AiSportsMicrospace.Views
using var scope = App.AppHost.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService();
var BaseData = await db.BasicConfig.FirstOrDefaultAsync(x => x.Code == AppSettings.Code);
- if (BaseData==null)
+ if (BaseData == null)
{
this.ShowError("相机主机地址/IP不能为空。");
return;
@@ -200,14 +200,19 @@ namespace Wpf_AiSportsMicrospace.Views
{
try
{
+ string code = Utils.GetMacAddress();
var app = (App)Application.Current;
using var scope = App.AppHost.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService();
- var pointsData = db.JumpLongPoints.FirstOrDefault(x => x.Code == AppSettings.Code);
+ var pointsData = db.JumpLongPoints.FirstOrDefault(x => x.Code == code);
if (pointsData == null)
{
pointsData = new JumpLongPoints();
+
+ pointsData.Code = code;
+
+
// 保存所有点的位置
pointsData.TopPoint1 = new AiSportsMicrospaceDB.Entities.Point
{
@@ -247,7 +252,50 @@ namespace Wpf_AiSportsMicrospace.Views
db.JumpLongPoints.Add(pointsData);
}
+ else
+ {
+ // 保存所有点的位置
+ pointsData.TopPoint1 = new AiSportsMicrospaceDB.Entities.Point
+ {
+ X = Canvas.GetLeft(TopPoint1) + 10,
+ Y = Canvas.GetTop(TopPoint1) + 10
+ };
+
+ pointsData.TopPoint2 = new AiSportsMicrospaceDB.Entities.Point
+ {
+ X = Canvas.GetLeft(TopPoint2) + 10,
+ Y = Canvas.GetTop(TopPoint2) + 10
+ };
+
+ pointsData.TopPoint3 = new AiSportsMicrospaceDB.Entities.Point
+ {
+ X = Canvas.GetLeft(TopPoint3) + 10,
+ Y = Canvas.GetTop(TopPoint3) + 10
+ };
+
+ pointsData.BottomPoint1 = new AiSportsMicrospaceDB.Entities.Point
+ {
+ X = Canvas.GetLeft(BottomPoint1) + 10,
+ Y = Canvas.GetTop(BottomPoint1) + 10
+ };
+
+ pointsData.BottomPoint2 = new AiSportsMicrospaceDB.Entities.Point
+ {
+ X = Canvas.GetLeft(BottomPoint2) + 10,
+ Y = Canvas.GetTop(BottomPoint2) + 10
+ };
+
+ pointsData.BottomPoint3 = new AiSportsMicrospaceDB.Entities.Point
+ {
+ X = Canvas.GetLeft(BottomPoint3) + 10,
+ Y = Canvas.GetTop(BottomPoint3) + 10
+ };
+
+ db.JumpLongPoints.Update(pointsData);
+ }
+
db.SaveChanges();
+
UpdateStatus("点数据保存成功");
}
catch (Exception ex)