From df8b9fc9cd4086bf3fabeb26df7547190106589c Mon Sep 17 00:00:00 2001
From: tanglong <842690096@qq.com>
Date: Fri, 13 Mar 2026 13:50:21 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9B=B4=E6=96=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Wpf_AiSportsMicrospace/Common/SportOperate.cs | 12 +-
Wpf_AiSportsMicrospace/Common/Utils.cs | 33 +++-
.../SportExpand/Optimizes.cs | 41 ++++
Wpf_AiSportsMicrospace/Views/Home.xaml.cs | 35 +---
.../Views/JumpRope/GroupJumpRope.xaml.cs | 180 ++++++++++--------
.../Views/SquatFu/WhackAMole.xaml.cs | 35 ++--
6 files changed, 199 insertions(+), 137 deletions(-)
create mode 100644 Wpf_AiSportsMicrospace/SportExpand/Optimizes.cs
diff --git a/Wpf_AiSportsMicrospace/Common/SportOperate.cs b/Wpf_AiSportsMicrospace/Common/SportOperate.cs
index 01ebc37..49c7cb9 100644
--- a/Wpf_AiSportsMicrospace/Common/SportOperate.cs
+++ b/Wpf_AiSportsMicrospace/Common/SportOperate.cs
@@ -34,7 +34,6 @@ namespace Wpf_AiSportsMicrospace.Common
private const int WaveThreshold = 4;
WebcamClient _webcamClient;
- private DateTime? _raiseStartTime = null;
private DateTime? _wristStartTime = null;
private bool _firstHandTriggered = false;
@@ -75,7 +74,8 @@ namespace Wpf_AiSportsMicrospace.Common
///
/// 验证右手动作(右手举手优先,然后左右挥手)
///
- public int VerifyRightWavingAction(List humans)
+ public int
+ VerifyRightWavingAction(List humans)
{
if (humans == null || humans.Count == 0)
return (int)WavingAction.None;
@@ -148,7 +148,6 @@ namespace Wpf_AiSportsMicrospace.Common
if (!pass)
{
- _raiseStartTime = null;
_wristStartTime = null;
_firstHandTriggered = false;
return (int)WavingAction.None;
@@ -156,23 +155,20 @@ namespace Wpf_AiSportsMicrospace.Common
var now = DateTime.Now;
- _raiseStartTime ??= now;
_wristStartTime ??= now;
double wristElapsed = (now - _wristStartTime.Value).TotalSeconds;
- double raiseElapsed = (now - _raiseStartTime.Value).TotalSeconds;
// 第一步:触发倒计时 / 举手开始
- if (!_firstHandTriggered && wristElapsed >= 1)
+ if (!_firstHandTriggered && wristElapsed >= 0)
{
_firstHandTriggered = true;
return (int)WavingAction.FirstHand;
}
// 第二步:举手完成
- if (raiseElapsed >= 1)
+ if (wristElapsed >= 3)
{
- _raiseStartTime = null;
_wristStartTime = null;
_firstHandTriggered = false;
return (int)WavingAction.RaiseHand;
diff --git a/Wpf_AiSportsMicrospace/Common/Utils.cs b/Wpf_AiSportsMicrospace/Common/Utils.cs
index cd614d2..014089b 100644
--- a/Wpf_AiSportsMicrospace/Common/Utils.cs
+++ b/Wpf_AiSportsMicrospace/Common/Utils.cs
@@ -1,4 +1,5 @@
-using Common;
+using AiSportsMicrospaceDB.Entities;
+using Common;
using Dto;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Jpeg;
@@ -87,7 +88,7 @@ namespace Wpf_AiSportsMicrospace.Common
Application.Current.Dispatcher.Invoke(() =>
{
if (_bgPlayer != null)
-
+
currentTime = _bgPlayer.Position.TotalSeconds;
});
return currentTime;
@@ -353,5 +354,33 @@ namespace Wpf_AiSportsMicrospace.Common
// 转成常用的 XX-XX-XX-XX-XX-XX 格式
return string.Join("-", macBytes.Select(b => b.ToString("X2")));
}
+
+ public static List<(double XNorm, double YNorm)> GetPointsList(int pointCount, GroupPoints cfg)
+ {
+ List<(double XNorm, double YNorm)> pointlist = new List<(double XNorm, double YNorm)>();
+
+ if (cfg == null || pointCount <= 0)
+ return pointlist;
+
+ // 所有可能的点
+ var allPoints = new[]
+ {
+ cfg.Point1, cfg.Point2, cfg.Point3,
+ cfg.Point4, cfg.Point5, cfg.Point6,
+ cfg.Point7, cfg.Point8, cfg.Point9, cfg.Point10
+ };
+
+ // 取前 pointCount 个点
+ foreach (var point in allPoints.Take(pointCount))
+ {
+ if (point != null)
+ {
+ pointlist.Add((point.X, point.Y));
+ }
+ }
+
+ return pointlist;
+ }
+
}
}
diff --git a/Wpf_AiSportsMicrospace/SportExpand/Optimizes.cs b/Wpf_AiSportsMicrospace/SportExpand/Optimizes.cs
new file mode 100644
index 0000000..e2786ee
--- /dev/null
+++ b/Wpf_AiSportsMicrospace/SportExpand/Optimizes.cs
@@ -0,0 +1,41 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Yztob.AiSports.Postures.Sports;
+using Yztob.AiSports.Postures.Things;
+
+namespace SportExpand
+{
+ public class Optimizes
+ { ///
+ /// 执行运动微调
+ ///
+ /// 要微调的运动
+ public static void Optimizeing(SportBase sport)
+ {
+ if (sport == null)
+ throw new ArgumentNullException(nameof(sport));
+
+ //获取运动的检测规则,如果使用的是规则检测时提供
+ Console.WriteLine(JsonConvert.SerializeObject(sport.Rules));
+ //获取运动的检测动作样本姿态,如果使用的是相似度时提供
+ Console.WriteLine(JsonConvert.SerializeObject(sport.Samples));
+
+ switch (sport.Key)
+ {
+ case "squat":
+ var loggicRule = sport.Rules["squat"] as CalcLogicAndRule;
+ //删除手部姿态检查规则
+ loggicRule.Rules.RemoveAt(2);
+ loggicRule.Rules.RemoveAt(1);
+ break;
+
+ case "rope-skipping":
+ var newSport = sport as SportRopeSkipping;
+ newSport.ShakeRate = 0.02f;
+ break;
+ }
+ }
+ }
+}
diff --git a/Wpf_AiSportsMicrospace/Views/Home.xaml.cs b/Wpf_AiSportsMicrospace/Views/Home.xaml.cs
index a226a24..d3700fa 100644
--- a/Wpf_AiSportsMicrospace/Views/Home.xaml.cs
+++ b/Wpf_AiSportsMicrospace/Views/Home.xaml.cs
@@ -57,6 +57,7 @@ namespace Wpf_AiSportsMicrospace
ImageUri = GetResourceUri("play_img/play_music.png"),
ProgressColor1 = "#e73d42",
ProgressColor2 = "#fd8212"
+
});
coverFlow.Images.Add(new CoverFlowItem
{
@@ -80,7 +81,7 @@ namespace Wpf_AiSportsMicrospace
if (_mainWin.WebcamClient == null)
{
- //HandyControl.Controls.MessageBox.Show("摄像头网络异常,请重新连接!");
+ HandyControl.Controls.MessageBox.Show("摄像头网络异常,请重新连接!");
return;
}
@@ -89,15 +90,14 @@ namespace Wpf_AiSportsMicrospace
}
private void Home_Unloaded(object sender, RoutedEventArgs e)
{
- //_mainWin.HumanFrameUpdated -= OnHumanFrameUpdated;
+ _mainWin.HumanFrameUpdated -= OnHumanFrameUpdated;
}
private bool IsGestureActive = true; // 标记手势识别是否有效
private void OnHumanFrameUpdated(object sender, List humans)
{
if (!IsGestureActive) return; // 手势识别已停止,直接返回
- var human = humans.FirstOrDefault();
- if (human == null) return;
+ if (humans == null || humans.Count == 0) return;
// 检测挥手动作
var wavingaction = _mainWin.SportOperate.VerifyRightWavingAction(humans);
@@ -120,9 +120,9 @@ namespace Wpf_AiSportsMicrospace
break;
case (int)WavingAction.RaiseHand: // 举手完成
- coverFlow.ProgressCompleted += CoverFlow_ProgressCompleted;
-
- // 设置标记,停止后续手势识别
+ // 设置标记,停止后续手势识别
+ //coverFlow.ProgressCompleted += CoverFlow_ProgressCompleted;
+ RouterGoNew();
IsGestureActive = false;
break;
@@ -132,20 +132,6 @@ namespace Wpf_AiSportsMicrospace
}
}
- private void CoverFlow_ProgressCompleted(CoverFlowItem item)
- {
- // 停止抽帧线程/释放资源
- try
- {
- //_mainWin.HumanFrameUpdated -= OnHumanFrameUpdated;
- //_mainWin.WebcamClient.StopExtract();
- RouterGoNew();
- }
- catch (Exception ex)
- {
- Debug.WriteLine($"停止抽帧异常: {ex.Message}");
- }
- }
//测试点击
private void GoNew(object sender, MouseButtonEventArgs e)
{
@@ -162,9 +148,6 @@ namespace Wpf_AiSportsMicrospace
if (coverFlow.SelectedIndex == 0)
{
var newPage = new GroupJumpRope();
- //mainWin?.SwitchPageWithMaskAnimation(newPage, true);
-
- //var newPage = new BambooDragonfly();
mainWin?.SwitchPageWithMaskAnimation(newPage, true);
}
else if (coverFlow.SelectedIndex == 1)
@@ -272,7 +255,7 @@ namespace Wpf_AiSportsMicrospace
var baseData = await db.BasicConfig.FirstOrDefaultAsync(x => x.Code == AppSettings.Code);
if (baseData == null)
{
- baseData = new BasicConfig { Code = AppSettings.Code, Host = host.Text, UserName = name.Text, Password = password.Text , HomeWidth = int.Parse(homeWidth.Text)};
+ baseData = new BasicConfig { Code = AppSettings.Code, Host = host.Text, UserName = name.Text, Password = password.Text, HomeWidth = int.Parse(homeWidth.Text) };
db.BasicConfig.Add(baseData);
db.SaveChanges();
}
@@ -326,7 +309,7 @@ namespace Wpf_AiSportsMicrospace
//var db = scope.ServiceProvider.GetRequiredService();
//var mainWindow = new MainWindow(db);
//mainWindow.Show();
-
+
var mainWin = Application.Current.MainWindow as Main;
mainWin.SwitchPageWithMaskAnimation(new MultiJumpRope(), true);
}
diff --git a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs
index cfd104d..5868a77 100644
--- a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs
+++ b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs
@@ -83,23 +83,25 @@ namespace Wpf_AiSportsMicrospace.Views
var app = (App)Application.Current;
using var scope = App.AppHost.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService();
+
+ // 获取配置
+ var pointCount = await db.BasicConfig
+ .Where(x => x.Code == AppSettings.Code)
+ .Select(x => x.HomeWidth)
+ .FirstOrDefaultAsync();
+
var cfg = await db.GroupPoints.FirstOrDefaultAsync(x => x.Code == AppSettings.Code);
- List<(double XNorm, double YNorm)> pointlist = new List<(double XNorm, double YNorm)>();
- var points = new[] { cfg.Point1, cfg.Point2, cfg.Point3,
- cfg.Point4, cfg.Point5, cfg.Point6,
- cfg.Point7, cfg.Point8, cfg.Point9, cfg.Point10 };
-
- foreach (var point in points)
+ if (pointCount == 0 || cfg == null)
{
- if (point != null)
- {
- pointlist.Add((point.X, point.Y));
- }
+ HandyControl.Controls.MessageBox.Error("配置加载失败!", "提示");
+ return;
}
- _groupJumpRopeContext.CirclePositions = pointlist;
+
+ _groupJumpRopeContext.CirclePositions = Utils.GetPointsList(pointCount, cfg);
_mainWin.HumanFrameUpdated += OnHumanFrameUpdated;
+ _mainWin.WebcamClient.StartExtract();
DrawCirclesWithText();
@@ -197,7 +199,7 @@ namespace Wpf_AiSportsMicrospace.Views
private void OnHumanFrameUpdated(object sender, List humans)
{
if (humans == null || humans.Count == 0) return;
- //var sportOperate = new SportOperate();
+
switch (_currentGameState)
{
case GameState.NotStarted: // 未开始
@@ -207,9 +209,6 @@ namespace Wpf_AiSportsMicrospace.Views
int leftWaving = sportOperate.VerifyLeftWavingAction(humans);
if (leftWaving == 5)
{
- _mainWin.HumanFrameUpdated -= OnHumanFrameUpdated;
- _mainWin.WebcamClient.StopExtract();
-
// 举左手逻辑,例如结束动画或退出
var newPage = new Home();
_mainWin?.SwitchPageWithMaskAnimation(newPage, true);
@@ -223,16 +222,10 @@ namespace Wpf_AiSportsMicrospace.Views
switch (rightWaving)
{
case (int)WavingAction.FirstHand:
+ _currentGameState = GameState.Running;
StartCountdown(3);
_isCountdownStarted = true; // 倒计时开始,停止左手检测
break;
- //case (int)WavingAction.Raising:
- // UpdateCountdown();
- // break;
- //case (int)WavingAction.RaiseHand:
- // FinishCountdown();
- // _currentGameState = GameState.Running; // 倒计时完成 → 游戏开始
- // break;
}
}
break;
@@ -243,74 +236,46 @@ namespace Wpf_AiSportsMicrospace.Views
}
}
-
- private double _currentCountdown = 3600;
- private DateTime _lastUpdateTime = DateTime.Now;
private async void StartCountdown(int start = 3)
{
_mainWin.ShowCountDownAnimation();
- //_currentCountdown = start;
-
- //countdownText.Text = _currentCountdown.ToString();
- //countdownGrid.Visibility = Visibility.Visible;
-
- //_lastUpdateTime = DateTime.Now;
Utils.PlayBackgroundMusic("countdown_3.mp3", false);
//开始人脸识别=============================================
- Action handler = null;
+ //Action handler = null;
- handler = async (frame) =>
- {
- var buffer = frame.GetImageBuffer(ImageFormat.Jpeg).ToArray();
- double[] xValues = [.. _groupJumpRopeContext.CirclePositions.Select(p => p.XNorm)];
+ //handler = async (frame) =>
+ //{
+ // var buffer = frame.GetImageBuffer(ImageFormat.Jpeg).ToArray();
+ // double[] xValues = [.. _groupJumpRopeContext.CirclePositions.Select(p => p.XNorm)];
- var studentList = Utils.FacialRecognition(buffer, xValues);
+ // var studentList = Utils.FacialRecognition(buffer, xValues);
- if (studentList != null && studentList.Count > 0)
- {
- // 解绑事件
- _mainWin.FacialRecognitionEvent -= handler;
+ // if (studentList != null && studentList.Count > 0)
+ // {
+ // // 解绑事件
+ // _mainWin.FacialRecognitionEvent -= handler;
- for (int i = 0; i < studentList.Count; i++)
- {
- var student = studentList[i];
- if (student != null)
- {
- _groupJumpRopeContext.UserList[i].DisplayText = student.StudentName;
- }
- }
+ // for (int i = 0; i < studentList.Count; i++)
+ // {
+ // var student = studentList[i];
+ // if (student != null)
+ // {
+ // _groupJumpRopeContext.UserList[i].DisplayText = student.StudentName;
+ // }
+ // }
- }
+ // }
- // 这里可以继续处理 studentList
- };
+ // // 这里可以继续处理 studentList
+ //};
- // 绑定事件
- _mainWin.FacialRecognitionEvent += handler;
+ //// 绑定事件
+ //_mainWin.FacialRecognitionEvent += handler;
await Task.Delay(3000);
FinishCountdown();
- _currentGameState = GameState.Running;
- }
-
- private void UpdateCountdown()
- {
- if ((DateTime.Now - _lastUpdateTime).TotalMilliseconds >= 600)
- {
- _lastUpdateTime = DateTime.Now;
- _currentCountdown -= 600;
-
- if (_currentCountdown > 0)
- {
- countdownText.Text = _currentCountdown.ToString();
- }
- else
- {
- FinishCountdown();
- }
- }
}
private async void FinishCountdown()
@@ -340,9 +305,6 @@ namespace Wpf_AiSportsMicrospace.Views
x.ImageState = "1";
});
- _mainWin.HumanFrameUpdated -= OnHumanFrameUpdated;
- _mainWin.WebcamClient.StopExtract();
-
RankingItemList = _groupJumpRopeContext.UpdateRankList();
ShowRankingBoard(RankingItemList);
Utils.StopBackgroundMusic();
@@ -350,8 +312,6 @@ namespace Wpf_AiSportsMicrospace.Views
_currentGameState = GameState.NotStarted;
_isCountdownStarted = false;
- _mainWin.HumanFrameUpdated += OnHumanFrameUpdated;
- _mainWin.WebcamClient.StartExtract();
}
private void DrawCirclesWithText()
@@ -371,7 +331,10 @@ namespace Wpf_AiSportsMicrospace.Views
// 绘制发光圆
var userItem = AddUserItem(x, y, i);
// 绑定运动对象
+
var sport = SportBase.Create("rope-skipping");
+ Optimizes.Optimizeing(sport);
+
int indexCopy = i;
var currentItem = userItem;
@@ -391,6 +354,55 @@ namespace Wpf_AiSportsMicrospace.Views
_groupJumpRopeContext.Sports.Add(sport);
}
}
+ //private void UpdateCircleCounts(List humans)
+ //{
+ // if (humans == null || humans.Count == 0)
+ // return;
+
+ // double halfW = AppSettings.AreaSize.X;
+ // double halfH = AppSettings.AreaSize.Y;
+
+ // var circles = _groupJumpRopeContext.CirclePositions;
+ // var sports = _groupJumpRopeContext.Sports;
+
+ // int circleCount = circles.Count;
+
+ // // 每个圈匹配到的人
+ // Human[] circleHumans = new Human[circleCount];
+
+ // // 1️⃣ 批量匹配圈内的人(保留原验证逻辑)
+ // foreach (var h in humans)
+ // {
+ // for (int i = 0; i < circleCount; i++)
+ // {
+ // // 已经有人占用该圈
+ // if (circleHumans[i] != null)
+ // continue;
+
+ // var circle = circles[i];
+ // double cx = circle.XNorm;
+ // double cy = circle.YNorm;
+
+ // // ⭐ 保留你的原验证
+ // if (sportOperate.IsAnyFootInCircle(h, cx, cy, halfW, halfH))
+ // {
+ // circleHumans[i] = h;
+ // break; // 每个人只匹配一个圈
+ // }
+ // }
+ // }
+
+ // // 2️⃣ 推送跳绳计数
+ // for (int i = 0; i < circleCount; i++)
+ // {
+ // var human = circleHumans[i];
+ // if (human != null)
+ // {
+ // sports[i].Pushing(human);
+ // }
+ // }
+ //}
+
private void UpdateCircleCounts(List humans)
{
double halfW = AppSettings.AreaSize.X;
@@ -418,18 +430,18 @@ namespace Wpf_AiSportsMicrospace.Views
bool hasHuman = targetHuman != null;
+ // 3️⃣ 推送跳绳计数
+ if (hasHuman)
+ {
+ _groupJumpRopeContext.Sports[i].Pushing(targetHuman);
+ }
+
// 2️⃣ 更新视觉状态
lock (_updateLock)
{
_groupJumpRopeContext.UserList[i].ImageState =
GetJumpState(i, hasHuman);
}
-
- // 3️⃣ 推送跳绳计数
- if (hasHuman)
- {
- _groupJumpRopeContext.Sports[i].Pushing(targetHuman);
- }
}
}
diff --git a/Wpf_AiSportsMicrospace/Views/SquatFu/WhackAMole.xaml.cs b/Wpf_AiSportsMicrospace/Views/SquatFu/WhackAMole.xaml.cs
index 0d095de..7eb6a9b 100644
--- a/Wpf_AiSportsMicrospace/Views/SquatFu/WhackAMole.xaml.cs
+++ b/Wpf_AiSportsMicrospace/Views/SquatFu/WhackAMole.xaml.cs
@@ -54,7 +54,7 @@ namespace Views.SquatFu
_WhackAMoleContext = new WhackAMoleContext();
}
- private async void UserControl_Loaded(object sender, RoutedEventArgs e)
+ private async void UserControl_Loaded(object sender, RoutedEventArgs e)
{
// 使用局部变量保存事件处理方法,以便解绑
Action handler = null;
@@ -62,27 +62,28 @@ namespace Views.SquatFu
var app = (App)Application.Current;
using var scope = App.AppHost.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService();
+ // 获取配置
+ var pointCount = await db.BasicConfig
+ .Where(x => x.Code == AppSettings.Code)
+ .Select(x => x.HomeWidth)
+ .FirstOrDefaultAsync();
+
var cfg = await db.GroupPoints.FirstOrDefaultAsync(x => x.Code == AppSettings.Code);
- List<(double XNorm, double YNorm)> pointlist = new List<(double XNorm, double YNorm)>();
- var points = new[] { cfg.Point1, cfg.Point2, cfg.Point3,
- cfg.Point4, cfg.Point5, cfg.Point6,
- cfg.Point7, cfg.Point8, cfg.Point9, cfg.Point10 };
-
- foreach (var point in points)
+ if (pointCount == 0 || cfg == null)
{
- if (point != null)
- {
- pointlist.Add((point.X, point.Y));
- }
+ HandyControl.Controls.MessageBox.Error("配置加载失败!", "提示");
+ return;
}
- _WhackAMoleContext.CirclePositions = pointlist;
+
+
+ _WhackAMoleContext.CirclePositions = Utils.GetPointsList(pointCount, cfg);
DrawCirclesWithText();
// 播放音乐
PlayMusic("raisehand.mp3");
_mainWin.HumanFrameUpdated += OnHumanFrameUpdated;
-
+ _mainWin.WebcamClient.StartExtract();
}
private void UserControl_Unloaded(object sender, RoutedEventArgs e)
@@ -353,7 +354,7 @@ namespace Views.SquatFu
{
// 随机决定是地鼠(1)还是兔子(3)
int imageState = _random.Next(2) == 0 ? 1 : 3;
- if(_WhackAMoleContext.UserList[index].ImageState == "0")
+ if (_WhackAMoleContext.UserList[index].ImageState == "0")
{
_WhackAMoleContext.UserList[index].ImageState = imageState.ToString();
}
@@ -467,7 +468,7 @@ namespace Views.SquatFu
{
_WhackAMoleContext.UserList[indexCopy].ImageState = "2";
}
- else if(imageState == "3")
+ else if (imageState == "3")
{
_WhackAMoleContext.UserList[indexCopy].ImageState = "4";
@@ -515,7 +516,7 @@ namespace Views.SquatFu
}
}
- void AddUserItem(double centerX, double centerY, int index)
+ void AddUserItem(double centerX, double centerY, int index)
{
//var userItem = new WhackAMoleUserControl();
//userItem.Width = 400;
@@ -547,7 +548,7 @@ namespace Views.SquatFu
}
-
+
public void ShowRankingBoard(List list)
{
var scoreGrid = FindName("ScoreGrid") as Grid;