tl
This commit is contained in:
parent
8b6aa81e00
commit
589678b324
@ -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>
|
||||
|
||||
@ -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
|
||||
|
||||
}
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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"/>
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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"/>
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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"/>
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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" />
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user