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)