举手会首页

This commit is contained in:
tanglong 2025-10-15 17:35:12 +08:00
parent 5ea60735e4
commit 6d248c8892
4 changed files with 113 additions and 47 deletions

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Enum
{
public enum GameState
{
NotStarted, // 游戏未开始
Running, // 游戏进行中
Finished // 游戏完成
}
}

View File

@ -64,14 +64,15 @@ namespace Wpf_AiSportsMicrospace
{ {
_mainWin.HumanFrameUpdated -= OnHumanFrameUpdated; _mainWin.HumanFrameUpdated -= OnHumanFrameUpdated;
} }
private bool IsGestureActive = true; // 标记手势识别是否有效
private void OnHumanFrameUpdated(object sender, List<Human> humans) private void OnHumanFrameUpdated(object sender, List<Human> humans)
{ {
var human = humans.FirstOrDefault(); if (!IsGestureActive) return; // 手势识别已停止,直接返回
var human = humans.FirstOrDefault();
if (human == null) return; if (human == null) return;
//检测挥手动作 // 检测挥手动作
var wavingaction = _mainWin.SportOperate.VerifyWavingAction(humans); var wavingaction = _mainWin.SportOperate.VerifyWavingAction(humans);
switch (wavingaction) switch (wavingaction)
@ -93,6 +94,9 @@ namespace Wpf_AiSportsMicrospace
case (int)WavingAction.RaiseHand: // 举手完成 case (int)WavingAction.RaiseHand: // 举手完成
coverFlow.ProgressCompleted += CoverFlow_ProgressCompleted; coverFlow.ProgressCompleted += CoverFlow_ProgressCompleted;
// 设置标记,停止后续手势识别
IsGestureActive = false;
break; break;
default: // 没有动作 → 取消进度 default: // 没有动作 → 取消进度

View File

@ -1,5 +1,6 @@
using Dto; using Dto;
using Emgu.CV.Flann; using Emgu.CV.Flann;
using Enum;
using HandyControl.Controls; using HandyControl.Controls;
using SharpDX.Direct3D9; using SharpDX.Direct3D9;
using System; using System;
@ -49,18 +50,20 @@ namespace Wpf_AiSportsMicrospace.Views
private MediaPlayer _mediaPlayer = new MediaPlayer(); private MediaPlayer _mediaPlayer = new MediaPlayer();
List<RankItem> RankingItemList = new(); List<RankItem> RankingItemList = new();
private readonly SportDetectionQueue _detectQueue;
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{ {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
} }
private bool IsGameStarted = false; private GameState _currentGameState = GameState.NotStarted;
private readonly object _updateLock = new object(); private readonly object _updateLock = new object();
private readonly Dictionary<int, (string lastNumber, DateTime lastChangeTime, string currentState)> _jumpStatus = new Dictionary<int, (string, DateTime, string)>(); private readonly Dictionary<int, (string lastNumber, DateTime lastChangeTime, string currentState)> _jumpStatus = new Dictionary<int, (string, DateTime, string)>();
private GroupJumpRopeContext _groupJumpRopeContext; private GroupJumpRopeContext _groupJumpRopeContext;
public GroupJumpRope() public GroupJumpRope()
{ {
InitializeComponent(); InitializeComponent();
_detectQueue = new SportDetectionQueue();
Loaded += UserControl_Loaded; Loaded += UserControl_Loaded;
Unloaded += UserControl_Unloaded; Unloaded += UserControl_Unloaded;
_groupJumpRopeContext = new GroupJumpRopeContext(); _groupJumpRopeContext = new GroupJumpRopeContext();
@ -162,47 +165,46 @@ namespace Wpf_AiSportsMicrospace.Views
private void OnHumanFrameUpdated(object sender, List<Human> humans) private void OnHumanFrameUpdated(object sender, List<Human> humans)
{ {
try try
{
if (!IsGameStarted)
{ {
if (humans == null || humans.Count == 0) return; if (humans == null || humans.Count == 0) return;
switch (_currentGameState)
int wavingaction = 0; {
case GameState.NotStarted: // 未开始
wavingaction = DetectRightHandRaise(humans); int rightWaving = DetectRightHandRaise(humans);
if (rightWaving >= 3)
if (wavingaction < 3) {
return; switch (rightWaving)
switch (wavingaction)
{ {
case (int)WavingAction.FirstHand: case (int)WavingAction.FirstHand:
// 第一次举手,初始化倒计时
StartCountdown(3); StartCountdown(3);
break; break;
case (int)WavingAction.Raising: case (int)WavingAction.Raising:
// 持续倒计时中
UpdateCountdown(); UpdateCountdown();
break; break;
case (int)WavingAction.RaiseHand: case (int)WavingAction.RaiseHand:
// 举手完成,倒计时结束
FinishCountdown(); FinishCountdown();
break; _currentGameState = GameState.Running; // 倒计时完成 → 游戏开始
default:
// 没检测到动作,重置倒计时显示
Utils.StopBackgroundMusic();
countdownText.Text = "3";
countdownGrid.Visibility = Visibility.Hidden;
break; break;
} }
} }
else break;
{
case GameState.Running: // 游戏进行中
UpdateCircleCounts(humans); UpdateCircleCounts(humans);
// 可选:判断游戏结束条件,将状态切换到 Finished
// if (CheckGameFinished()) _currentGameState = GameState.Finished;
break;
case GameState.Finished: // 游戏完成
int leftWaving = DetectLeftHandRaise(humans);
if (leftWaving == 5)
{
// 举左手逻辑,例如结束动画或退出
var newPage = new Home();
_mainWin?.SwitchPageWithMaskAnimation(newPage, true);
}
break;
} }
} }
catch (Exception ex) catch (Exception ex)
@ -210,6 +212,7 @@ namespace Wpf_AiSportsMicrospace.Views
Console.WriteLine("OnFrameExtracted error: " + ex.Message); Console.WriteLine("OnFrameExtracted error: " + ex.Message);
} }
} }
private int _currentCountdown = 3; private int _currentCountdown = 3;
private DateTime _lastUpdateTime = DateTime.Now; private DateTime _lastUpdateTime = DateTime.Now;
private void StartCountdown(int start = 3) private void StartCountdown(int start = 3)
@ -246,11 +249,9 @@ namespace Wpf_AiSportsMicrospace.Views
{ {
countdownText.Text = "GO!"; countdownText.Text = "GO!";
countdownGrid.Visibility = Visibility.Hidden; countdownGrid.Visibility = Visibility.Hidden;
IsGameStarted = true;
// 播放背景音乐(循环) // 播放背景音乐(循环)
Utils.PlayBackgroundMusic("homeprojectselected1.mp3", true); Utils.PlayBackgroundMusic("homeprojectselected1.mp3", true);
// 启动60秒倒计时独立任务 // 启动60秒倒计时独立任务
StartGameCountdown(60); StartGameCountdown(60);
} }
@ -273,8 +274,9 @@ namespace Wpf_AiSportsMicrospace.Views
RankingItemList = _groupJumpRopeContext.UpdateRankList(); RankingItemList = _groupJumpRopeContext.UpdateRankList();
ShowRankingBoard(RankingItemList); ShowRankingBoard(RankingItemList);
IsGameStarted = false;
Utils.StopBackgroundMusic(); Utils.StopBackgroundMusic();
_currentGameState = GameState.Finished;
} }
private DateTime? _raiseStartTime; private DateTime? _raiseStartTime;
@ -367,6 +369,46 @@ namespace Wpf_AiSportsMicrospace.Views
// 没有任何中心区域内的人举手 // 没有任何中心区域内的人举手
return (int)WavingAction.None; return (int)WavingAction.None;
} }
public int DetectLeftHandRaise(List<Human> humans)
{
if (humans == null || humans.Count == 0)
return (int)WavingAction.None;
foreach (var human in humans)
{
if (human?.Keypoints == null)
continue;
// --- 筛选右脚踝坐标 ---
var rightAnkle = human.Keypoints.FirstOrDefault(k => k.Name == "right_ankle");
if (rightAnkle == null)
continue;
double xNorm = rightAnkle.X / 1920;
double yNorm = rightAnkle.Y / 1080;
// 仅检测中心区域内的人
if (!(xNorm >= 0.44 && xNorm <= 0.57 && yNorm >= 0.81))
continue;
// 获取左手关键点
var leftWrist = human.Keypoints.FirstOrDefault(k => k.Name == "left_wrist");
var leftElbow = human.Keypoints.FirstOrDefault(k => k.Name == "left_elbow");
if (leftWrist == null || leftElbow == null)
continue;
const double raiseThreshold = 60; // 举手阈值
// 判断左手是否举起
double verticalRise = leftWrist.Y - leftElbow.Y;
if (verticalRise >= raiseThreshold)
{
return (int)WavingAction.RaiseHand; // 一旦检测到左手举起,立即返回
}
}
return (int)WavingAction.None; // 没有检测到举手
}
private void ResetRaiseState() private void ResetRaiseState()
{ {
@ -529,7 +571,8 @@ namespace Wpf_AiSportsMicrospace.Views
number3.Text = list[2].Number.ToString(); number3.Text = list[2].Number.ToString();
foreach (var item in list) foreach (var item in list)
{ {
var grid = new Grid { var grid = new Grid
{
Width = 1344, Width = 1344,
Height = 71, Height = 71,
HorizontalAlignment = HorizontalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Center,
@ -549,8 +592,8 @@ namespace Wpf_AiSportsMicrospace.Views
Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#999999")), Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#999999")),
HorizontalAlignment = HorizontalAlignment.Left, HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Center, VerticalAlignment = VerticalAlignment.Center,
TextAlignment= TextAlignment.Center, TextAlignment = TextAlignment.Center,
Width=200 Width = 200
}; };
grid.Children.Add(rankText); grid.Children.Add(rankText);

View File

@ -30,6 +30,7 @@ namespace Wpf_AiSportsMicrospace.Views
private HumanGraphicsRenderer _humanGraphicsRenderer; private HumanGraphicsRenderer _humanGraphicsRenderer;
public SportOperate SportOperate { get; private set; } public SportOperate SportOperate { get; private set; }
public WebcamClient WebcamClient { get; private set; } public WebcamClient WebcamClient { get; private set; }
private readonly SportDetectionQueue _detectQueue;
private readonly ConcurrentQueue<VideoFrame> _frameQueue = new(); private readonly ConcurrentQueue<VideoFrame> _frameQueue = new();
private readonly CancellationTokenSource _cts = new(); private readonly CancellationTokenSource _cts = new();
private DateTime _lastFrameTime = DateTime.Now; private DateTime _lastFrameTime = DateTime.Now;
@ -52,6 +53,7 @@ namespace Wpf_AiSportsMicrospace.Views
_humanPredictor = HumanPredictorFactory.Create(HumanPredictorType.MultiMedium); _humanPredictor = HumanPredictorFactory.Create(HumanPredictorType.MultiMedium);
_humanGraphicsRenderer = new HumanGraphicsRenderer(); _humanGraphicsRenderer = new HumanGraphicsRenderer();
_humanGraphicsRenderer.DrawLabel = false; _humanGraphicsRenderer.DrawLabel = false;
_detectQueue = new SportDetectionQueue();
SportOperate = new SportOperate(); SportOperate = new SportOperate();
WebcamClient = SportOperate.CreateRTSP(); WebcamClient = SportOperate.CreateRTSP();
@ -108,6 +110,10 @@ namespace Wpf_AiSportsMicrospace.Views
var humans = humanResult?.Humans?.ToList(); var humans = humanResult?.Humans?.ToList();
if (humans == null || humans.Count == 0) if (humans == null || humans.Count == 0)
return; return;
foreach (var human in humans)
{
_detectQueue.Enqueue(frame.Number, human, null);
}
// 触发全局事件 // 触发全局事件
Application.Current.Dispatcher.BeginInvoke(() => Application.Current.Dispatcher.BeginInvoke(() =>