This commit is contained in:
tanglong 2025-10-12 10:20:08 +08:00
parent 8b6aa81e00
commit 589678b324
11 changed files with 411 additions and 181 deletions

View File

@ -2,7 +2,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.Views"
StartupUri="Views/Home.xaml">
StartupUri="Views/Main.xaml">
<!--StartupUri="Views/JumpRope/GroupJumpRope.xaml">-->
<Application.Resources>

View File

@ -16,9 +16,9 @@ public partial class App : Application
base.OnStartup(e);
#if DEBUG
// 初始化 DebugTracker
DebugTracker.Enabled = true;
DebugTracker.Channels.Add(new DiagnosisDebugTrackChannel());
// 初始化 DebugTracker
DebugTracker.Enabled = true;
DebugTracker.Channels.Add(new DiagnosisDebugTrackChannel());
#endif
}

View File

@ -54,21 +54,30 @@ namespace Wpf_AiSportsMicrospace.Common
public WebcamClient CreateRTSP()
{
_webcamClient = WebcamClient.CreateRTSP("192.168.3.64", "admin", "yd708090", 554u);
try
{
_webcamClient = WebcamClient.CreateRTSP("192.168.3.64", "admin", "yd708090", 554u);
}
catch (Exception)
{
HandyControl.Controls.MessageBox.Show("摄像头网络异常,请重新连接!");
}
return _webcamClient;
}
public int VerifyWavingAction(Human human)
{
var nose = human.Keypoints.FirstOrDefault(k => k.Name == "nose");
var nose = human.Keypoints.FirstOrDefault(k => k.Name == "right_ankle");
if (nose == null)
return 0;
return (int)WavingAction.None;
// 使用 Canvas 宽度归一化
double xNorm = nose.X / 1920;
if (!(xNorm >= 0.44 && xNorm <= 0.57))
return 0;
double yNorm = nose.Y / 1080;
if (!(xNorm >= 0.44 && xNorm <= 0.57 && yNorm >= 0.81))
return (int)WavingAction.None;
var leftWrist = human.Keypoints.FirstOrDefault(x => x.Name == "left_wrist");
var leftElbow = human.Keypoints.FirstOrDefault(x => x.Name == "left_elbow");

View File

@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.MyUserControl"
xmlns:gif="http://wpfanimatedgif.codeplex.com"
Height="1080" Width="1920" >
Height="1080" Width="1920" Loaded="Window_Loaded" Unloaded="CenterHome_Unloaded" >
<Grid VerticalAlignment="Bottom">
<Grid.Background>
<ImageBrush ImageSource="/Resources/Img/play_img/play_home_bg.png" Stretch="UniformToFill"/>

View File

@ -19,6 +19,7 @@ using Wpf_AiSportsMicrospace.Enum;
using Wpf_AiSportsMicrospace.MyUserControl;
using Wpf_AiSportsMicrospace.Views;
using Yztob.AiSports.Inferences.Abstractions;
using Yztob.AiSports.Inferences.Things;
using Yztob.AiSports.Postures;
using Yztob.AiSports.Postures.Abstractions;
using Yztob.AiSports.Postures.Sports;
@ -33,10 +34,13 @@ namespace Wpf_AiSportsMicrospace.Views
public partial class CenterHome : UserControl
{
private IHumanPredictor _humanPredictor;
private IObjectDetector _objectDetector;
private HumanGraphicsRenderer _humanGraphicsRenderer;
private WebcamClient _webcamClient;
private ConcurrentQueue<VideoFrame> _frameQueue = new();
private CancellationTokenSource _cts = new();
private SportOperate _sportOperate;
private Main _mainWin => Application.Current.MainWindow as Main;
public String _nowSelect = "test"; //测试吧test 游戏吧play
public String NowSelect
@ -55,7 +59,11 @@ namespace Wpf_AiSportsMicrospace.Views
public CenterHome()
{
InitializeComponent();
_humanPredictor = HumanPredictorFactory.Create(HumanPredictorType.SingleHigh);
//_humanPredictor = HumanPredictorFactory.Create(HumanPredictorType.SingleHigh);
//_humanPredictor = HumanPredictorFactory.Create(HumanPredictorType.MultiMedium);
//_objectDetector = ObjectDetectorFactory.CreateSportGoodsDetector();
//_humanGraphicsRenderer = new HumanGraphicsRenderer();
//_humanGraphicsRenderer.DrawLabel = false;
//_sports = SportBase.GetSports();
//_detectQueue = new SportDetectionQueue();
@ -66,36 +74,66 @@ namespace Wpf_AiSportsMicrospace.Views
coverFlow.SelectedIndex = 0;
InitImg();
Loaded += Window_Loaded;
Unloaded += CenterHome_Unloaded;
//AnimationBehavior.SetSourceUri(LoadingImage, loadingImage);
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
_sportOperate = new SportOperate();
_webcamClient = _sportOperate.CreateRTSP();
_webcamClient.OnExtractFrame += frame =>
{
if (frame != null)
_frameQueue.Enqueue(frame);
};
_webcamClient.StartExtract();
StartFrameProcessing();
_mainWin.HumanFrameUpdated += OnHumanFrameUpdated;
Utils.PlayBackgroundMusic("homeprojectselected.mp3");
//coverFlow.ProgressCompleted += CoverFlow_ProgressCompleted;
}
private void CenterHome_Unloaded(object sender, RoutedEventArgs e)
{
_mainWin.HumanFrameUpdated -= OnHumanFrameUpdated;
}
private void OnHumanFrameUpdated(object sender, List<Human> humans)
{
var human = humans.FirstOrDefault();
if (human == null) return;
//检测挥手动作
var wavingaction = _mainWin.SportOperate.VerifyWavingAction(human);
switch (wavingaction)
{
case (int)WavingAction.LeftWave: // 左手挥动
coverFlow.SlideRight();
break;
case (int)WavingAction.RightWave: // 右手挥动
coverFlow.SlideLeft();
break;
case (int)WavingAction.FirstHand: // 举手开始
coverFlow.StartSelectedProgress();
break;
case (int)WavingAction.Raising: // 举手中,实时更新进度
break;
case (int)WavingAction.RaiseHand: // 举手完成
_cts.Cancel();
coverFlow.ProgressCompleted += CoverFlow_ProgressCompleted;
break;
default: // 没有动作 → 取消进度
coverFlow.CancelSelectedProgress();
break;
}
}
private void CoverFlow_ProgressCompleted(CoverFlowItem item)
{
// 停止抽帧线程/释放资源
try
{
_cts.Cancel(); // 停止后台处理线程
_webcamClient?.StopExtract(); // 停止摄像头抽帧
_webcamClient = null;
RouterGoNew();
}
catch (Exception ex)
{
@ -123,35 +161,33 @@ namespace Wpf_AiSportsMicrospace.Views
// mainWin.SwitchPage(new GroupJumpRope(), true);
//}
RouterGoNew();
}
private void StartFrameProcessing()
{
Task.Run(() =>
Task.Run(async () =>
{
while (!_cts.Token.IsCancellationRequested)
{
if (_frameQueue.TryDequeue(out var frame))
{
ProcessFrame(frame);
try
{
ProcessFrame(frame);
}
catch (Exception ex)
{
Console.WriteLine("ProcessFrame error: " + ex.Message);
}
}
else
{
//_webcamClient.OnExtractFrame += frame =>
//{
// if (frame != null)
// _frameQueue.Enqueue(frame);
//};
//_webcamClient.StartExtract();
_webcamClient.StartExtract();
//Thread.Sleep(5);
await Task.Delay(5, _cts.Token);
}
}
}, _cts.Token);
}
private void ProcessFrame(VideoFrame frame)
{
try
@ -163,13 +199,6 @@ namespace Wpf_AiSportsMicrospace.Views
if (humans == null || humans.Count == 0)
return;
//var human = humans
// .Where(h =>
// h.Keypoints.Any(kp => kp.Name == "left_ankle" && kp.X < 1020 && kp.Y > 900 && kp.Y < 1020) &&
// h.Keypoints.Any(kp => kp.Name == "right_ankle" && kp.X > 750 && kp.Y > 900 && kp.Y < 1020)
// )
// .FirstOrDefault();
var human = humans.FirstOrDefault();
if (human == null) return;
@ -177,10 +206,6 @@ namespace Wpf_AiSportsMicrospace.Views
//检测挥手动作
var wavingaction = _sportOperate.VerifyWavingAction(human);
// 把低 8 位作为动作类型,高 8 位作为进度
//int actionType = wavingaction & 0xFF;
//int progress = (wavingaction >> 8) & 0xFF;
switch (wavingaction)
{
case (int)WavingAction.LeftWave: // 左手挥动
@ -216,7 +241,10 @@ namespace Wpf_AiSportsMicrospace.Views
public void Dispose()
{
throw new NotImplementedException();
_cts.Cancel();
_webcamClient?.StopExtract();
_webcamClient = null;
_humanPredictor.Dispose();
}
public void InitImg()

View File

@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.MyUserControl"
xmlns:gif="http://wpfanimatedgif.codeplex.com"
Height="1080" Width="1920" Loaded="Window_Loaded">
Height="1080" Width="1920" Loaded="Window_Loaded" Unloaded="Home_Unloaded">
<Grid VerticalAlignment="Bottom">
<Grid.Background>
<ImageBrush ImageSource="/Resources/Img/Album/home_bg.png" Stretch="UniformToFill"/>

View File

@ -20,6 +20,7 @@ using Wpf_AiSportsMicrospace.Enum;
using Wpf_AiSportsMicrospace.MyUserControl;
using Wpf_AiSportsMicrospace.Views;
using Yztob.AiSports.Inferences.Abstractions;
using Yztob.AiSports.Inferences.Things;
using Yztob.AiSports.Postures;
using Yztob.AiSports.Postures.Abstractions;
using Yztob.AiSports.Postures.Sports;
@ -34,16 +35,21 @@ namespace Wpf_AiSportsMicrospace
public partial class Home : UserControl
{
private IHumanPredictor _humanPredictor;
private HumanGraphicsRenderer _humanGraphicsRenderer;
private WebcamClient _webcamClient;
private ConcurrentQueue<VideoFrame> _frameQueue = new();
private CancellationTokenSource _cts = new();
private SportOperate _sportOperate;
public static Uri loadingImage = new Uri("/Resources/Img/Album/1.gif", UriKind.Relative);
private Main _mainWin => Application.Current.MainWindow as Main;
public Home()
{
InitializeComponent();
_humanPredictor = HumanPredictorFactory.Create(HumanPredictorType.SingleHigh);
//_humanPredictor = HumanPredictorFactory.Create(HumanPredictorType.SingleHigh);
//_humanGraphicsRenderer = new HumanGraphicsRenderer();
//_humanGraphicsRenderer.DrawLabel = false;
//_sports = SportBase.GetSports();
//_detectQueue = new SportDetectionQueue();
@ -64,24 +70,101 @@ namespace Wpf_AiSportsMicrospace
// 默认选中第3张
coverFlow.SelectedIndex = 0;
Loaded += Window_Loaded;
Unloaded += Home_Unloaded;
//AnimationBehavior.SetSourceUri(LoadingImage, loadingImage);
}
private void Home_Unloaded(object sender, RoutedEventArgs e)
{
_mainWin.HumanFrameUpdated -= OnHumanFrameUpdated;
}
private void OnHumanFrameUpdated(object sender, List<Human> humans)
{
var human = humans.FirstOrDefault();
if (human == null) return;
//检测挥手动作
var wavingaction = _mainWin.SportOperate.VerifyWavingAction(human);
// 把低 8 位作为动作类型,高 8 位作为进度
//int actionType = wavingaction & 0xFF;
//int progress = (wavingaction >> 8) & 0xFF;
//switch (wavingaction)
//{
// case (int)WavingAction.LeftWave: // 左手挥动
// Application.Current.Dispatcher.BeginInvoke(() => coverFlow.SlideRight());
// break;
// case (int)WavingAction.RightWave: // 右手挥动
// Application.Current.Dispatcher.BeginInvoke(() => coverFlow.SlideLeft());
// break;
// case (int)WavingAction.FirstHand: // 举手开始
// Application.Current.Dispatcher.BeginInvoke(() => coverFlow.StartSelectedProgress());
// break;
// case (int)WavingAction.Raising: // 举手中,实时更新进度
// break;
// case (int)WavingAction.RaiseHand: // 举手完成
// _cts.Cancel();
// coverFlow.ProgressCompleted += CoverFlow_ProgressCompleted;
// break;
// default: // 没有动作 → 取消进度
// Application.Current.Dispatcher.BeginInvoke(() => coverFlow.CancelSelectedProgress());
// break;
//}
switch (wavingaction)
{
case (int)WavingAction.LeftWave: // 左手挥动
coverFlow.SlideRight();
break;
case (int)WavingAction.RightWave: // 右手挥动
coverFlow.SlideLeft();
break;
case (int)WavingAction.FirstHand: // 举手开始
coverFlow.StartSelectedProgress();
break;
case (int)WavingAction.Raising: // 举手中,实时更新进度
break;
case (int)WavingAction.RaiseHand: // 举手完成
_cts.Cancel();
coverFlow.ProgressCompleted += CoverFlow_ProgressCompleted;
break;
default: // 没有动作 → 取消进度
coverFlow.CancelSelectedProgress();
break;
}
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
_sportOperate = new SportOperate();
_webcamClient = _sportOperate.CreateRTSP();
_mainWin.HumanFrameUpdated += OnHumanFrameUpdated;
_webcamClient.OnExtractFrame += frame =>
{
if (frame != null)
_frameQueue.Enqueue(frame);
};
_webcamClient.StartExtract();
//_sportOperate = new SportOperate();
//_webcamClient = _sportOperate.CreateRTSP();
StartFrameProcessing();
//_webcamClient.OnExtractFrame += frame =>
//{
// if (frame != null)
// _frameQueue.Enqueue(frame);
//};
//_webcamClient.StartExtract();
//StartFrameProcessing();
//Utils.PlayBackgroundMusic("homeprojectselected.mp3");
@ -92,10 +175,8 @@ namespace Wpf_AiSportsMicrospace
// 停止抽帧线程/释放资源
try
{
_cts.Cancel(); // 停止后台处理线程
_webcamClient?.StopExtract(); // 停止摄像头抽帧
_webcamClient = null;
//Dispose();
RouterGoNew();
}
catch (Exception ex)
{
@ -115,28 +196,27 @@ namespace Wpf_AiSportsMicrospace
//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);
//}
RouterGoNew();
}
private void StartFrameProcessing()
{
Task.Run(() =>
Task.Run(async () =>
{
while (!_cts.Token.IsCancellationRequested)
{
if (_frameQueue.TryDequeue(out var frame))
{
ProcessFrame(frame);
try
{
ProcessFrame(frame);
}
catch (Exception ex)
{
Console.WriteLine("ProcessFrame error: " + ex.Message);
}
}
else
{
Thread.Sleep(5);
await Task.Delay(5, _cts.Token);
}
}
}, _cts.Token);
@ -173,18 +253,16 @@ namespace Wpf_AiSportsMicrospace
switch (wavingaction)
{
case 0: // 点位验证失败
break;
case (int)WavingAction.LeftWave: // 左手挥动
Dispatcher.BeginInvoke(() => coverFlow.SlideRight());
Application.Current.Dispatcher.BeginInvoke(() => coverFlow.SlideRight());
break;
case (int)WavingAction.RightWave: // 右手挥动
Dispatcher.BeginInvoke(() => coverFlow.SlideLeft());
Application.Current.Dispatcher.BeginInvoke(() => coverFlow.SlideLeft());
break;
case (int)WavingAction.FirstHand: // 举手开始
Dispatcher.BeginInvoke(() => coverFlow.StartSelectedProgress());
Application.Current.Dispatcher.BeginInvoke(() => coverFlow.StartSelectedProgress());
break;
case (int)WavingAction.Raising: // 举手中,实时更新进度
@ -196,7 +274,7 @@ namespace Wpf_AiSportsMicrospace
break;
default: // 没有动作 → 取消进度
Dispatcher.BeginInvoke(() => coverFlow.CancelSelectedProgress());
Application.Current.Dispatcher.BeginInvoke(() => coverFlow.CancelSelectedProgress());
break;
}
}
@ -208,14 +286,17 @@ namespace Wpf_AiSportsMicrospace
public void Dispose()
{
throw new NotImplementedException();
_cts.Cancel();
_webcamClient?.StopExtract();
_webcamClient = null;
_humanPredictor.Dispose();
}
//测试点击
private void GoNew(object sender, MouseButtonEventArgs e)
{
// 跳转逻辑(如导航到新页面并传递参数)
// 例如RaiseEvent、调用外部委托、或使用导航框架
//例如RaiseEvent、调用外部委托、或使用导航框架
var mainWin = Application.Current.MainWindow as Main;
var newPage = new CenterHome
{

View File

@ -4,7 +4,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.Views"
mc:Ignorable="d" Height="1080" Width="1920" Loaded="UserControl_Loaded">
mc:Ignorable="d" Height="1080" Width="1920" Loaded="UserControl_Loaded" Unloaded="UserControl_Unloaded">
<Grid >
<Grid.Background>
<ImageBrush ImageSource="/Resources/Img/Album/home_bg.png" Stretch="UniformToFill"/>

View File

@ -1,5 +1,6 @@
using Emgu.CV.Flann;
using HandyControl.Controls;
using SharpDX.Direct3D9;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@ -44,23 +45,23 @@ namespace Wpf_AiSportsMicrospace.Views
private ConcurrentQueue<VideoFrame> _frameQueue = new();
private CancellationTokenSource _cts = new();
private SportOperate _sportOperate;
private SportBase _sport;
private readonly SportDetectionQueue _detectQueue;
private List<SportBase> sports = new();
private List<TextBlock> circleTexts = new();
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;
ConfigService configService = new ConfigService();
public GroupJumpRope()
{
InitializeComponent();
_humanPredictor = HumanPredictorFactory.Create(HumanPredictorType.MultiMedium);
_objectDetector = ObjectDetectorFactory.CreateSportGoodsDetector();
_humanGraphicsRenderer = new HumanGraphicsRenderer();
_humanGraphicsRenderer.DrawLabel = false;
//_humanPredictor = HumanPredictorFactory.Create(HumanPredictorType.MultiMedium);
//_objectDetector = ObjectDetectorFactory.CreateSportGoodsDetector();
//_humanGraphicsRenderer = new HumanGraphicsRenderer();
//_humanGraphicsRenderer.DrawLabel = false;
_detectQueue = new SportDetectionQueue();
Loaded += UserControl_Loaded;
Unloaded += UserControl_Unloaded;
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
@ -68,17 +69,37 @@ namespace Wpf_AiSportsMicrospace.Views
DrawCirclesWithText();
_sportOperate = new SportOperate();
_webcamClient = _sportOperate.CreateRTSP();
_mainWin.HumanFrameUpdated += OnHumanFrameUpdated;
_webcamClient.OnExtractFrame += frame =>
//_sportOperate = new SportOperate();
//_webcamClient = _sportOperate.CreateRTSP();
//_webcamClient.OnExtractFrame += frame =>
//{
// if (frame != null)
// _frameQueue.Enqueue(frame);
//};
//_webcamClient.StartExtract();
//StartFrameProcessing();
}
private void UserControl_Unloaded(object sender, RoutedEventArgs e)
{
_mainWin.HumanFrameUpdated -= OnHumanFrameUpdated;
}
private void OnHumanFrameUpdated(object sender, List<Human> humans)
{
try
{
if (frame != null)
_frameQueue.Enqueue(frame);
};
_webcamClient.StartExtract();
UpdateCircleCounts(humans);
}
catch (Exception ex)
{
Console.WriteLine("OnFrameExtracted error: " + ex.Message);
}
StartFrameProcessing();
}
private void StartFrameProcessing()
@ -93,7 +114,7 @@ namespace Wpf_AiSportsMicrospace.Views
}
else
{
Thread.Sleep(5); // 空队列时避免忙等
Thread.Sleep(5);
}
}
}, _cts.Token);
@ -124,7 +145,7 @@ namespace Wpf_AiSportsMicrospace.Views
foreach (var hu in humans)
{
var nose = hu.Keypoints.FirstOrDefault(k => k.Name == "nose");
var nose = hu.Keypoints.FirstOrDefault(k => k.Name == "right_ankle");
if (nose == null)
continue;
@ -197,8 +218,6 @@ namespace Wpf_AiSportsMicrospace.Views
sports.Add(sport);
}
}
private void UpdateCircleCounts(List<Human> humans)
{
for (int i = 0; i < circlePositionsX.Length; i++)
@ -215,7 +234,6 @@ namespace Wpf_AiSportsMicrospace.Views
}
}
}
private void AddGlowEllipse(double centerX, double centerY, double radius, Canvas canvas)
{
var ellipse = new Ellipse
@ -361,5 +379,6 @@ namespace Wpf_AiSportsMicrospace.Views
Canvas.SetTop(ellipse, centerY - (radius * flattenFactor) / 2);
canvas.Children.Add(ellipse);
}
}
}

View File

@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -12,6 +13,11 @@ using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using Wpf_AiSportsMicrospace.Common;
using Yztob.AiSports.Inferences.Abstractions;
using Yztob.AiSports.Inferences.Things;
using Yztob.AiSports.Sensors.Abstractions;
using Yztob.AiSports.Sensors.Things;
namespace Wpf_AiSportsMicrospace.Views
{
@ -20,13 +26,86 @@ namespace Wpf_AiSportsMicrospace.Views
/// </summary>
public partial class Main : Window
{
private IHumanPredictor _humanPredictor;
private HumanGraphicsRenderer _humanGraphicsRenderer;
public SportOperate SportOperate { get; private set; }
public WebcamClient WebcamClient { get; private set; }
private readonly ConcurrentQueue<VideoFrame> _frameQueue = new();
private readonly CancellationTokenSource _cts = new();
public Main()
{
InitializeComponent();
var options = new InferenceOptions()
{
GpuEnabled = true
};
Yztob.AiSports.Common.SportAppSettingService.Set("inferences", options);
_humanPredictor = HumanPredictorFactory.Create(HumanPredictorType.MultiMedium);
_humanGraphicsRenderer = new HumanGraphicsRenderer();
_humanGraphicsRenderer.DrawLabel = false;
SportOperate = new SportOperate();
WebcamClient = SportOperate.CreateRTSP();
// 开始抽帧线程
StartFrameProcessing();
// 默认显示首页
MainContent.Content = new Home();
}
private void StartFrameProcessing()
{
WebcamClient.OnExtractFrame += frame =>
{
if (frame != null)
_frameQueue.Enqueue(frame);
};
WebcamClient.StartExtract();
Task.Run(() =>
{
while (!_cts.Token.IsCancellationRequested)
{
if (_frameQueue.TryDequeue(out var frame))
{
ProcessFrame(frame);
}
else
{
// 避免 CPU 占满
Thread.Sleep(5);
}
}
}, _cts.Token);
}
private void ProcessFrame(VideoFrame frame)
{
try
{
var buffer = frame.GetImageBuffer(ImageFormat.Jpeg).ToArray();
var humanResult = _humanPredictor.Predicting(buffer, frame.Number);
var humans = humanResult?.Humans?.ToList();
if (humans == null || humans.Count == 0)
return;
// 触发全局事件
Application.Current.Dispatcher.Invoke(() =>
{
HumanFrameUpdated?.Invoke(this, humans);
});
}
catch (Exception ex)
{
Console.WriteLine("ProcessFrame error: " + ex.Message);
}
}
public event EventHandler<List<Human>> HumanFrameUpdated;
//public void SwitchPage(UserControl newPage, bool fromRight)
//{
// if (MainContent.Content == newPage) return;
@ -79,86 +158,100 @@ namespace Wpf_AiSportsMicrospace.Views
// 预加载新页面资源
PreloadPageResources(newPage);
if (oldPage != null)
{
MainContent.Content = null;
// 创建容器同时显示新旧页面
var container = new Grid();
container.Children.Add(newPage); // 新页面在底层
container.Children.Add(oldPage); // 旧页面在顶层
// 确保最终状态
newPage.RenderTransform = null;
newPage.Opacity = 1;
MainContent.Content = container;
// 切换到只有新页面
MainContent.Content = newPage;
// 设置新页面初始状态 - 轻微缩放和偏移
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;
// 清理资源
if (oldPage is IDisposable disposable)
disposable.Dispose();
// 动画参数
var duration = TimeSpan.FromMilliseconds(1200);
var easing = new CubicEase { EasingMode = EasingMode.EaseInOut };
//container.Children.Clear();
// 旧页面飞出动画
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
};
//if (oldPage != null)
//{
// MainContent.Content = null;
// // 创建容器同时显示新旧页面
// var container = new Grid();
// container.Children.Add(newPage); // 新页面在底层
// container.Children.Add(oldPage); // 旧页面在顶层
// 新页面进入动画
var newScaleAnim = new DoubleAnimation(0.8, 1, duration) { EasingFunction = easing };
var newTranslateAnim = new DoubleAnimation(fromRight ? -80 : -80, 0, duration) { EasingFunction = easing };
// MainContent.Content = container;
// 开始动画
oldScale.BeginAnimation(ScaleTransform.ScaleXProperty, oldScaleAnim);
oldScale.BeginAnimation(ScaleTransform.ScaleYProperty, oldScaleAnim);
oldSkew.BeginAnimation(SkewTransform.AngleYProperty, oldSkewAnim);
oldTranslate.BeginAnimation(TranslateTransform.XProperty, oldTranslateAnim);
// // 设置新页面初始状态 - 轻微缩放和偏移
// 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;
newScale.BeginAnimation(ScaleTransform.ScaleXProperty, newScaleAnim);
newScale.BeginAnimation(ScaleTransform.ScaleYProperty, newScaleAnim);
newTranslate.BeginAnimation(TranslateTransform.XProperty, newTranslateAnim);
// // 旧页面动画 - 飞出效果
// 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;
// 动画完成后清理
oldTranslateAnim.Completed += (s, e) =>
{
// 确保最终状态
newPage.RenderTransform = null;
newPage.Opacity = 1;
// // 动画参数
// var duration = TimeSpan.FromMilliseconds(1200);
// var easing = new CubicEase { EasingMode = EasingMode.EaseInOut };
// 切换到只有新页面
MainContent.Content = newPage;
// // 旧页面飞出动画
// 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
// };
// 清理资源
if (oldPage is IDisposable disposable)
disposable.Dispose();
// // 新页面进入动画
// var newScaleAnim = new DoubleAnimation(0.8, 1, duration) { EasingFunction = easing };
// var newTranslateAnim = new DoubleAnimation(fromRight ? -80 : -80, 0, duration) { EasingFunction = easing };
container.Children.Clear();
};
}
else
{
MainContent.Content = newPage;
newPage.Opacity = 1;
}
// // 开始动画
// 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)

View File

@ -64,7 +64,7 @@
<PackageReference Include="HandyControl" Version="3.5.1" />
<PackageReference Include="Microsoft.Management.Infrastructure" Version="3.0.0" />
<PackageReference Include="Microsoft.ML" Version="4.0.2" />
<PackageReference Include="Microsoft.ML.OnnxRuntime" Version="1.22.1" />
<PackageReference Include="Microsoft.ML.OnnxRuntime.DirectML" Version="1.23.0" />
<PackageReference Include="SharpDX.Direct3D9" Version="4.2.0" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.11" />
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.7" />