2026-01-14 13:25:07 +08:00

292 lines
10 KiB
C#

using SharpDX.Direct3D9;
using System.Collections.Concurrent;
using System.Drawing;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using Wpf_AiSportsMicrospace.Common;
using WpfAnimatedGif;
using Yztob.AiSports.Inferences.Abstractions;
using Yztob.AiSports.Inferences.Things;
using Yztob.AiSports.Sensors.Abstractions;
using Yztob.AiSports.Sensors.Things;
using Brushes = System.Windows.Media.Brushes;
namespace Wpf_AiSportsMicrospace.Views
{
/// <summary>
/// Main.xaml 的交互逻辑
/// </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 SportDetectionQueue _detectQueue;
private readonly ConcurrentQueue<VideoFrame> _frameQueue = new();
private readonly CancellationTokenSource _cts = new();
private readonly object _reconnectLock = new();
public event EventHandler<List<Human>> HumanFrameUpdated;
public event Action<VideoFrame> FacialRecognitionEvent;
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;
_detectQueue = new SportDetectionQueue();
SportOperate = new SportOperate();
WebcamClient = SportOperate.CreateRTSP();
// 开始抽帧线程
StartFrameProcessing();
// 启动心跳检测线程
//StartHeartbeatMonitor();
// 默认显示首页
MainContent.Content = new Home();
ImageBehavior.AddAnimationCompletedHandler(time3, TimeDown);
}
private void StartFrameProcessing()
{
if (WebcamClient == null)
{
//HandyControl.Controls.MessageBox.Show("摄像头网络异常,请重新连接!");
return;
}
WebcamClient.OnExtractFrame += frame =>
{
_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
{
//if (frame.Number % 2 != 0)
// return;
// 触发全局事件
//Application.Current.Dispatcher.BeginInvoke(() =>
//{
// FacialRecognitionEvent?.Invoke(frame);
//});
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.BeginInvoke(() =>
{
HumanFrameUpdated?.Invoke(this, humans);
});
}
catch (Exception ex)
{
Console.WriteLine("ProcessFrame error: " + ex.Message);
}
}
public void SwitchPage(UserControl newPage, bool fromRight)
{
if (MainContent.Content == newPage) return;
var oldPage = MainContent.Content as UserControl;
// 预加载新页面资源
PreloadPageResources(newPage);
// 确保最终状态
newPage.RenderTransform = null;
newPage.Opacity = 1;
// 切换到只有新页面
MainContent.Content = newPage;
// 清理资源
if (oldPage is IDisposable disposable)
disposable.Dispose();
}
private void PreloadPageResources(UserControl page)
{
// 先从原来的父容器中移除页面(如果存在)
if (page.Parent != null)
{
var parent = page.Parent as Panel;
parent?.Children.Remove(page);
}
// 强制WPF加载所有资源
page.Measure(new System.Windows.Size(double.PositiveInfinity, double.PositiveInfinity));
page.Arrange(new Rect(0, 0, page.DesiredSize.Width, page.DesiredSize.Height));
}
public void SwitchPageWithMaskAnimation(UserControl newPage, bool fromRight, double durationSeconds = 1.2)
{
if (MainContent.Content == newPage) return;
var oldPage = MainContent.Content as UserControl;
PreloadPageResources(newPage);
// 每次都创建新的 Image 实例
var maskTop = new System.Windows.Controls.Image
{
Source = new BitmapImage(new Uri("/Resources/Img/gif/top_animation_image.png", UriKind.Relative)),
Stretch = Stretch.Fill,
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Top,
Width = 1920,
Height = 1000
};
var maskBottom = new System.Windows.Controls.Image
{
Source = new BitmapImage(new Uri("/Resources/Img/gif/bottom_animation_image.png", UriKind.Relative)),
Stretch = Stretch.Fill,
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Bottom,
Width = 1920,
Height = 1000
};
var maskGrid = new Grid { Background = Brushes.Transparent, Width = 1920, Height = 1080 };
maskGrid.Children.Add(maskTop);
maskGrid.Children.Add(maskBottom);
if (MainContent.Parent is Grid parentGrid)
{
parentGrid.Children.Add(maskGrid);
Grid.SetZIndex(maskGrid, 9999);
}
else
{
var win = Window.GetWindow(this);
if (win != null && win.Content is Grid winGrid)
{
winGrid.Children.Add(maskGrid);
Grid.SetZIndex(maskGrid, 9999);
}
}
double height = ActualHeight;
double maskHeight = 1000;
//double maskHeight = height / 2 - 150;
//maskTop.Height = maskHeight;
//maskBottom.Height = maskHeight;
maskTop.RenderTransform = new TranslateTransform(0, -maskHeight);
maskBottom.RenderTransform = new TranslateTransform(0, maskHeight);
var duration = TimeSpan.FromSeconds(durationSeconds);
var ease = new CubicEase { EasingMode = EasingMode.EaseInOut };
var topInAnim = new DoubleAnimation(-maskHeight, 0, duration) { EasingFunction = ease };
var bottomInAnim = new DoubleAnimation(maskHeight, 0, duration) { EasingFunction = ease };
//var topOutAnim = new DoubleAnimation(0, maskHeight, duration) { EasingFunction = ease };
//var bottomOutAnim = new DoubleAnimation(0, -maskHeight, duration) { EasingFunction = ease };
var bottomOutAnim = new DoubleAnimation(0, maskHeight, duration) { EasingFunction = ease };
var topOutAnim = new DoubleAnimation(0, -maskHeight, duration) { EasingFunction = ease };
topInAnim.Completed += (s, e) =>
{
MainContent.Content = newPage;
maskTop.RenderTransform.BeginAnimation(TranslateTransform.YProperty, topOutAnim);
maskBottom.RenderTransform.BeginAnimation(TranslateTransform.YProperty, bottomOutAnim);
};
topOutAnim.Completed += (s, e) =>
{
if (maskGrid.Parent is Grid grid)
grid.Children.Remove(maskGrid);
if (oldPage is IDisposable disposable)
disposable.Dispose();
};
maskTop.RenderTransform.BeginAnimation(TranslateTransform.YProperty, topInAnim);
maskBottom.RenderTransform.BeginAnimation(TranslateTransform.YProperty, bottomInAnim);
}
public void ShowElement(string name, int time = 600)
{
var Element = FindName(name) as FrameworkElement;
if (Element == null) return;
Element.Visibility = Visibility.Visible;
var fadeIn = new DoubleAnimation(0, 1, TimeSpan.FromMilliseconds(time));
Element.BeginAnimation(UIElement.OpacityProperty, fadeIn);
}
int num = 1;
public void ShowCountDownAnimation()
{
ImageBehavior.SetRepeatBehavior(time3, new RepeatBehavior(2));
ImageBehavior.SetRepeatBehavior(time3, new RepeatBehavior(1));
CountTimeGrid.Visibility = Visibility.Visible;
time3.Visibility = Visibility.Visible;
ImageBehavior.GetAnimationController(time3).Play();
}
private void TimeDown(object? sender, RoutedEventArgs? e)
{
//MessageBox.Show("播放完啦");// 弹提示框
ImageBehavior.GetAnimationController(time3).Pause();
CountTimeGrid.Visibility = Visibility.Hidden;
time3.Visibility = Visibility.Hidden;
num++;
}
private void Window_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
// 确认是左键双击
if (e.ChangedButton == MouseButton.Right)
{
Application.Current.Shutdown();
}
}
}
}