diff --git a/Wpf_AiSportsMicrospace/App.xaml b/Wpf_AiSportsMicrospace/App.xaml index bb7194e..726f59f 100644 --- a/Wpf_AiSportsMicrospace/App.xaml +++ b/Wpf_AiSportsMicrospace/App.xaml @@ -1,8 +1,8 @@  + xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.Views" + StartupUri="Views/Main.xaml"> diff --git a/Wpf_AiSportsMicrospace/Common/SportOperate.cs b/Wpf_AiSportsMicrospace/Common/SportOperate.cs index 5ace40a..65f2ff9 100644 --- a/Wpf_AiSportsMicrospace/Common/SportOperate.cs +++ b/Wpf_AiSportsMicrospace/Common/SportOperate.cs @@ -34,6 +34,9 @@ namespace Wpf_AiSportsMicrospace.Common private Point? _lastRightWrist = null; private DateTime? _raiseStartTime = null; private DateTime? _wristStartTime = null; + private double _leftWristDeltaX = 0; + private double _rightWristDeltaX = 0; + private bool _firstHandTriggered = false; public SportOperate() @@ -43,10 +46,10 @@ namespace Wpf_AiSportsMicrospace.Common _leftElbow = PostureCalculate.CreatePointTracker("left_elbow", 0); _rightElbow = PostureCalculate.CreatePointTracker("right_elbow", 0); - //_leftTracker.Amplitude = 0.05f; - //_rightTracker.Amplitude = 0.05f; - //_leftElbow.Amplitude = 0.05f; - //_rightElbow.Amplitude = 0.05f; + //_leftTracker.Amplitude = 0.03f; + //_rightTracker.Amplitude = 0.03f; + //_leftElbow.Amplitude = 0.03f; + //_rightElbow.Amplitude = 0.03f; } public WebcamClient CreateRTSP() @@ -62,119 +65,98 @@ namespace Wpf_AiSportsMicrospace.Common var rightWrist = human.Keypoints.FirstOrDefault(x => x.Name == "right_wrist"); var rightElbow = human.Keypoints.FirstOrDefault(x => x.Name == "right_elbow"); - // 左手逻辑 + // --- 左手挥手 --- if (leftWrist != null && leftElbow != null) { - var result = RecognizeLeftHandGesture( + int leftResult = DetectHorizontalWave( new Point(leftWrist.X, leftWrist.Y), - new Point(leftElbow.X, leftElbow.Y)); - if (result != 0) return result; + new Point(leftElbow.X, leftElbow.Y), + ref _lastLeftWrist, + ref _leftWristDeltaX, + true); + if (leftResult != (int)WavingAction.None) return leftResult; } - // 右手逻辑 + // --- 右手挥手或举手 --- if (rightWrist != null && rightElbow != null) { - var result = RecognizeRightHandGesture( + int rightWaveResult = DetectHorizontalWave( new Point(rightWrist.X, rightWrist.Y), - new Point(rightElbow.X, rightElbow.Y)); - if (result != 0) return result; - } + new Point(rightElbow.X, rightElbow.Y), + ref _lastRightWrist, + ref _rightWristDeltaX, + false); + if (rightWaveResult != (int)WavingAction.None) return rightWaveResult; - return 0; - } - - /// - /// 统一的水平挥手检测 - /// - private int DetectHorizontalWave(Point wrist, Point elbow, Point? lastWrist, bool isLeft) - { - if (lastWrist != null) - { - double dx = wrist.X - lastWrist.Value.X; - double dy = Math.Abs(wrist.Y - lastWrist.Value.Y); - - // 挥手:水平位移明显,垂直位移小,且接近肘部水平 - if (Math.Abs(dx) > 30 && dy < 40 && Math.Abs(wrist.Y - elbow.Y) < 100) + // --- 举手逻辑 --- + double verticalRise = rightElbow.Y - rightWrist.Y; // 手腕在肘上方 → 正值 + if (verticalRise >= 60) // 举手阈值 { - if (CheckCooldown()) + // 初始化计时 + if (_raiseStartTime == null) + _raiseStartTime = DateTime.Now; + + if (_wristStartTime == null) + _wristStartTime = DateTime.Now; + + var wristDuration = DateTime.Now - _wristStartTime.Value; + + // 保持 >1 秒才触发一次 FirstHand + if (!_firstHandTriggered && wristDuration.TotalSeconds >= 1) { - if (isLeft && dx > 0) - return (int)WavingAction.LeftWave; // 左手往右挥 - if (!isLeft && dx < 0) - return (int)WavingAction.RightWave; // 右手往左挥 + _firstHandTriggered = true; + return (int)WavingAction.FirstHand; // 举手开始,只触发一次 } + + // 判断是否完成3秒举手 + var duration = DateTime.Now - _raiseStartTime.Value; + if (duration.TotalSeconds >= 3) + { + _raiseStartTime = null; + _wristStartTime = null; + _firstHandTriggered = false; // 重置状态 + return (int)WavingAction.RaiseHand; // 举手完成 + } + else + { + return (int)WavingAction.Raising; // 举手中 + } + } + else + { + // 手放下,重置计时和状态 + _raiseStartTime = null; + _wristStartTime = null; + _firstHandTriggered = false; } } return (int)WavingAction.None; } /// - /// 识别左手动作 + /// 统一的水平挥手检测 /// - public int RecognizeLeftHandGesture(Point wrist, Point elbow) + private int DetectHorizontalWave(Point wrist, Point elbow, ref Point? lastWrist, ref double deltaX, bool isLeft) { - int result = DetectHorizontalWave(wrist, elbow, _lastLeftWrist, true); - _lastLeftWrist = wrist; // 更新记录 - return result; - } - private bool _firstHandTriggered = false; - - /// - /// 识别右手动作 - /// - /// - /// - /// - public int RecognizeRightHandGesture(Point wrist, Point elbow) - { - // --- 先判断水平挥手 --- - int waveResult = DetectHorizontalWave(wrist, elbow, _lastRightWrist, false); - _lastRightWrist = wrist; // 更新记录 - if (waveResult != (int)WavingAction.None) - return waveResult; - - // --- 举手逻辑 --- - double verticalRise = elbow.Y - wrist.Y; // 手腕在肘上方 → 正值 - if (verticalRise > 100) // 举手阈值 + if (lastWrist != null) { - // 初始化计时 - if (_raiseStartTime == null) - _raiseStartTime = DateTime.Now; + double dx = wrist.X - lastWrist.Value.X; + double dy = Math.Abs(wrist.Y - lastWrist.Value.Y); - if (_wristStartTime == null) - _wristStartTime = DateTime.Now; + // 累计水平位移 + deltaX += dx; - var wristDuration = DateTime.Now - _wristStartTime.Value; - - // 保持 >1 秒才触发一次 FirstHand - if (!_firstHandTriggered && wristDuration.TotalSeconds >= 1) + if (Math.Abs(deltaX) > 40 && dy < 60 && Math.Abs(wrist.Y - elbow.Y) < 60) { - _firstHandTriggered = true; - return (int)WavingAction.FirstHand; // 举手开始,只触发一次 - } - - // 判断是否完成3秒举手 - var duration = DateTime.Now - _raiseStartTime.Value; - if (duration.TotalSeconds >= 4) - { - _raiseStartTime = null; - _wristStartTime = null; - _firstHandTriggered = false; // 重置状态 - return (int)WavingAction.RaiseHand; // 举手完成 - } - else - { - return (int)WavingAction.Raising; // 举手中 + deltaX = 0; // 重置 + if (CheckCooldown()) + { + return isLeft ? (int)WavingAction.LeftWave : (int)WavingAction.RightWave; + } } } - else - { - // 手放下,重置计时和状态 - _raiseStartTime = null; - _wristStartTime = null; - _firstHandTriggered = false; - } + lastWrist = wrist; return (int)WavingAction.None; } @@ -189,5 +171,8 @@ namespace Wpf_AiSportsMicrospace.Common _lastActionTime = DateTime.Now; return true; } + + + } } diff --git a/Wpf_AiSportsMicrospace/Common/Utils.cs b/Wpf_AiSportsMicrospace/Common/Utils.cs new file mode 100644 index 0000000..f316c35 --- /dev/null +++ b/Wpf_AiSportsMicrospace/Common/Utils.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media; + +namespace Wpf_AiSportsMicrospace.Common +{ + public static class Utils + { + private static MediaPlayer _bgPlayer; + public static void PlayBackgroundMusic(string musicFileName) + { + string projectRoot = Path.Combine(AppContext.BaseDirectory, @"..\..\.."); + string musicPath = Path.Combine(projectRoot, "Resources", "Music", musicFileName); + + if (_bgPlayer == null) + { + _bgPlayer = new MediaPlayer(); + _bgPlayer.Volume = 0.5; + _bgPlayer.MediaEnded += (s, e) => + { + _bgPlayer.Position = TimeSpan.Zero; // 循环播放 + _bgPlayer.Play(); + }; + } + else + { + _bgPlayer.Stop(); + } + + _bgPlayer.Open(new Uri(musicPath, UriKind.Absolute)); + _bgPlayer.Play(); + } + public static void StopBackgroundMusic() + { + if (_bgPlayer != null) + { + _bgPlayer.Stop(); + //_bgPlayer.Close(); // 如果想释放资源,可以取消注释 + } + } + } +} diff --git a/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl.xaml.cs b/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl.xaml.cs index ca4ad04..e79269c 100644 --- a/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl.xaml.cs +++ b/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl.xaml.cs @@ -24,31 +24,11 @@ namespace Wpf_AiSportsMicrospace.MyUserControl /// CoverFlowControl.xaml 的交互逻辑 /// public partial class CoverFlowControl : UserControl - { - //public ObservableCollection Images { get; set; } = new ObservableCollection(); - public ObservableCollection Images { get; set; } = new ObservableCollection(); - - // 新增事件:进度条完成 + {// 新增事件:进度条完成 public event Action ProgressCompleted; - - // 添加附加属性帮助类 - public static class LayoutHelper - { - public static int GetZIndex(DependencyObject obj) - { - return (int)obj.GetValue(ZIndexProperty); - } - - public static void SetZIndex(DependencyObject obj, int value) - { - obj.SetValue(ZIndexProperty, value); - } - - public static readonly DependencyProperty ZIndexProperty = - DependencyProperty.RegisterAttached("ZIndex", typeof(int), typeof(LayoutHelper), new PropertyMetadata(0)); - } - + public ObservableCollection Images { get; set; } = new ObservableCollection(); private int _selectedIndex = 0; + public int SelectedIndex { get => _selectedIndex; @@ -59,25 +39,9 @@ namespace Wpf_AiSportsMicrospace.MyUserControl if (value < 0) _selectedIndex = Images.Count - 1; else if (value >= Images.Count) _selectedIndex = 0; else _selectedIndex = value; - for (int i = 0; i < Images.Count; i++) - { Images[i].IsSelected = i == _selectedIndex; - //if (SelectedIndex == 0) - //{ - // Images[i].ProgressColor = (Brush)new BrushConverter().ConvertFromString("#e73d42")!; - //} - //else if (SelectedIndex == Images.Count - 1) - //{ - // Images[i].ProgressColor = (Brush)new BrushConverter().ConvertFromString("#215bc7")!; - //} - //else - //{ - // Images[i].ProgressColor = (Brush)new BrushConverter().ConvertFromString("#fc640e")!; - //} - } - UpdateLayoutWithAnimation(); @@ -85,44 +49,32 @@ namespace Wpf_AiSportsMicrospace.MyUserControl //var current = Images[_selectedIndex]; //StartProgress(current); } + } + public CoverFlowControl() + { + InitializeComponent(); + DataContext = this; + Loaded += (s, e) => UpdateLayoutWithAnimation(true); + + //var timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(5) }; + //timer.Tick += (s, e) => + //{ + // if (Images.Count == 0) return; + // var current = Images[_selectedIndex]; + // if (current.Progress < 1) + // current.Progress += 0.01; // 调整速度 + //}; + //timer.Start(); + } private EventHandler _renderHandler; private CoverFlowItem _currentItem; - private void StartProgress(CoverFlowItem item) - { - StopProgress(); - - _currentItem = item; - _currentItem.Progress = 0; - - _renderHandler = (s, e) => - { - if (_currentItem.Progress < 1) - { - _currentItem.Progress += 1.0 / (3 * 60.0); // 3秒完成一圈,假设60帧/s - if (_currentItem.Progress > 1) _currentItem.Progress = 1; - } - else - { - StopProgress(); - } - }; - - CompositionTarget.Rendering += _renderHandler; - } - - private void StopProgress() - { - if (_renderHandler != null) - { - CompositionTarget.Rendering -= _renderHandler; - _renderHandler = null; - } - } - + /// + /// 针对当前选中项启动进度条动画 + /// public void StartSelectedProgress() { if (SelectedIndex >= 0 && SelectedIndex < Images.Count) @@ -145,23 +97,83 @@ namespace Wpf_AiSportsMicrospace.MyUserControl current.Progress = 0; } } - - public CoverFlowControl() + public void StartProgress(CoverFlowItem item) { + StopProgress(); - InitializeComponent(); - DataContext = this; - Loaded += (s, e) => UpdateLayoutWithAnimation(true); + _currentItem = item; + item.Progress = 0; - //var timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(5) }; - //timer.Tick += (s, e) => - //{ - // if (Images.Count == 0) return; - // var current = Images[_selectedIndex]; - // if (current.Progress < 1) - // current.Progress += 0.01; // 调整速度 - //}; - //timer.Start(); + var container = ItemsHost.ItemContainerGenerator.ContainerFromItem(item) as ContentPresenter; + if (container == null) return; + + var canvas = FindVisualChild(container); + var spark = FindVisualChild(canvas); + if (spark != null) + spark.Visibility = Visibility.Visible; + + _renderHandler = (s, e) => + { + if (_currentItem.Progress < 1) + { + _currentItem.Progress += 0.00556; // 控制速度 + if (spark != null) + { + var pos = GetSparkPosition(_currentItem.Progress, 150, 200); + Canvas.SetLeft(spark, pos.X - spark.Width / 2); + Canvas.SetTop(spark, pos.Y - spark.Height / 2); + } + } + else + { + ProgressCompleted?.Invoke(_currentItem); + // 停止动画 + StopProgress(); + } + }; + + CompositionTarget.Rendering += _renderHandler; + } + + private void StopProgress() + + { + if (_renderHandler != null) + { + CompositionTarget.Rendering -= _renderHandler; + _renderHandler = null; + } + + if (_currentItem != null) + { + _currentItem.Progress = 0; + //_currentItem.IsSelected = true; + + var container = ItemsHost.ItemContainerGenerator.ContainerFromItem(_currentItem) as ContentPresenter; + if (container != null) + { + var canvas = FindVisualChild(container); + var spark = FindVisualChild(canvas); + if (spark != null) + spark.Visibility = Visibility.Collapsed; + } + + _currentItem = null; + } + } + + private Point GetSparkPosition(double progress, double width, double height) + { + double perimeter = 2 * (width + height); + double len = progress * perimeter; + + if (len <= width) return new Point(len, 0); // 上边 + len -= width; + if (len <= height) return new Point(width, len); // 右边 + len -= height; + if (len <= width) return new Point(width - len, height); // 下边 + len -= width; + return new Point(0, height - len); // 左边 } private void Image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) @@ -180,9 +192,9 @@ namespace Wpf_AiSportsMicrospace.MyUserControl private void UpdateLayoutWithAnimation(bool instant = false) { double centerX = ActualWidth / 2; - double spacing = 500; - double sideScale = 1; - double centerScale = 1.33; + double spacing = 550; + double sideScale = 0.93; + double centerScale = 1.43; for (int i = 0; i < ItemsHost.Items.Count; i++) { @@ -193,7 +205,7 @@ namespace Wpf_AiSportsMicrospace.MyUserControl if (border == null) continue; var transformGroup = border.RenderTransform as TransformGroup; - var scale = transformGroup!.Children[0] as ScaleTransform; + var scale = transformGroup.Children[0] as ScaleTransform; var translate = transformGroup.Children[1] as TranslateTransform; double targetX; @@ -202,67 +214,52 @@ namespace Wpf_AiSportsMicrospace.MyUserControl if (i == SelectedIndex) { - targetX = centerX - 190; + targetX = centerX - 75; targetScale = centerScale; targetOpacity = 1.0; } else if (i == SelectedIndex - 1 || (SelectedIndex == 0 && i == Images.Count - 1)) { - // 左边图片,循环处理 - targetX = centerX - spacing - 190; + targetX = centerX - spacing - 75; targetScale = sideScale; targetOpacity = 1.0; } else if (i == SelectedIndex + 1 || (SelectedIndex == Images.Count - 1 && i == 0)) { - // 右边图片,循环处理 - targetX = centerX + spacing - 190; + targetX = centerX + spacing - 75; targetScale = sideScale; targetOpacity = 1.0; } else { - targetX = centerX - 190; + targetX = centerX - 75; targetScale = sideScale; targetOpacity = 0.0; } if (instant) { - translate!.X = targetX; - scale!.ScaleX = scale.ScaleY = targetScale; + translate.X = targetX; + scale.ScaleX = scale.ScaleY = targetScale; border.Opacity = targetOpacity; } else { - translate!.BeginAnimation(TranslateTransform.XProperty, + translate.BeginAnimation(TranslateTransform.XProperty, new DoubleAnimation(targetX, TimeSpan.FromMilliseconds(400)) { EasingFunction = new QuadraticEase() }); - scale!.BeginAnimation(ScaleTransform.ScaleXProperty, + scale.BeginAnimation(ScaleTransform.ScaleXProperty, new DoubleAnimation(targetScale, TimeSpan.FromMilliseconds(400)) { EasingFunction = new QuadraticEase() }); scale.BeginAnimation(ScaleTransform.ScaleYProperty, new DoubleAnimation(targetScale, TimeSpan.FromMilliseconds(400)) { EasingFunction = new QuadraticEase() }); border.BeginAnimation(Border.OpacityProperty, new DoubleAnimation(targetOpacity, TimeSpan.FromMilliseconds(400))); } - - var item = Images[i]; - - if (i == SelectedIndex) - { - item.IsSelected = true; - StartProgress(item); - } - else - { - item.IsSelected = false; - item.Progress = 0; - } - } } private static T FindVisualChild(DependencyObject obj) where T : DependencyObject { + if (obj == null) return null; for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) { var child = VisualTreeHelper.GetChild(obj, i); @@ -272,17 +269,17 @@ namespace Wpf_AiSportsMicrospace.MyUserControl } return null; } - - // 外部调用:左滑(下一张) + + public void SlideLeft() { + StopProgress(); SelectedIndex++; } - - // 外部调用:右滑(上一张) public void SlideRight() { + StopProgress(); SelectedIndex--; } } -} +} \ No newline at end of file diff --git a/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl1.xaml.cs b/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl1.xaml.cs index 8ea9af2..ca668aa 100644 --- a/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl1.xaml.cs +++ b/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl1.xaml.cs @@ -1,4 +1,4 @@ -using _3DTools; + using System; using System.Collections.Generic; using System.Collections.ObjectModel; diff --git a/Wpf_AiSportsMicrospace/Resources/Img/gif/1.gif b/Wpf_AiSportsMicrospace/Resources/Img/gif/1.gif new file mode 100644 index 0000000..fa54d10 Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Img/gif/1.gif differ diff --git a/Wpf_AiSportsMicrospace/Resources/Img/gif/2.gif b/Wpf_AiSportsMicrospace/Resources/Img/gif/2.gif new file mode 100644 index 0000000..e514ee7 Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Img/gif/2.gif differ diff --git a/Wpf_AiSportsMicrospace/Resources/Img/gif/3.gif b/Wpf_AiSportsMicrospace/Resources/Img/gif/3.gif new file mode 100644 index 0000000..22f0150 Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Img/gif/3.gif differ diff --git a/Wpf_AiSportsMicrospace/Resources/Music/homeprojectselected.mp3 b/Wpf_AiSportsMicrospace/Resources/Music/homeprojectselected.mp3 new file mode 100644 index 0000000..65b067b Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Music/homeprojectselected.mp3 differ diff --git a/Wpf_AiSportsMicrospace/Resources/Music/homeprojectselected1.mp3 b/Wpf_AiSportsMicrospace/Resources/Music/homeprojectselected1.mp3 new file mode 100644 index 0000000..0aae4ae Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Music/homeprojectselected1.mp3 differ diff --git a/Wpf_AiSportsMicrospace/Resources/Music/musicjumprope.mp3 b/Wpf_AiSportsMicrospace/Resources/Music/musicjumprope.mp3 new file mode 100644 index 0000000..2b40a48 Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Music/musicjumprope.mp3 differ diff --git a/Wpf_AiSportsMicrospace/Resources/Music/musicjumprope1.mp3 b/Wpf_AiSportsMicrospace/Resources/Music/musicjumprope1.mp3 new file mode 100644 index 0000000..0aae4ae Binary files /dev/null and b/Wpf_AiSportsMicrospace/Resources/Music/musicjumprope1.mp3 differ diff --git a/Wpf_AiSportsMicrospace/Home.xaml b/Wpf_AiSportsMicrospace/Views/Home.xaml similarity index 97% rename from Wpf_AiSportsMicrospace/Home.xaml rename to Wpf_AiSportsMicrospace/Views/Home.xaml index d2b97a7..d672e03 100644 --- a/Wpf_AiSportsMicrospace/Home.xaml +++ b/Wpf_AiSportsMicrospace/Views/Home.xaml @@ -1,4 +1,4 @@ - - + diff --git a/Wpf_AiSportsMicrospace/Home.xaml.cs b/Wpf_AiSportsMicrospace/Views/Home.xaml.cs similarity index 85% rename from Wpf_AiSportsMicrospace/Home.xaml.cs rename to Wpf_AiSportsMicrospace/Views/Home.xaml.cs index c4ac7b8..a451699 100644 --- a/Wpf_AiSportsMicrospace/Home.xaml.cs +++ b/Wpf_AiSportsMicrospace/Views/Home.xaml.cs @@ -29,8 +29,7 @@ namespace Wpf_AiSportsMicrospace /// /// Home.xaml 的交互逻辑 /// - /// - public partial class Home : Window + public partial class Home : UserControl { private IHumanPredictor _humanPredictor; private WebcamClient _webcamClient; @@ -58,7 +57,7 @@ namespace Wpf_AiSportsMicrospace //coverFlow.Images.Add(new Uri(Path.Combine(albumPath, "4.jpg"))); //coverFlow.Images.Add(new Uri(Path.Combine(albumPath, "5.jpg"))); - coverFlow.Images.Add(new CoverFlowItem { ImageUri = new Uri(Path.Combine(albumPath, "home_test.png")) , ProgressColor1 = "#215bc7" , ProgressColor2 = "#fc640e" }); + coverFlow.Images.Add(new CoverFlowItem { ImageUri = new Uri(Path.Combine(albumPath, "home_test.png")), ProgressColor1 = "#215bc7", ProgressColor2 = "#fc640e" }); coverFlow.Images.Add(new CoverFlowItem { ImageUri = new Uri(Path.Combine(albumPath, "home_play.png")), ProgressColor1 = "#e73d42", ProgressColor2 = "#fd8212" }); coverFlow.Images.Add(new CoverFlowItem { ImageUri = new Uri(Path.Combine(albumPath, "home_history.png")), ProgressColor1 = "#e73d42", ProgressColor2 = "#215bc7" }); @@ -81,10 +80,12 @@ namespace Wpf_AiSportsMicrospace //}; //_webcamClient.StartExtract(); - //StartFrameProcessing(); + StartFrameProcessing(); + + Utils.PlayBackgroundMusic("homeprojectselected.mp3"); + //coverFlow.ProgressCompleted += CoverFlow_ProgressCompleted; } - private void CoverFlow_ProgressCompleted(CoverFlowItem item) { // 停止抽帧线程/释放资源 @@ -105,22 +106,20 @@ namespace Wpf_AiSportsMicrospace // 根据图片跳转新窗口 string uri = item.ImageUri.ToString(); - Window newWindow = null; - 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(); + //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 - if (newWindow != null) + var mainWin = Application.Current.MainWindow as Main; + if (mainWin != null) { - Dispatcher.BeginInvoke(() => - { - newWindow.Show(); // 先显示新窗口 - this.Close(); // 再关闭当前窗口 - }); + Utils.PlayBackgroundMusic("musicjumprope1.mp3"); + mainWin.SwitchPage(new GroupJumpRope(), true); } } @@ -143,9 +142,8 @@ namespace Wpf_AiSportsMicrospace //}; //_webcamClient.StartExtract(); - _webcamClient.StartExtract(); - Thread.Sleep(5); + //Thread.Sleep(5); } } }, _cts.Token); @@ -177,10 +175,10 @@ namespace Wpf_AiSportsMicrospace var wavingaction = _sportOperate.VerifyWavingAction(human); // 把低 8 位作为动作类型,高 8 位作为进度 - int actionType = wavingaction & 0xFF; - int progress = (wavingaction >> 8) & 0xFF; + //int actionType = wavingaction & 0xFF; + //int progress = (wavingaction >> 8) & 0xFF; - switch (actionType) + switch (wavingaction) { case (int)WavingAction.LeftWave: // 左手挥动 Dispatcher.BeginInvoke(() => coverFlow.SlideRight()); @@ -199,6 +197,7 @@ namespace Wpf_AiSportsMicrospace case (int)WavingAction.RaiseHand: // 举手完成 _cts.Cancel(); + coverFlow.ProgressCompleted += CoverFlow_ProgressCompleted; break; default: // 没有动作 → 取消进度 @@ -212,5 +211,9 @@ namespace Wpf_AiSportsMicrospace } } + public void Dispose() + { + throw new NotImplementedException(); + } } } diff --git a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml index 26ba7e6..56423cc 100644 --- a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml +++ b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml @@ -1,12 +1,24 @@ - - - + mc:Ignorable="d" Height="500" Width="800"> + + + + + + + + + - + diff --git a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs index e26ef5a..e8da202 100644 --- a/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs +++ b/Wpf_AiSportsMicrospace/Views/JumpRope/GroupJumpRope.xaml.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -10,18 +11,27 @@ using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; -using System.Windows.Shapes; +using Wpf_AiSportsMicrospace.Common; +using WpfAnimatedGif; namespace Wpf_AiSportsMicrospace.Views { /// /// GroupJumpRope.xaml 的交互逻辑 /// - public partial class GroupJumpRope : Window + public partial class GroupJumpRope : UserControl { public GroupJumpRope() { InitializeComponent(); + + var image = new BitmapImage(); + image.BeginInit(); + image.UriSource = new Uri("../../Resources/Img/gif/1.gif", UriKind.Relative); // 替换成你的 GIF 路径 + image.EndInit(); + + // 设置动画源 + ImageBehavior.SetAnimatedSource(GifImage, image); } } } diff --git a/Wpf_AiSportsMicrospace/Views/Main.xaml b/Wpf_AiSportsMicrospace/Views/Main.xaml new file mode 100644 index 0000000..64bcb66 --- /dev/null +++ b/Wpf_AiSportsMicrospace/Views/Main.xaml @@ -0,0 +1,12 @@ + + + + + + diff --git a/Wpf_AiSportsMicrospace/Views/Main.xaml.cs b/Wpf_AiSportsMicrospace/Views/Main.xaml.cs new file mode 100644 index 0000000..0ead876 --- /dev/null +++ b/Wpf_AiSportsMicrospace/Views/Main.xaml.cs @@ -0,0 +1,98 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.Windows.Media.Imaging; +using System.Windows.Media.Media3D; + +namespace Wpf_AiSportsMicrospace.Views +{ + /// + /// Main.xaml 的交互逻辑 + /// + public partial class Main : Window + { + public Main() + { + InitializeComponent(); + + // 默认显示首页 + MainContent.Content = new Home(); + } + 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); + } + } + + private void AnimateNewPageEnhanced(UserControl newPage, bool fromRight) + { + var transformGroup = new TransformGroup(); + var scale = new ScaleTransform(0.7, 0.7); + var skew = new SkewTransform(fromRight ? -45 : 45, 0); + var translate = new TranslateTransform(fromRight ? ActualWidth : -ActualWidth, 0); + transformGroup.Children.Add(scale); + transformGroup.Children.Add(skew); + transformGroup.Children.Add(translate); + newPage.RenderTransformOrigin = new Point(fromRight ? 0 : 1, 0.5); + newPage.RenderTransform = transformGroup; + + // 动画 + var scaleAnim = new DoubleAnimation(0.7, 1, TimeSpan.FromMilliseconds(600)) { EasingFunction = new CubicEase { EasingMode = EasingMode.EaseInOut } }; + var skewAnim = new DoubleAnimation(fromRight ? -45 : 45, 0, TimeSpan.FromMilliseconds(600)) { EasingFunction = new CubicEase { EasingMode = EasingMode.EaseInOut } }; + var fadeAnim = new DoubleAnimation(0.2, 1, TimeSpan.FromMilliseconds(600)); + var translateAnim = new DoubleAnimation(fromRight ? ActualWidth : -ActualWidth, 0, TimeSpan.FromMilliseconds(600)) { EasingFunction = new CubicEase { EasingMode = EasingMode.EaseInOut } }; + + scale.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnim); + scale.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnim); + skew.BeginAnimation(SkewTransform.AngleYProperty, skewAnim); + translate.BeginAnimation(TranslateTransform.XProperty, translateAnim); + newPage.BeginAnimation(OpacityProperty, fadeAnim); + } + } +} \ No newline at end of file diff --git a/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj b/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj index b21fb99..7947066 100644 --- a/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj +++ b/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj @@ -35,10 +35,16 @@ + + + + + + + - @@ -155,6 +161,27 @@ Always + + Always + + + Always + + + Always + + + Always + + + Always + + + Always + + + Always +