From 7db24230e0b3951f85b4f2ddfd9e496bc413bff4 Mon Sep 17 00:00:00 2001
From: tanglong <842690096@qq.com>
Date: Mon, 13 Oct 2025 14:36:18 +0800
Subject: [PATCH] =?UTF-8?q?=E5=80=92=E8=AE=A1=E6=97=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../MyUserControl/SportUserItem.xaml | 25 +-
.../MyUserControl/SportUserItem.xaml.cs | 92 ++++-
.../Views/CenterHome.xaml.cs | 33 +-
Wpf_AiSportsMicrospace/Views/Home.xaml.cs | 9 +-
.../Views/JumpRope/GroupJumpRope.xaml | 17 +-
.../Views/JumpRope/GroupJumpRope.xaml.cs | 334 ++++++++----------
Wpf_AiSportsMicrospace/Views/Main.xaml.cs | 155 +-------
7 files changed, 275 insertions(+), 390 deletions(-)
diff --git a/Wpf_AiSportsMicrospace/MyUserControl/SportUserItem.xaml b/Wpf_AiSportsMicrospace/MyUserControl/SportUserItem.xaml
index 42fc688..5a12fde 100644
--- a/Wpf_AiSportsMicrospace/MyUserControl/SportUserItem.xaml
+++ b/Wpf_AiSportsMicrospace/MyUserControl/SportUserItem.xaml
@@ -11,7 +11,7 @@
-
+
@@ -32,7 +32,7 @@
HorizontalAlignment="Center"
VerticalAlignment="Top"/>
-
@@ -44,6 +44,23 @@
VerticalAlignment="Top"
Width="370"
Margin="0,131,0,0"
- Visibility="{Binding ImageState, RelativeSource={RelativeSource AncestorType=UserControl}, Converter={StaticResource ImageStateToVisibilityConverter}, ConverterParameter=2}" />
+ Visibility="{Binding ImageState, RelativeSource={RelativeSource AncestorType=UserControl}, Converter={StaticResource ImageStateToVisibilityConverter}, ConverterParameter=2}" />-->
+
+
+
+
+
+
-
+
\ No newline at end of file
diff --git a/Wpf_AiSportsMicrospace/MyUserControl/SportUserItem.xaml.cs b/Wpf_AiSportsMicrospace/MyUserControl/SportUserItem.xaml.cs
index acb646d..1c3ba4b 100644
--- a/Wpf_AiSportsMicrospace/MyUserControl/SportUserItem.xaml.cs
+++ b/Wpf_AiSportsMicrospace/MyUserControl/SportUserItem.xaml.cs
@@ -1,4 +1,5 @@
-using System;
+using HandyControl.Controls;
+using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
@@ -17,6 +18,7 @@ using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
+using WpfAnimatedGif;
namespace Wpf_AiSportsMicrospace.MyUserControl
{
@@ -29,6 +31,7 @@ namespace Wpf_AiSportsMicrospace.MyUserControl
public SportUserItem()
{
InitializeComponent();
+ //InitGif();
}
public string DisplayText
@@ -43,20 +46,99 @@ namespace Wpf_AiSportsMicrospace.MyUserControl
public string NumberText
{
get => (string)GetValue(NumberTextProperty);
- set => SetValue(DisplayTextProperty, value);
+ set => SetValue(NumberTextProperty, value);
}
public static readonly DependencyProperty NumberTextProperty =
- DependencyProperty.Register(nameof(NumberText), typeof(string), typeof(SportUserItem), new PropertyMetadata("??"));
+ DependencyProperty.Register(nameof(NumberText), typeof(string), typeof(SportUserItem), new PropertyMetadata("0"));
public string ImageState
- //0 没有人 1 准备中 2 运动中 3 出圈了
+ //0 没有人 1 准备中 2 运动中 3 出圈了
{
get => (string)GetValue(ImageStateProperty);
set => SetValue(ImageStateProperty, value);
}
public static readonly DependencyProperty ImageStateProperty =
- DependencyProperty.Register(nameof(ImageState), typeof(string), typeof(SportUserItem), new PropertyMetadata("0"));
+ DependencyProperty.Register(nameof(ImageState), typeof(string), typeof(SportUserItem), new PropertyMetadata("0", OnImageStateChanged));
+
+ private static void OnImageStateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var control = (SportUserItem)d;
+ control.ShowImage((string)e.NewValue);
+ }
+ private void ShowImage(string imageIndex)
+ {
+ // 隐藏所有图片
+ image1.Visibility = Visibility.Hidden;
+ image2.Visibility = Visibility.Hidden;
+ image3.Visibility = Visibility.Hidden;
+
+ // 显示指定的图片
+ switch (imageIndex)
+ {
+ case "1":
+ //image1.Visibility = Visibility.Visible;
+ //image1.Visibility = Visibility.Visible;
+ image1.Visibility = Visibility.Visible;
+ //Pause_Click();
+ break;
+ case "2":
+ //image2.Visibility = Visibility.Visible;
+ image2.Visibility = Visibility.Visible;
+ //Play_Click();
+ break;
+ case "3":
+ image3.Visibility = Visibility.Visible;
+ break;
+ }
+ }
+ private BitmapImage _gifSource;
+ private BitmapFrame _firstFrame; // <- 改为 BitmapFrame
+
+ private void InitGif()
+ {
+ var uri = new Uri("pack://application:,,,/Resources/Img/test_img/one_rope/jump_rope.gif");
+
+ // 1) 加载用于播放的 BitmapImage(注意 OnLoad 防止被锁定)
+ _gifSource = new BitmapImage();
+ _gifSource.BeginInit();
+ _gifSource.UriSource = uri;
+ _gifSource.CacheOption = BitmapCacheOption.OnLoad;
+ _gifSource.EndInit();
+
+ // 2) 提取第一帧(使用 GifBitmapDecoder)
+ var sri = Application.GetResourceStream(uri);
+ if (sri != null)
+ {
+ using (var stream = sri.Stream)
+ {
+ var decoder = new GifBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
+ if (decoder.Frames.Count > 0)
+ _firstFrame = decoder.Frames[0];
+ }
+ }
+
+ // 3) 默认显示第一帧(静态)
+ image2.Source = _firstFrame;
+ }
+
+ private void Play_Click()
+ {
+ // 重新设置动画源并播放
+ //ImageBehavior.SetAnimatedSource(image2, _gifSource);
+ //ImageBehavior.GetAnimationController(image2)?.Play();
+ var controller = ImageBehavior.GetAnimationController(image2);
+ controller?.Play();
+ }
+ private void Pause_Click()
+ {
+ var controller = ImageBehavior.GetAnimationController(image2);
+ if (controller != null)
+ {
+ controller.Pause(); // 暂停动画
+ //controller.GotoFrame(0); // 回到第一帧
+ }
+ }
}
}
\ No newline at end of file
diff --git a/Wpf_AiSportsMicrospace/Views/CenterHome.xaml.cs b/Wpf_AiSportsMicrospace/Views/CenterHome.xaml.cs
index cb9a057..ac01d92 100644
--- a/Wpf_AiSportsMicrospace/Views/CenterHome.xaml.cs
+++ b/Wpf_AiSportsMicrospace/Views/CenterHome.xaml.cs
@@ -33,7 +33,6 @@ namespace Wpf_AiSportsMicrospace.Views
///
public partial class CenterHome : UserControl
{
- private SportOperate _sportOperate;
private Main _mainWin => Application.Current.MainWindow as Main;
public String _nowSelect = "test"; //测试吧:test 游戏吧:play
@@ -53,11 +52,6 @@ namespace Wpf_AiSportsMicrospace.Views
public CenterHome()
{
InitializeComponent();
- //string imgPath = Path.Combine(projectRoot, "Resources", "Img" , _nowSelect == "test" ? "test_img" : "play_img");
-
- // 默认选中第1张
- coverFlow.SelectedIndex = 0;
-
InitImg();
Loaded += Window_Loaded;
@@ -68,8 +62,6 @@ namespace Wpf_AiSportsMicrospace.Views
private void Window_Loaded(object sender, RoutedEventArgs e)
{
_mainWin.HumanFrameUpdated += OnHumanFrameUpdated;
-
- //Utils.PlayBackgroundMusic("homeprojectselected.mp3", true);
}
private void CenterHome_Unloaded(object sender, RoutedEventArgs e)
@@ -115,7 +107,6 @@ namespace Wpf_AiSportsMicrospace.Views
private void CoverFlow_ProgressCompleted(CoverFlowItem item)
{
- // 停止抽帧线程/释放资源
try
{
RouterGoNew();
@@ -124,28 +115,6 @@ namespace Wpf_AiSportsMicrospace.Views
{
Debug.WriteLine($"停止抽帧异常: {ex.Message}");
}
-
- // 解绑事件,防止重复触发
- //coverFlow.ProgressCompleted -= CoverFlow_ProgressCompleted;
-
- // 根据图片跳转新窗口
- string uri = item.ImageUri.ToString();
-
- //if (uri.EndsWith("1.jpg"))
- // newWindow = new GroupJumpRope();
- //else if (uri.EndsWith("2.jpg"))
- // newWindow = new GroupJumpRope();
- //else if (uri.EndsWith("3.jpg"))
- // newWindow = new GroupJumpRope();
- // 找到主窗口,切换内容到 GroupJumpRopePage
-
- //var mainWin = Application.Current.MainWindow as Main;
- //if (mainWin != null)
- //{
- // Utils.PlayBackgroundMusic("musicjumprope1.mp3");
- // mainWin.SwitchPage(new GroupJumpRope(), true);
- //}
-
}
public void InitImg()
{
@@ -165,7 +134,7 @@ namespace Wpf_AiSportsMicrospace.Views
coverFlow.Images.Add(new CoverFlowItem { ImageUri = new Uri(Path.Combine(imgPath, "play_jump.png")), ProgressColor1 = "#e73d42", ProgressColor2 = "#fd8212" });
coverFlow.Images.Add(new CoverFlowItem { ImageUri = new Uri(Path.Combine(imgPath, "play_music.png")), ProgressColor1 = "#e73d42", ProgressColor2 = "#215bc7" });
}
-
+ coverFlow.SelectedIndex = 0;
}
//跳转二级页面
diff --git a/Wpf_AiSportsMicrospace/Views/Home.xaml.cs b/Wpf_AiSportsMicrospace/Views/Home.xaml.cs
index f336520..eb6a3a6 100644
--- a/Wpf_AiSportsMicrospace/Views/Home.xaml.cs
+++ b/Wpf_AiSportsMicrospace/Views/Home.xaml.cs
@@ -55,7 +55,10 @@ namespace Wpf_AiSportsMicrospace
Utils.PlayBackgroundMusic("homeprojectselected.mp3", true);
}
-
+ private void Window_Loaded(object sender, RoutedEventArgs e)
+ {
+ _mainWin.HumanFrameUpdated += OnHumanFrameUpdated;
+ }
private void Home_Unloaded(object sender, RoutedEventArgs e)
{
_mainWin.HumanFrameUpdated -= OnHumanFrameUpdated;
@@ -98,10 +101,6 @@ namespace Wpf_AiSportsMicrospace
}
- private void Window_Loaded(object sender, RoutedEventArgs e)
- {
- _mainWin.HumanFrameUpdated += OnHumanFrameUpdated;
- }
private void CoverFlow_ProgressCompleted(CoverFlowItem item)
{
// 停止抽帧线程/释放资源
diff --git a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml
index c4d854c..1a9b0a2 100644
--- a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml
+++ b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml
@@ -5,24 +5,22 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.MyUserControl"
mc:Ignorable="d" Height="1080" Width="1920" Loaded="UserControl_Loaded" Unloaded="UserControl_Unloaded">
-
+
-
-
-
-
-
-
-
-
+
+
+
+
-
diff --git a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs
index c097bf7..0647c8b 100644
--- a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs
+++ b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs
@@ -43,12 +43,14 @@ namespace Wpf_AiSportsMicrospace.Views
private List sports = new();
private List circleTexts = new();
private List userList = new();
+ private List userNumberList = ["0", "0", "0", "0", "0", "0", "0"];
private double[] circlePositionsX = { 0.07, 0.21, 0.36, 0.50, 0.64, 0.78, 0.92 };
private Main _mainWin => Application.Current.MainWindow as Main;
private List<(double XNorm, double YNorm)> circlePositions = new();
private MediaPlayer _mediaPlayer = new MediaPlayer();
private bool IsGameStarted = false;
+ List _useName = ["四号位", "一号位", "五号位", "二号位", "六号位", "三号位", "七号位",];
public GroupJumpRope()
{
InitializeComponent();
@@ -59,6 +61,7 @@ namespace Wpf_AiSportsMicrospace.Views
private async void UserControl_Loaded(object sender, RoutedEventArgs e)
{
DrawCirclesWithText();
+
// 播放音乐
PlayMusic("raisehand.mp3");
}
@@ -67,56 +70,6 @@ namespace Wpf_AiSportsMicrospace.Views
{
_mainWin.HumanFrameUpdated -= OnHumanFrameUpdated;
}
- private void ShowCenterTip(string imagePath, TimeSpan duration)
- {
- var tipImage = new Image
- {
- Source = new BitmapImage(new Uri(imagePath, UriKind.Absolute)),
- HorizontalAlignment = HorizontalAlignment.Center,
- VerticalAlignment = VerticalAlignment.Center,
- Opacity = 0
- };
-
- // 增加图片的大小,调整比例
- tipImage.Width = overlayCanvas.ActualWidth * 0.9; // 宽度为 Canvas 宽度的 90%
- tipImage.Height = overlayCanvas.ActualHeight * 0.6; // 高度为 Canvas 高度的 60%
-
- // 将图片添加到 Overlay Canvas
- overlayCanvas.Children.Add(tipImage);
- Canvas.SetLeft(tipImage, (overlayCanvas.ActualWidth - tipImage.Width) / 2); // 居中
- Canvas.SetTop(tipImage, (overlayCanvas.ActualHeight - tipImage.Height) / 2); // 居中
-
- // 渐变出现动画
- var fadeInAnimation = new DoubleAnimation
- {
- From = 0,
- To = 1,
- Duration = TimeSpan.FromSeconds(1.5)
- };
- tipImage.BeginAnimation(UIElement.OpacityProperty, fadeInAnimation);
-
- // 定时移除,并且渐变消失
- Task.Delay(duration).ContinueWith(_ =>
- {
- Dispatcher.Invoke(() =>
- {
- // 渐变消失动画
- var fadeOutAnimation = new DoubleAnimation
- {
- From = 1,
- To = 0,
- Duration = TimeSpan.FromSeconds(1.5)
- };
- tipImage.BeginAnimation(UIElement.OpacityProperty, fadeOutAnimation);
-
- // 完成后移除图片
- fadeOutAnimation.Completed += (s, e) =>
- {
- overlayCanvas.Children.Remove(tipImage);
- };
- });
- });
- }
private void PlayMusic(string musicFileName)
{
@@ -147,17 +100,16 @@ namespace Wpf_AiSportsMicrospace.Views
Source = new BitmapImage(new Uri(imagePath, UriKind.Absolute)),
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
- Opacity = 0
+ Opacity = 0,
+ Margin = new Thickness(0, -100, 0, 0),
};
// 增加图片的大小,调整比例
- tipImage.Width = overlayCanvas.ActualWidth * 0.9; // 宽度为 Canvas 宽度的 90%
- tipImage.Height = overlayCanvas.ActualHeight * 0.6; // 高度为 Canvas 高度的 60%
+ tipImage.Width = 1920 * 0.9; // 宽度为 Canvas 宽度的 90%
+ tipImage.Height = 1080 * 0.6; // 高度为 Canvas 高度的 60%
// 将图片添加到 Overlay Canvas
- overlayCanvas.Children.Add(tipImage);
- Canvas.SetLeft(tipImage, (overlayCanvas.ActualWidth - tipImage.Width) / 2); // 居中
- Canvas.SetTop(tipImage, (overlayCanvas.ActualHeight - tipImage.Height) / 2); // 居中
+ userBox.Children.Add(tipImage);
// 渐变出现动画
var fadeInAnimation = new DoubleAnimation
@@ -185,7 +137,7 @@ namespace Wpf_AiSportsMicrospace.Views
// 完成后移除图片
fadeOutAnimation.Completed += (s, e) =>
{
- overlayCanvas.Children.Remove(tipImage);
+ userBox.Children.Remove(tipImage);
};
});
});
@@ -233,8 +185,7 @@ namespace Wpf_AiSportsMicrospace.Views
// 没检测到动作,重置倒计时显示
Utils.StopBackgroundMusic();
countdownText.Text = "3";
- countdownText.Visibility = Visibility.Collapsed;
- countdownGrid.Visibility = Visibility.Collapsed;
+ countdownGrid.Visibility = Visibility.Hidden;
break;
}
}
@@ -255,7 +206,6 @@ namespace Wpf_AiSportsMicrospace.Views
{
_currentCountdown = start;
countdownText.Text = _currentCountdown.ToString();
- countdownText.Visibility = Visibility.Visible;
countdownGrid.Visibility = Visibility.Visible;
_lastUpdateTime = DateTime.Now;
@@ -282,15 +232,16 @@ namespace Wpf_AiSportsMicrospace.Views
private async void FinishCountdown()
{
- foreach (var item in userList)
- {
- item.ImageState = "2";
- }
+ //foreach (var item in userList)
+ //{
+ // item.ImageState = "2";
+ //}
// 举手完成,显示 ✔
countdownText.Text = "GO!";
- countdownText.Visibility = Visibility.Collapsed;
- countdownGrid.Visibility = Visibility.Collapsed;
+ countdownGrid.Visibility = Visibility.Hidden;
IsGameStarted = true;
+
+
// 播放背景音乐(循环)
Utils.PlayBackgroundMusic("homeprojectselected1.mp3", true);
@@ -299,25 +250,18 @@ namespace Wpf_AiSportsMicrospace.Views
}
private async void StartGameCountdown(int seconds)
{
- countdownText.Visibility = Visibility.Visible;
countdownGrid.Visibility = Visibility.Visible;
for (int i = seconds; i >= 0; i--)
{
countdownText.Text = i.ToString();
- await Task.Delay(1000); // 不阻塞主线程,计数逻辑继续执行
+ await Task.Delay(1000);
}
- countdownText.Visibility = Visibility.Collapsed;
- countdownGrid.Visibility = Visibility.Collapsed;
+ countdownGrid.Visibility = Visibility.Hidden;
IsGameStarted = false;
- // 倒计时完成后可以触发其他逻辑,例如停止音乐
- foreach (var item in userList)
- {
- item.ImageState = "1";
- }
Utils.StopBackgroundMusic();
}
@@ -331,64 +275,64 @@ namespace Wpf_AiSportsMicrospace.Views
var rightWrist = human.Keypoints.FirstOrDefault(k => k.Name == "right_wrist");
var rightElbow = human.Keypoints.FirstOrDefault(k => k.Name == "right_elbow");
- if (rightWrist == null || rightElbow == null)
- return (int)WavingAction.None;
+ const double raiseThreshold = 60; // 举手阈值
+ const double holdDuration = 2; // 持续 2 秒触发倒计时
+ const int countdownSeconds = 3; // 倒计时长度
- double verticalRise = rightElbow.Y - rightWrist.Y; // 手腕高于肘部 → 正值
- const double raiseThreshold = 60; // 举手阈值,可调整
+ bool handRaised = false;
- if (verticalRise >= raiseThreshold)
+ if (rightWrist != null && rightElbow != null)
{
- // 初始化
- _raiseStartTime ??= DateTime.Now;
- _wristStartTime ??= DateTime.Now;
- _countdownStartTime ??= DateTime.Now;
-
- var wristDuration = DateTime.Now - _wristStartTime.Value;
-
- // 第一次举手触发
- if (!_firstHandTriggered && wristDuration.TotalSeconds >= 1)
- {
- _firstHandTriggered = true;
- _lastCountdownSecond = 3;
- _countdownStartTime = DateTime.Now;
- return (int)WavingAction.FirstHand;
- }
-
- // 倒计时逻辑
- if (_firstHandTriggered)
- {
- var elapsed = DateTime.Now - _countdownStartTime.Value;
- int currentSecond = 3 - (int)Math.Floor(elapsed.TotalSeconds);
-
- if (currentSecond != _lastCountdownSecond && currentSecond > 0)
- {
- _lastCountdownSecond = currentSecond;
- // 你可以在这里触发倒计时提示(比如语音播报或 UI 更新)
- Console.WriteLine($"倒计时:{currentSecond}");
- return (int)WavingAction.Raising; // 可选:倒计时状态
- }
-
- // 举手完成
- if (elapsed.TotalSeconds >= 3)
- {
- ResetRaiseState();
- return (int)WavingAction.RaiseHand; // 举手完成
- }
-
- return (int)WavingAction.Raising; // 举手中
- }
-
- return (int)WavingAction.Raising;
+ double verticalRise = rightElbow.Y - rightWrist.Y;
+ handRaised = verticalRise >= raiseThreshold;
}
- else
+
+ // ---------- 第一步:持续举手触发倒计时 ----------
+ if (!_firstHandTriggered)
+ {
+ if (handRaised)
+ {
+ _raiseStartTime ??= DateTime.Now;
+ var holdElapsed = (DateTime.Now - _raiseStartTime.Value).TotalSeconds;
+ if (holdElapsed >= holdDuration)
+ {
+ // 举手达到 2 秒,启动倒计时
+ _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.None;
+ return (int)WavingAction.RaiseHand; // 举手完成
}
+
+ return (int)WavingAction.Raising; // 倒计时中
}
+
private void ResetRaiseState()
{
_raiseStartTime = null;
@@ -398,28 +342,31 @@ namespace Wpf_AiSportsMicrospace.Views
_lastCountdownSecond = 3;
}
+ private Dictionary _lastJumpUpdateTime = new Dictionary();
public Human LocateHuman(List humans, double begin, double end, double frameWidth, double frameHeight, int circleIndex)
{
if (humans == null || humans.Count == 0)
+ {
return null;
+ }
double circleX = circlePositions[circleIndex].XNorm;
double circleY = circlePositions[circleIndex].YNorm;
- double radiusNormX = 0.07; // X方向半径
- double radiusNormY = 0.1; // Y方向半径
+ double radiusNormX = 0.073;
+ double radiusNormY = 0.135;
+
+ Human inCircleHuman = null;
+ bool isOut = false;
foreach (var hu 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 / frameWidth;
double xLeftNorm = leftFoot.X / frameWidth;
-
- // 前后出圈检测(Y方向)
double yRightNorm = rightFoot.Y / frameHeight;
double yLeftNorm = leftFoot.Y / frameHeight;
@@ -431,32 +378,61 @@ namespace Wpf_AiSportsMicrospace.Views
if (outOfCircle)
{
- Application.Current.Dispatcher.BeginInvoke(() =>
- {
- circleTexts[circleIndex].Text = "您已出圈!";
- userList[circleIndex].ImageState = "3";
- });
- continue;
+ isOut = true;
}
-
- // X 范围匹配 → 未出圈的人
- if (xRightNorm >= (circleX - radiusNormX) && xRightNorm <= (circleX + radiusNormX))
+ else if (inCircleHuman == null)
{
- return hu; // 返回给计数逻辑
+ inCircleHuman = hu;
}
}
- return null;
+ if (isOut)
+ userList[circleIndex].ImageState = "3";
+ else
+ {
+ if (userList[circleIndex].ImageState == "3")
+ {
+ userList[circleIndex].ImageState = "1";
+ }
+
+ if (userNumberList[circleIndex] == userList[circleIndex].NumberText)
+ {
+ // 获取上次触发时间
+ if (!_lastJumpUpdateTime.TryGetValue(circleIndex, out var lastTime))
+ {
+ lastTime = DateTime.MinValue;
+ }
+
+ // 判断是否超过 2 秒
+ if ((DateTime.Now - lastTime).TotalSeconds >= 1)
+ {
+ userList[circleIndex].ImageState = "1";
+ _lastJumpUpdateTime[circleIndex] = DateTime.Now;
+ }
+ }
+ else
+ {
+ userNumberList[circleIndex] = userList[circleIndex].NumberText;
+ }
+ }
+ //else if
+ // (inCircleHuman != null) userList[circleIndex].ImageState = "1";
+ //else
+ // userList[circleIndex].ImageState = "1";
+
+ return inCircleHuman;
}
+
private void DrawCirclesWithText()
{
- overlayCanvas.Children.Clear();
+ userBox.Children.Clear();
sports.Clear();
circleTexts.Clear();
+ userList.Clear(); // 清空用户控件列表
- double imgWidth = overlayCanvas.ActualWidth;
- double imgHeight = overlayCanvas.ActualHeight;
+ double imgWidth = userBox.ActualWidth;
+ double imgHeight = userBox.ActualHeight;
double radius = 100;
// 每个圆的位置:X 和 Y 都归一化 0~1
@@ -479,37 +455,35 @@ namespace Wpf_AiSportsMicrospace.Views
// 绘制发光圆
//AddGlowEllipse(x, y, overlayCanvas);
-
- AddUserItem(x, y, i);
-
-
- // 创建文本控件
- var text = new TextBlock
- {
- Text = "0",
- Foreground = Brushes.Red,
- FontWeight = FontWeights.Bold,
- FontSize = 50,
- TextAlignment = TextAlignment.Center,
- Width = radius * 2
- };
-
- Canvas.SetLeft(text, x - radius);
- Canvas.SetTop(text, y - radius - 25);
- overlayCanvas.Children.Add(text);
- circleTexts.Add(text);
-
+ var userItem = AddUserItem(x, y, i);
// 绑定运动对象
var sport = SportBase.Create("rope-skipping");
- int index = circleTexts.Count - 1;
+ int indexCopy = i;
+ var currentItem = userItem;
+
+ // 订阅事件
sport.OnTicked += (count, times) =>
{
- Application.Current.Dispatcher.BeginInvoke(() =>
- {
- circleTexts[index].Text = count.ToString();
- userList[index].NumberText = count.ToString();
- });
+ //if (currentItem.NumberText == count.ToString())
+ //{
+ // currentItem.ImageState = "1";
+ //}
+ //else
+ //{
+
+ // currentItem.ImageState = "2";
+ // currentItem.NumberText = count.ToString();
+ //}
+
+ currentItem.ImageState = "2";
+ currentItem.NumberText = count.ToString();
+
+ //Application.Current.Dispatcher.BeginInvoke(() =>
+ //{
+ // currentItem.NumberText = count.ToString();
+ //});
};
+
sport.Start();
sports.Add(sport);
}
@@ -523,7 +497,7 @@ namespace Wpf_AiSportsMicrospace.Views
double begin = center - range;
double end = center + range;
- var human = LocateHuman(humans, begin, end, overlayCanvas.ActualWidth, overlayCanvas.ActualHeight, i);
+ var human = LocateHuman(humans, begin, end, userBox.ActualWidth, userBox.ActualHeight, i);
if (human != null)
{
sports[i].Pushing(human);
@@ -535,31 +509,17 @@ namespace Wpf_AiSportsMicrospace.Views
///
private SportUserItem AddUserItem(double centerX, double centerY, int index)
{
- List trueName = ["一号位", "二号位", "三号位", "四号位", "五号位", "六号位", "七号位", ];
- List useName = ["四号位", "一号位", "五号位", "二号位", "六号位", "三号位", "七号位", ];
var userItem = new SportUserItem();
userItem.Width = 270;
userItem.Height = 560;
- userItem.DisplayText = useName[index];
+ userItem.DisplayText = _useName[index];
userItem.VerticalAlignment = VerticalAlignment.Top;
userItem.HorizontalAlignment = HorizontalAlignment.Left;
- if(index == 3)
- {
- userItem.ImageState = "1";
- }
- //设置位置---------------------------------
- userItem.Margin = new Thickness(centerX - 135, centerY - 540, 0, 0);
+ userItem.ImageState = "1";
+ userItem.Margin = new Thickness(centerX - (index == 0 ? 80 : index == 6 ? 190 : 135), centerY - 540, 0, 0);
userBox.Children.Add(userItem);
userList.Add(userItem);
return userItem; //
}
-
-
- public bool IsInsideCircle(double px, double py, double cx, double cy, double r)
- {
- double dx = px - cx;
- double dy = py - cy;
- return dx * dx + dy * dy <= r * r;
- }
}
}
diff --git a/Wpf_AiSportsMicrospace/Views/Main.xaml.cs b/Wpf_AiSportsMicrospace/Views/Main.xaml.cs
index 1c7998d..1798983 100644
--- a/Wpf_AiSportsMicrospace/Views/Main.xaml.cs
+++ b/Wpf_AiSportsMicrospace/Views/Main.xaml.cs
@@ -36,33 +36,29 @@ namespace Wpf_AiSportsMicrospace.Views
{
InitializeComponent();
- //var options = new InferenceOptions()
- //{
- // GpuEnabled = true
- //};
- //Yztob.AiSports.Common.SportAppSettingService.Set("inferences", options);
+ var options = new InferenceOptions()
+ {
+ GpuEnabled = true
+ };
+ Yztob.AiSports.Common.SportAppSettingService.Set("inferences", options);
_humanPredictor = HumanPredictorFactory.Create(HumanPredictorType.MultiLow);
_humanGraphicsRenderer = new HumanGraphicsRenderer();
_humanGraphicsRenderer.DrawLabel = false;
+ SportOperate = new SportOperate();
+ WebcamClient = SportOperate.CreateRTSP();
+
// 开始抽帧线程
StartFrameProcessing();
- //WebcamClient.OnExtractFrame += this.ProcessFrame;
- //WebcamClient.StartExtract();//开始抽帧
-
// 默认显示首页
MainContent.Content = new Home();
}
private void StartFrameProcessing()
{
- SportOperate = new SportOperate();
- WebcamClient = SportOperate.CreateRTSP();
-
WebcamClient.OnExtractFrame += frame =>
{
- //if (frame != null)
_frameQueue.Enqueue(frame);
};
@@ -79,16 +75,6 @@ namespace Wpf_AiSportsMicrospace.Views
else
{
// 避免 CPU 占满
- //Thread.Sleep(5);
- //if (frame == null)
- //{
- // WebcamClient.OnExtractFrame += frame =>
- // {
- // //if (frame != null)
- // _frameQueue.Enqueue(frame);
- // };
- //}
- //else
Thread.Sleep(5);
}
}
@@ -120,48 +106,6 @@ namespace Wpf_AiSportsMicrospace.Views
}
public event EventHandler> HumanFrameUpdated;
- //public void SwitchPage(UserControl newPage, bool fromRight)
- //{
- // if (MainContent.Content == newPage) return;
-
- // var oldPage = MainContent.Content as UserControl;
-
- // if (oldPage != null)
- // {
- // // 旧页面动画
- // var oldTransformGroup = new TransformGroup();
- // var oldScale = new ScaleTransform(1, 1);
- // var oldSkew = new SkewTransform(0, 0);
- // var oldTranslate = new TranslateTransform(0, 0);
- // oldTransformGroup.Children.Add(oldScale);
- // oldTransformGroup.Children.Add(oldSkew);
- // oldTransformGroup.Children.Add(oldTranslate);
- // oldPage.RenderTransformOrigin = new Point(fromRight ? 1 : 0, 0.5); // 左右翻页中心
- // oldPage.RenderTransform = oldTransformGroup;
-
- // var scaleAnim = new DoubleAnimation(1, 0.7, TimeSpan.FromMilliseconds(600)) { EasingFunction = new CubicEase { EasingMode = EasingMode.EaseInOut } };
- // var skewAnim = new DoubleAnimation(0, fromRight ? 45 : -45, TimeSpan.FromMilliseconds(600)) { EasingFunction = new CubicEase { EasingMode = EasingMode.EaseInOut } };
- // var fadeAnim = new DoubleAnimation(1, 0.2, TimeSpan.FromMilliseconds(600));
- // var translateAnim = new DoubleAnimation(0, fromRight ? -ActualWidth : ActualWidth, TimeSpan.FromMilliseconds(600)) { EasingFunction = new CubicEase { EasingMode = EasingMode.EaseInOut } };
-
- // oldScale.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnim);
- // oldScale.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnim);
- // oldSkew.BeginAnimation(SkewTransform.AngleYProperty, skewAnim);
- // oldTranslate.BeginAnimation(TranslateTransform.XProperty, translateAnim);
- // oldPage.BeginAnimation(OpacityProperty, fadeAnim);
-
- // fadeAnim.Completed += (s, e) =>
- // {
- // MainContent.Content = newPage;
- // AnimateNewPageEnhanced(newPage, fromRight);
- // };
- // }
- // else
- // {
- // MainContent.Content = newPage;
- // AnimateNewPageEnhanced(newPage, fromRight);
- // }
- //}
public void SwitchPage(UserControl newPage, bool fromRight)
{
@@ -183,89 +127,6 @@ namespace Wpf_AiSportsMicrospace.Views
// 清理资源
if (oldPage is IDisposable disposable)
disposable.Dispose();
-
- //container.Children.Clear();
-
- //if (oldPage != null)
- //{
- // MainContent.Content = null;
- // // 创建容器同时显示新旧页面
- // var container = new Grid();
- // container.Children.Add(newPage); // 新页面在底层
- // container.Children.Add(oldPage); // 旧页面在顶层
-
- // MainContent.Content = container;
-
- // // 设置新页面初始状态 - 轻微缩放和偏移
- // var newTransformGroup = new TransformGroup();
- // var newScale = new ScaleTransform(0.95, 0.95);
- // var newTranslate = new TranslateTransform(fromRight ? 80 : -80, 0);
- // newTransformGroup.Children.Add(newScale);
- // newTransformGroup.Children.Add(newTranslate);
- // newPage.RenderTransformOrigin = new Point(0.5, 0.5);
- // newPage.RenderTransform = newTransformGroup;
- // newPage.Opacity = 1;
-
- // // 旧页面动画 - 飞出效果
- // var oldTransformGroup = new TransformGroup();
- // var oldScale = new ScaleTransform(1, 1);
- // var oldSkew = new SkewTransform(0, 0);
- // var oldTranslate = new TranslateTransform(0, 0);
- // oldTransformGroup.Children.Add(oldScale);
- // oldTransformGroup.Children.Add(oldSkew);
- // oldTransformGroup.Children.Add(oldTranslate);
- // oldPage.RenderTransformOrigin = new Point(fromRight ? 1 : 0, 0.5);
- // oldPage.RenderTransform = oldTransformGroup;
- // oldPage.Opacity = 1;
-
- // // 动画参数
- // var duration = TimeSpan.FromMilliseconds(1200);
- // var easing = new CubicEase { EasingMode = EasingMode.EaseInOut };
-
- // // 旧页面飞出动画
- // var oldScaleAnim = new DoubleAnimation(1, 1.1, duration) { EasingFunction = easing };
- // var oldSkewAnim = new DoubleAnimation(0, fromRight ? 15 : -15, duration) { EasingFunction = easing };
- // var oldTranslateAnim = new DoubleAnimation(0, fromRight ? ActualWidth * 1.1 : -ActualWidth * 1.1, duration)
- // {
- // EasingFunction = easing
- // };
-
- // // 新页面进入动画
- // var newScaleAnim = new DoubleAnimation(0.8, 1, duration) { EasingFunction = easing };
- // var newTranslateAnim = new DoubleAnimation(fromRight ? -80 : -80, 0, duration) { EasingFunction = easing };
-
- // // 开始动画
- // oldScale.BeginAnimation(ScaleTransform.ScaleXProperty, oldScaleAnim);
- // oldScale.BeginAnimation(ScaleTransform.ScaleYProperty, oldScaleAnim);
- // oldSkew.BeginAnimation(SkewTransform.AngleYProperty, oldSkewAnim);
- // oldTranslate.BeginAnimation(TranslateTransform.XProperty, oldTranslateAnim);
-
- // newScale.BeginAnimation(ScaleTransform.ScaleXProperty, newScaleAnim);
- // newScale.BeginAnimation(ScaleTransform.ScaleYProperty, newScaleAnim);
- // newTranslate.BeginAnimation(TranslateTransform.XProperty, newTranslateAnim);
-
- // // 动画完成后清理
- // oldTranslateAnim.Completed += (s, e) =>
- // {
- // // 确保最终状态
- // newPage.RenderTransform = null;
- // newPage.Opacity = 1;
-
- // // 切换到只有新页面
- // MainContent.Content = newPage;
-
- // // 清理资源
- // if (oldPage is IDisposable disposable)
- // disposable.Dispose();
-
- // container.Children.Clear();
- // };
- //}
- //else
- //{
- // MainContent.Content = newPage;
- // newPage.Opacity = 1;
- //}
}
private void PreloadPageResources(UserControl page)