2025-10-12 10:20:08 +08:00

296 lines
12 KiB
C#

using System;
using System.Collections.Concurrent;
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;
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
{
/// <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 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;
// 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);
// }
//}
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();
//container.Children.Clear();
//if (oldPage != null)
//{
// MainContent.Content = null;
// // 创建容器同时显示新旧页面
// var container = new Grid();
// container.Children.Add(newPage); // 新页面在底层
// container.Children.Add(oldPage); // 旧页面在顶层
// MainContent.Content = container;
// // 设置新页面初始状态 - 轻微缩放和偏移
// 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;
// // 动画参数
// var duration = TimeSpan.FromMilliseconds(1200);
// var easing = new CubicEase { EasingMode = EasingMode.EaseInOut };
// // 旧页面飞出动画
// 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
// };
// // 新页面进入动画
// var newScaleAnim = new DoubleAnimation(0.8, 1, duration) { EasingFunction = easing };
// var newTranslateAnim = new DoubleAnimation(fromRight ? -80 : -80, 0, duration) { EasingFunction = easing };
// // 开始动画
// 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)
{
// 先从原来的父容器中移除页面(如果存在)
if (page.Parent != null)
{
var parent = page.Parent as Panel;
parent?.Children.Remove(page);
}
// 强制WPF加载所有资源
page.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
page.Arrange(new Rect(0, 0, page.DesiredSize.Width, page.DesiredSize.Height));
}
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);
}
}
}