From 2a24d26ce467fde82e113eefe7d1f1cab9bb7e38 Mon Sep 17 00:00:00 2001 From: tanglong <842690096@qq.com> Date: Sun, 28 Sep 2025 09:17:44 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=BE=E6=89=8B=E5=8A=A8=E7=94=BB=E8=AF=86?= =?UTF-8?q?=E5=88=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Wpf_AiSportsMicrospace/Common/SportOperate.cs | 16 +- Wpf_AiSportsMicrospace/Home.xaml.cs | 8 +- .../MyUserControl/CoverFlowControl.xaml.cs | 232 +++++++++--------- .../Wpf_AiSportsMicrospace.csproj | 12 + 4 files changed, 138 insertions(+), 130 deletions(-) diff --git a/Wpf_AiSportsMicrospace/Common/SportOperate.cs b/Wpf_AiSportsMicrospace/Common/SportOperate.cs index 5ace40a..1e2e3b8 100644 --- a/Wpf_AiSportsMicrospace/Common/SportOperate.cs +++ b/Wpf_AiSportsMicrospace/Common/SportOperate.cs @@ -43,10 +43,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() @@ -94,7 +94,7 @@ namespace Wpf_AiSportsMicrospace.Common double dy = Math.Abs(wrist.Y - lastWrist.Value.Y); // 挥手:水平位移明显,垂直位移小,且接近肘部水平 - if (Math.Abs(dx) > 30 && dy < 40 && Math.Abs(wrist.Y - elbow.Y) < 100) + if (Math.Abs(dx) > 30 && dy < 40 && Math.Abs(wrist.Y - elbow.Y) < 150) { if (CheckCooldown()) { @@ -135,7 +135,7 @@ namespace Wpf_AiSportsMicrospace.Common // --- 举手逻辑 --- double verticalRise = elbow.Y - wrist.Y; // 手腕在肘上方 → 正值 - if (verticalRise > 100) // 举手阈值 + if (verticalRise > 60) // 举手阈值 { // 初始化计时 if (_raiseStartTime == null) @@ -155,7 +155,7 @@ namespace Wpf_AiSportsMicrospace.Common // 判断是否完成3秒举手 var duration = DateTime.Now - _raiseStartTime.Value; - if (duration.TotalSeconds >= 4) + if (duration.TotalSeconds >= 3) { _raiseStartTime = null; _wristStartTime = null; @@ -181,7 +181,7 @@ namespace Wpf_AiSportsMicrospace.Common /// /// 冷却防抖(避免重复触发) /// - private bool CheckCooldown(int cooldownMs = 1000) + private bool CheckCooldown(int cooldownMs = 800) { if ((DateTime.Now - _lastActionTime).TotalMilliseconds < cooldownMs) return false; diff --git a/Wpf_AiSportsMicrospace/Home.xaml.cs b/Wpf_AiSportsMicrospace/Home.xaml.cs index d1a59ab..f605763 100644 --- a/Wpf_AiSportsMicrospace/Home.xaml.cs +++ b/Wpf_AiSportsMicrospace/Home.xaml.cs @@ -77,7 +77,7 @@ namespace Wpf_AiSportsMicrospace _webcamClient.StartExtract(); StartFrameProcessing(); - coverFlow.ProgressCompleted += CoverFlow_ProgressCompleted; + //coverFlow.ProgressCompleted += CoverFlow_ProgressCompleted; } private void CoverFlow_ProgressCompleted(CoverFlowItem item) @@ -140,9 +140,8 @@ namespace Wpf_AiSportsMicrospace //}; //_webcamClient.StartExtract(); - _webcamClient.StartExtract(); - Thread.Sleep(5); + //Thread.Sleep(5); } } }, _cts.Token); @@ -195,7 +194,8 @@ namespace Wpf_AiSportsMicrospace break; case (int)WavingAction.RaiseHand: // 举手完成 - _cts.Cancel(); + coverFlow.ProgressCompleted += CoverFlow_ProgressCompleted; + // _cts.Cancel(); break; default: // 没有动作 → 取消进度 diff --git a/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl.xaml.cs b/Wpf_AiSportsMicrospace/MyUserControl/CoverFlowControl.xaml.cs index ca4ad04..366d67b 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,82 @@ 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 +191,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 +204,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 +213,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 +268,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/Wpf_AiSportsMicrospace.csproj b/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj index a9b1f33..7fc3af0 100644 --- a/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj +++ b/Wpf_AiSportsMicrospace/Wpf_AiSportsMicrospace.csproj @@ -15,7 +15,10 @@ + + + @@ -97,9 +100,18 @@ Always + + Always + Always + + Always + + + Always + Always