diff --git a/Wpf_AiSportsMicrospace/Views/Setting/JumpSetting.xaml b/Wpf_AiSportsMicrospace/Views/Setting/JumpSetting.xaml new file mode 100644 index 0000000..213adb8 --- /dev/null +++ b/Wpf_AiSportsMicrospace/Views/Setting/JumpSetting.xaml @@ -0,0 +1,19 @@ + + + + + + + + + + diff --git a/Wpf_AiSportsMicrospace/Views/Setting/JumpSetting.xaml.cs b/Wpf_AiSportsMicrospace/Views/Setting/JumpSetting.xaml.cs new file mode 100644 index 0000000..6d5cedf --- /dev/null +++ b/Wpf_AiSportsMicrospace/Views/Setting/JumpSetting.xaml.cs @@ -0,0 +1,348 @@ +using AiSportsMicrospaceDB.DBContext; +using Emgu.CV.Reg; +using Microsoft.EntityFrameworkCore; +using SharpDX.Direct3D9; +using SkiaSharp; +using System.Diagnostics; +using System.Drawing.Imaging; +using System.IO; +using System.Net.NetworkInformation; +using System.Runtime.InteropServices; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; +using System.Windows.Threading; +using Wpf_AiSportsMicrospace.Common; +using Wpf_AiSportsMicrospace.Dto; +using Yztob.AiSports.Inferences.Abstractions; +using Yztob.AiSports.Inferences.Things; +using Yztob.AiSports.Postures.Sports; +using Yztob.AiSports.Postures.Things; +using Yztob.AiSports.Sensors.Abstractions; +using Yztob.AiSports.Sensors.Things; + +namespace Wpf_AiSportsMicrospace.Views +{ + public partial class JumpSttting : UserControl + { + #region 私有成员 + private IHumanPredictor _humanPredictor; + private IObjectDetector _objectDetector; + private HumanGraphicsRenderer _humanGraphicsRenderer; + private readonly List _sports; + private SportBase _sport; + private readonly SportDetectionQueue _detectQueue; + + private WriteableBitmap _videoBitmap; + private int _lastFrameNumber = -1; + + // 拖拽相关成员变量 + private bool _isDragging = false; + private Ellipse? _draggingEllipse; + private TextBlock? _draggingTextBlock; + private Point _dragStartMousePos; + private double _dragStartLeft; + private double _dragStartTop; + #endregion + + public JumpSttting() + { + InitializeComponent(); + + _humanPredictor = HumanPredictorFactory.Create(HumanPredictorType.SingleHigh); + _objectDetector = ObjectDetectorFactory.CreateSportGoodsDetector(); + _humanGraphicsRenderer = new HumanGraphicsRenderer(); + _humanGraphicsRenderer.DrawLabel = false; + + _sports = SportBase.GetSports(); + + _detectQueue = new SportDetectionQueue(); + + // 确保在加载完成后绘制圆圈 + this.Loaded += (s, e) => DrawCirclesWithText(); + } + + private void Window_Loaded(object sender, RoutedEventArgs e) + { + Application.Current.Dispatcher.InvokeAsync(() => + { + DrawCirclesWithText(); + }, DispatcherPriority.Loaded); + + videoImage.SizeChanged += (s, ev) => + { + DrawCirclesWithText(); + }; + } + + /// + /// 绘制可拖动的圆圈和位置文本 + /// + private void DrawCirclesWithText() + { + if (overlayCanvas == null) + { + Debug.WriteLine("overlayCanvas 为空,无法绘制"); + return; + } + + try + { + overlayCanvas.Children.Clear(); + Debug.WriteLine($"Canvas 尺寸: {overlayCanvas.ActualWidth} x {overlayCanvas.ActualHeight}"); + + double imgWidth = overlayCanvas.ActualWidth; + double imgHeight = overlayCanvas.ActualHeight; + + // 如果实际尺寸为0,使用控件大小 + if (imgWidth <= 0 || imgHeight <= 0) + { + imgWidth = this.videoImage?.ActualWidth ?? 800; + imgHeight = this.videoImage?.ActualHeight ?? 600; + Debug.WriteLine($"使用备用尺寸: {imgWidth} x {imgHeight}"); + } + + if (imgWidth <= 0 || imgHeight <= 0) + { + Debug.WriteLine("尺寸无效,跳过绘制"); + return; + } + + double radius = 50; + int circleIndex = 1; + + // 每个圆的位置:X 和 Y 都归一化 0~1 + var circlePositions = new List<(double XNorm, double YNorm)> + { + (0.1, 0.6), + (0.3, 0.8), + (0.5, 0.6), + (0.7, 0.8), + (0.9, 0.6) + }; + + foreach (var pos in circlePositions) + { + double x = pos.XNorm * imgWidth; + double y = pos.YNorm * imgHeight; + + Debug.WriteLine($"创建第{circleIndex}个圆: 原始坐标 ({x:F0}, {y:F0})"); + + // 创建圆圈 + var ellipse = CreateDraggableEllipse(x, y, radius); + + // 创建文本控件 + var textBlock = CreatePositionText(x, y, radius, circleIndex); + + overlayCanvas.Children.Add(ellipse); + overlayCanvas.Children.Add(textBlock); + + circleIndex++; + } + + Debug.WriteLine($"成功绘制 {circleIndex - 1} 个可拖动圆圈"); + } + catch (Exception ex) + { + Debug.WriteLine($"绘制圆圈时出错: {ex.Message}"); + } + } + + /// + /// 创建可拖动的圆圈 + /// + private Ellipse CreateDraggableEllipse(double centerX, double centerY, double radius) + { + var ellipse = new Ellipse + { + Width = radius * 2, + Height = radius * 2, + Opacity = 0.7, + Fill = new SolidColorBrush(Colors.Blue), + Stroke = new SolidColorBrush(Colors.Yellow), + StrokeThickness = 3, + Cursor = Cursors.Hand, + Tag = "draggable_circle" // 添加标记便于识别 + }; + + Canvas.SetLeft(ellipse, centerX - radius); + Canvas.SetTop(ellipse, centerY - radius); + + // 添加鼠标事件处理程序 + ellipse.MouseLeftButtonDown += Ellipse_MouseLeftButtonDown; + ellipse.MouseMove += Ellipse_MouseMove; + ellipse.MouseLeftButtonUp += Ellipse_MouseLeftButtonUp; + ellipse.MouseEnter += (s, e) => ellipse.Opacity = 0.9; + ellipse.MouseLeave += (s, e) => ellipse.Opacity = _isDragging ? 1.0 : 0.7; + + return ellipse; + } + + /// + /// 创建位置显示文本 + /// + private TextBlock CreatePositionText(double centerX, double centerY, double radius, int circleIndex) + { + var textBlock = new TextBlock + { + Text = $"圆{circleIndex}: ({centerX:F0}, {centerY:F0})", + Foreground = Brushes.Red, + FontWeight = FontWeights.Bold, + FontSize = 14, + TextAlignment = TextAlignment.Center, + Width = 150, + Height = 25, + Background = new SolidColorBrush(Color.FromArgb(180, 255, 255, 255)), + Tag = $"text_for_circle_{circleIndex}" + }; + + Canvas.SetLeft(textBlock, centerX - 75); + Canvas.SetTop(textBlock, centerY - radius - 30); + + return textBlock; + } + + /// + /// 鼠标按下事件:开始拖动 + /// + private void Ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + if (sender is not Ellipse ellipse || overlayCanvas == null) return; + + Debug.WriteLine("开始拖动圆圈"); + + _draggingEllipse = ellipse; + _isDragging = true; + _dragStartMousePos = e.GetPosition(overlayCanvas); + _dragStartLeft = Canvas.GetLeft(ellipse); + _dragStartTop = Canvas.GetTop(ellipse); + + // 查找对应的文本控件 + _draggingTextBlock = FindCorrespondingTextBlock(ellipse); + + ellipse.CaptureMouse(); + ellipse.Opacity = 1.0; + e.Handled = true; + } + + /// + /// 查找圆圈对应的文本控件 + /// + private TextBlock? FindCorrespondingTextBlock(Ellipse ellipse) + { + double centerX = Canvas.GetLeft(ellipse) + ellipse.Width / 2; + double centerY = Canvas.GetTop(ellipse) + ellipse.Height / 2; + + // 查找距离圆圈中心最近的文本控件 + TextBlock? closestTextBlock = null; + double minDistance = double.MaxValue; + + foreach (var child in overlayCanvas.Children) + { + if (child is TextBlock textBlock) + { + double textX = Canvas.GetLeft(textBlock) + textBlock.Width / 2; + double textY = Canvas.GetTop(textBlock) + textBlock.Height / 2; + + double distance = Math.Sqrt(Math.Pow(textX - centerX, 2) + Math.Pow(textY - centerY, 2)); + + if (distance < minDistance) + { + minDistance = distance; + closestTextBlock = textBlock; + } + } + } + + return closestTextBlock; + } + + /// + /// 鼠标移动事件:拖动过程中更新位置 + /// + private void Ellipse_MouseMove(object sender, MouseEventArgs e) + { + if (!_isDragging || _draggingEllipse == null || overlayCanvas == null) return; + + var currentPos = e.GetPosition(overlayCanvas); + double dx = currentPos.X - _dragStartMousePos.X; + double dy = currentPos.Y - _dragStartMousePos.Y; + + double newLeft = _dragStartLeft + dx; + double newTop = _dragStartTop + dy; + + // 限制边界 + double maxLeft = overlayCanvas.ActualWidth - _draggingEllipse.Width; + double maxTop = overlayCanvas.ActualHeight - _draggingEllipse.Height; + newLeft = Math.Max(0, Math.Min(newLeft, maxLeft)); + newTop = Math.Max(0, Math.Min(newTop, maxTop)); + + // 更新圆圈位置 + Canvas.SetLeft(_draggingEllipse, newLeft); + Canvas.SetTop(_draggingEllipse, newTop); + + // 更新对应文本 + if (_draggingTextBlock != null) + { + double centerX = newLeft + _draggingEllipse.Width / 2; + double centerY = newTop + _draggingEllipse.Height / 2; + double radius = _draggingEllipse.Width / 2; + + Canvas.SetLeft(_draggingTextBlock, centerX - 75); + Canvas.SetTop(_draggingTextBlock, centerY - radius - 30); + + // 更新文本内容 + _draggingTextBlock.Text = $"({centerX:F0}, {centerY:F0})"; + } + } + + /// + /// 鼠标释放事件:结束拖动 + /// + private void Ellipse_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) + { + if (_draggingEllipse == null || overlayCanvas == null) return; + + if (_isDragging) + { + _isDragging = false; + _draggingEllipse.ReleaseMouseCapture(); + + double left = Canvas.GetLeft(_draggingEllipse); + double top = Canvas.GetTop(_draggingEllipse); + double centerX = left + _draggingEllipse.Width / 2; + double centerY = top + _draggingEllipse.Height / 2; + + Debug.WriteLine($"圆圈移动到坐标: X={centerX:F0}, Y={centerY:F0}"); + + // 显示完成标记 + if (_draggingTextBlock != null) + { + _draggingTextBlock.Text = $"({centerX:F0}, {centerY:F0}) ✓"; + + Task.Delay(2000).ContinueWith(t => + { + Application.Current.Dispatcher.Invoke(() => + { + if (_draggingTextBlock != null) + { + _draggingTextBlock.Text = $"({centerX:F0}, {centerY:F0})"; + } + }); + }); + } + + Debug.WriteLine("结束拖动圆圈"); + } + + _draggingEllipse.Opacity = 0.7; + _draggingEllipse = null; + _draggingTextBlock = null; + e.Handled = true; + } + } +} \ No newline at end of file