This commit is contained in:
tanglong 2026-01-29 17:18:22 +08:00
parent 5112151fdf
commit 05f147c6ae
3 changed files with 166 additions and 174 deletions

View File

@ -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)

View File

@ -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<int, (string lastNumber, DateTime lastChangeTime, string currentState)> _jumpStatus = new Dictionary<int, (string, DateTime, string)>();
private GroupJumpRopeContext _groupJumpRopeContext;
private List<CircleArea> _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<Human> humans)
private void OnHumanFrameUpdated(object sender, List<Human> 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<Human> 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++)
{

View File

@ -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<Human> 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++)
{