update:新建多人跳绳表&新建跳远位置点表&跳远配置页面&管理员密码输入
This commit is contained in:
parent
68078a2294
commit
ec7b800c26
@ -19,6 +19,7 @@ namespace AiSportsMicrospaceDB.DBContext
|
||||
public DbSet<BasicConfig> BasicConfig { get; set; }
|
||||
|
||||
public DbSet<SixGroupPoints> SixGroupPoints { get; set; }
|
||||
public DbSet<JumpLongPoints> JumpLongPoints { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
25
AiSportsMicrospaceDB/Entities/JumpLongPoints.cs
Normal file
25
AiSportsMicrospaceDB/Entities/JumpLongPoints.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AiSportsMicrospaceDB.Entities
|
||||
{
|
||||
|
||||
public class JumpLongPoints {
|
||||
// ✅ 主键
|
||||
public int Id { get; set; }
|
||||
public Point TopPoint1 { get; set; }
|
||||
public Point TopPoint2 { get; set; }
|
||||
public Point TopPoint3 { get; set; }
|
||||
public Point BottomPoint1 { get; set; }
|
||||
public Point BottomPoint2 { get; set; }
|
||||
public Point BottomPoint3 { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
<Application x:Class="Wpf_AiSportsMicrospace.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:hc="https://handyorg.github.io/handycontrol"
|
||||
xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.Views"
|
||||
xmlns:conv="clr-namespace:Wpf_AiSportsMicrospace.Converter">
|
||||
|
||||
@ -8,12 +9,33 @@
|
||||
|
||||
<!--StartupUri="Views/JumpRope/GroupJumpRope.xaml">-->
|
||||
<Application.Resources>
|
||||
<FontFamily x:Key="AppFont">./Resoures/Fonts/myFontFamily</FontFamily>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="FontFamily" Value="./Resoures/Fonts/myFontFamily"/>
|
||||
</Style>
|
||||
<conv:DotColorConverter x:Key="DotColorConverter"/>
|
||||
<!--<conv:SpacingConverter x:Key="SpacingConverter"/>-->
|
||||
</Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<!-- 1. 先合并 HandyControl 资源 -->
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/SkinDefault.xaml"/>
|
||||
<ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/Theme.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<!-- 2. 你的自定义资源 -->
|
||||
<!-- 字体 -->
|
||||
<FontFamily x:Key="AppFont">pack://application:,,,/YourApp;component/Resources/Fonts/#MyFontFamily</FontFamily>
|
||||
|
||||
<!-- 文本样式 -->
|
||||
<Style TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}">
|
||||
<Setter Property="FontFamily" Value="{StaticResource AppFont}"/>
|
||||
<Setter Property="Foreground" Value="#333333"/>
|
||||
<Setter Property="FontSize" Value="14"/>
|
||||
</Style>
|
||||
|
||||
<!-- 转换器 -->
|
||||
<conv:DotColorConverter x:Key="DotColorConverter"/>
|
||||
<!--<conv:SpacingConverter x:Key="SpacingConverter"/>-->
|
||||
|
||||
<!-- 其他自定义样式 -->
|
||||
<Style x:Key="PrimaryButtonStyle" TargetType="Button" BasedOn="{StaticResource ButtonPrimary}">
|
||||
<Setter Property="FontFamily" Value="{StaticResource AppFont}"/>
|
||||
</Style>
|
||||
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -106,12 +106,12 @@ public partial class MainWindow : Window
|
||||
|
||||
private void ping_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var config = _context.BasicConfig.FirstOrDefault();
|
||||
//var config = _context.BasicConfig.FirstOrDefault();
|
||||
|
||||
if (config != null)
|
||||
{
|
||||
//var ip = config.Ip;
|
||||
}
|
||||
//if (config != null)
|
||||
//{
|
||||
// //var ip = config.Ip;
|
||||
//}
|
||||
|
||||
var host = this.host.Text.Trim();
|
||||
if (string.IsNullOrWhiteSpace(host))
|
||||
|
||||
@ -3,12 +3,12 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.MyUserControl"
|
||||
xmlns:gif="http://wpfanimatedgif.codeplex.com"
|
||||
xmlns:hc="https://handyorg.github.io/handycontrol"
|
||||
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"/>
|
||||
</Grid.Background>
|
||||
|
||||
<!-- 顶部图片 -->
|
||||
<Image
|
||||
Source="/Resources/Img/Album/title.png"
|
||||
@ -74,5 +74,42 @@
|
||||
Width="880"
|
||||
/>
|
||||
|
||||
|
||||
<!-- 隐藏的管理员触发按钮(右上角)-->
|
||||
<Button x:Name="HiddenAdminButton"
|
||||
Width="60" Height="60"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
Margin="0,10,10,0"
|
||||
Opacity="0"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
Click="HiddenAdminButton_Click"
|
||||
Focusable="False"
|
||||
/>
|
||||
|
||||
<!-- 密码弹窗 -->
|
||||
<Grid x:Name="AdminDialogGrid" Visibility="Hidden" Background="#80000000">
|
||||
<Border CornerRadius="10" Width="420" Height="130" Background="#FFF">
|
||||
<Grid HorizontalAlignment="Center" hc:BorderElement.CornerRadius="10" VerticalAlignment="Center" Width="420" Height="130" >
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Text="请输入管理员密码:" FontSize="16" Margin="12" Grid.Row="0"/>
|
||||
<hc:PasswordBox x:Name="AdminPasswordBox" Grid.Row="1" Margin="12,4,12,0" FontSize="16" KeyDown="AdminPasswordBox_KeyDown"/>
|
||||
|
||||
|
||||
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right" Margin="12">
|
||||
<RadioButton Style="{DynamicResource RadioGroupItemSingle}" Content="取消" x:Name="AdminCancelButton" Click="AdminCancelButton_Click" />
|
||||
<hc:ButtonGroup Margin="30,0,0,0" Orientation="Vertical" Style="{StaticResource ButtonGroupSolid}">
|
||||
<RadioButton Content="确定" IsChecked="True" x:Name="AdminOkButton" Click="AdminOkButton_Click"/>
|
||||
</hc:ButtonGroup>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
@ -14,6 +14,7 @@ using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Animation;
|
||||
using System.Windows.Threading;
|
||||
using Views.JumpLong;
|
||||
using Views.JumpRope;
|
||||
using Wpf_AiSportsMicrospace;
|
||||
@ -39,13 +40,23 @@ namespace Wpf_AiSportsMicrospace
|
||||
{
|
||||
public static Uri loadingImage = new Uri("/Resources/Img/Album/1.gif", UriKind.Relative);
|
||||
public static Uri countDownGif = new Uri("/Resources/Img/gif/time_3.gif", UriKind.Relative);
|
||||
|
||||
private int _adminClickCount = 0;
|
||||
private readonly DispatcherTimer _resetTimer;
|
||||
private Main _mainWin => Application.Current.MainWindow as Main;
|
||||
|
||||
public Home()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// 初始化隐藏按钮点击计数重置定时器(3 秒无操作则重置计数)
|
||||
_resetTimer = new DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromSeconds(3)
|
||||
};
|
||||
_resetTimer.Tick += (s, e) =>
|
||||
{
|
||||
_adminClickCount = 0;
|
||||
_resetTimer.Stop();
|
||||
};
|
||||
string projectRoot = Path.Combine(AppContext.BaseDirectory, @"..\..\..");
|
||||
string albumPath = Path.Combine(projectRoot, "Resources", "Img");
|
||||
|
||||
@ -161,5 +172,77 @@ namespace Wpf_AiSportsMicrospace
|
||||
var mainWin = Application.Current.MainWindow as Main;
|
||||
mainWin!.ShowCountDownAnimation();
|
||||
}
|
||||
|
||||
// 隐藏按钮点击处理:连续点击五次显示内嵌密码弹窗
|
||||
private void HiddenAdminButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_adminClickCount++;
|
||||
// 每次点击重启计时器
|
||||
_resetTimer.Stop();
|
||||
_resetTimer.Start();
|
||||
|
||||
if (_adminClickCount >= 5)
|
||||
{
|
||||
_resetTimer.Stop();
|
||||
_adminClickCount = 0;
|
||||
|
||||
// 显示内嵌密码弹窗
|
||||
AdminPasswordBox.Password = string.Empty;
|
||||
AdminDialogGrid.Visibility = Visibility.Visible;
|
||||
AdminPasswordBox.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
// 密码弹窗:确定按钮
|
||||
private void AdminOkButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var entered = AdminPasswordBox.Password ?? string.Empty;
|
||||
if (entered == "8888")
|
||||
{
|
||||
AdminDialogGrid.Visibility = Visibility.Collapsed;
|
||||
// 密码正确,打开管理员页面(已有 AdminWindow 或按需改为导航)
|
||||
try
|
||||
{
|
||||
var mainWin = Application.Current.MainWindow as Main;
|
||||
mainWin.SwitchPageWithMaskAnimation(new LongSttting(), true);
|
||||
//var adminWin = new Views.AdminWindow();
|
||||
//adminWin.Owner = Window.GetWindow(this);
|
||||
//adminWin.Show();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show("密码正确");
|
||||
|
||||
Debug.WriteLine($"打开管理员页面异常: {ex.Message}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("密码错误", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
AdminPasswordBox.Password = string.Empty;
|
||||
AdminPasswordBox.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
// 密码弹窗:取消按钮
|
||||
private void AdminCancelButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
AdminDialogGrid.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
// 在 PasswordBox 按 Enter 等同于确定,按 Esc 等同于取消
|
||||
private void AdminPasswordBox_KeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.Enter)
|
||||
{
|
||||
AdminOkButton_Click(sender, e);
|
||||
e.Handled = true;
|
||||
}
|
||||
else if (e.Key == Key.Escape)
|
||||
{
|
||||
AdminCancelButton_Click(sender, e);
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
85
Wpf_AiSportsMicrospace/Views/Setting/LongSetting.xaml
Normal file
85
Wpf_AiSportsMicrospace/Views/Setting/LongSetting.xaml
Normal file
@ -0,0 +1,85 @@
|
||||
<UserControl x:Class="Wpf_AiSportsMicrospace.Views.LongSttting"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:Wpf_AiSportsMicrospace.MyUserControl"
|
||||
xmlns:hc="https://handyorg.github.io/handycontrol"
|
||||
Loaded="Window_Loaded"
|
||||
mc:Ignorable="d" Width="1920" Height="1080">
|
||||
<Grid>
|
||||
<Image x:Name="videoImage" Stretch="Uniform" />
|
||||
<!-- 背景网格,用于显示坐标参考 -->
|
||||
<Canvas x:Name="MainCanvas" >
|
||||
<!-- 网格线 -->
|
||||
<Canvas.Resources>
|
||||
<DrawingBrush x:Key="GridBackground" Viewport="0,0,50,50" ViewportUnits="Absolute" TileMode="Tile">
|
||||
<DrawingBrush.Drawing>
|
||||
<DrawingGroup>
|
||||
<GeometryDrawing Brush="White">
|
||||
<GeometryDrawing.Geometry>
|
||||
<RectangleGeometry Rect="0,0,50,50"/>
|
||||
</GeometryDrawing.Geometry>
|
||||
</GeometryDrawing>
|
||||
<GeometryDrawing>
|
||||
<GeometryDrawing.Pen>
|
||||
<Pen Brush="LightGray" Thickness="0.5"/>
|
||||
</GeometryDrawing.Pen>
|
||||
<GeometryDrawing.Geometry>
|
||||
<GeometryGroup>
|
||||
<LineGeometry StartPoint="0,0" EndPoint="0,50"/>
|
||||
<LineGeometry StartPoint="0,0" EndPoint="50,0"/>
|
||||
</GeometryGroup>
|
||||
</GeometryDrawing.Geometry>
|
||||
</GeometryDrawing>
|
||||
</DrawingGroup>
|
||||
</DrawingBrush.Drawing>
|
||||
</DrawingBrush>
|
||||
</Canvas.Resources>
|
||||
|
||||
<!--<Canvas.Background>
|
||||
<StaticResource ResourceKey="GridBackground"/>
|
||||
</Canvas.Background>-->
|
||||
|
||||
<!-- 可拖动的点 -->
|
||||
<Ellipse x:Name="TopPoint1" Width="20" Height="20" Fill="Red" Cursor="Hand"
|
||||
Canvas.Left="245" Canvas.Top="741" Tag="TopPoint1"/>
|
||||
<Ellipse x:Name="TopPoint2" Width="20" Height="20" Fill="Red" Cursor="Hand"
|
||||
Canvas.Left="1498" Canvas.Top="730" Tag="TopPoint2"/>
|
||||
<Ellipse x:Name="TopPoint3" Width="20" Height="20" Fill="Red" Cursor="Hand"
|
||||
Canvas.Left="1689" Canvas.Top="724" Tag="TopPoint3"/>
|
||||
|
||||
<Ellipse x:Name="BottomPoint1" Width="20" Height="20" Fill="Blue" Cursor="Hand"
|
||||
Canvas.Left="191" Canvas.Top="918" Tag="BottomPoint1"/>
|
||||
<Ellipse x:Name="BottomPoint2" Width="20" Height="20" Fill="Blue" Cursor="Hand"
|
||||
Canvas.Left="1516" Canvas.Top="918" Tag="BottomPoint2"/>
|
||||
<Ellipse x:Name="BottomPoint3" Width="20" Height="20" Fill="Blue" Cursor="Hand"
|
||||
Canvas.Left="1722" Canvas.Top="909" Tag="BottomPoint3"/>
|
||||
|
||||
<!-- 坐标显示标签 -->
|
||||
<hc:Tag ShowCloseButton="False" IsSelected="True" x:Name="CoordinateDisplay" Content="你是"
|
||||
Padding="18,0" FontSize="14" Visibility="Visible"/>
|
||||
</Canvas>
|
||||
|
||||
<!-- 控制面板 -->
|
||||
<StackPanel HorizontalAlignment="Right" VerticalAlignment="Top" Margin="20" Width="200">
|
||||
<Border Background="#F0F0F0" Padding="15" CornerRadius="8">
|
||||
<StackPanel>
|
||||
<TextBlock Text="跳远点编辑器" FontSize="16" FontWeight="Bold" Margin="0,0,0,10"/>
|
||||
|
||||
<TextBlock Text="红色点:上边界点" Foreground="Red" FontWeight="Bold"/>
|
||||
<TextBlock Text="蓝色点:下边界点" Foreground="Blue" FontWeight="Bold" Margin="0,0,0,10"/>
|
||||
|
||||
<Button x:Name="LoadPointsButton" Content="加载点数据" Click="LoadPointsButton_Click"
|
||||
Margin="0,5" Height="30" Background="#4CAF50" Foreground="White"/>
|
||||
<Button x:Name="SavePointsButton" Content="保存点数据" Click="SavePointsButton_Click"
|
||||
Margin="0,5" Height="30" Background="#2196F3" Foreground="White"/>
|
||||
<Button x:Name="ResetPointsButton" Content="重置为默认" Click="ResetPointsButton_Click"
|
||||
Margin="0,5" Height="30" Background="#FF9800" Foreground="White"/>
|
||||
|
||||
<TextBlock x:Name="StatusText" Text="就绪" Margin="0,10,0,0" TextWrapping="Wrap"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
415
Wpf_AiSportsMicrospace/Views/Setting/LongSetting.xaml.cs
Normal file
415
Wpf_AiSportsMicrospace/Views/Setting/LongSetting.xaml.cs
Normal file
@ -0,0 +1,415 @@
|
||||
using AiSportsMicrospaceDB.DBContext;
|
||||
using AiSportsMicrospaceDB.Entities;
|
||||
using Emgu.CV.Reg;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
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 LongSttting : UserControl
|
||||
{
|
||||
private bool _isDragging = false;
|
||||
private Ellipse _draggedEllipse;
|
||||
private System.Windows.Point _dragStartPoint;
|
||||
private IHumanPredictor _humanPredictor;
|
||||
private IObjectDetector _objectDetector;
|
||||
private HumanGraphicsRenderer _humanGraphicsRenderer;
|
||||
private readonly List<SportDescriptor> _sports;
|
||||
private SportBase _sport;
|
||||
private readonly SportDetectionQueue _detectQueue;
|
||||
|
||||
private WriteableBitmap _videoBitmap;
|
||||
private int _lastFrameNumber = -1;
|
||||
|
||||
|
||||
public LongSttting()
|
||||
{
|
||||
InitializeComponent();
|
||||
SetupDragEvents();
|
||||
LoadPointsFromDatabase();
|
||||
var _webcamClient = WebcamClient.CreateRTSP("172.17.30.64", "admin", "yd708090", 554u);
|
||||
|
||||
//处理抽帧回调
|
||||
_webcamClient.OnExtractFrame += this.OnFrameExtracted;
|
||||
_webcamClient.StartExtract();//开始抽帧
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private async void OnFrameExtracted(VideoFrame frame)
|
||||
{
|
||||
if (frame == null) return;
|
||||
|
||||
// 跳帧:每秒只渲染 10~15 帧,降低 CPU 占用
|
||||
if (_lastFrameNumber != -1 && frame.Number - _lastFrameNumber < 2) return;
|
||||
_lastFrameNumber = (int)frame.Number;
|
||||
|
||||
//获得帧二进制流,保存图像、人体识别竺
|
||||
var buffer = frame.GetImageBuffer(Yztob.AiSports.Sensors.Things.ImageFormat.Jpeg).ToArray();
|
||||
//await File.WriteAllBytesAsync($"./temps/{frame.Number}.jpg", buffer);
|
||||
|
||||
// === 显示到 WPF ===
|
||||
BitmapImage bitmap = null;
|
||||
await Task.Run(() =>
|
||||
{
|
||||
using var ms = new MemoryStream(buffer);
|
||||
bitmap = new BitmapImage();
|
||||
bitmap.BeginInit();
|
||||
bitmap.CacheOption = BitmapCacheOption.OnLoad;
|
||||
bitmap.StreamSource = ms;
|
||||
bitmap.EndInit();
|
||||
bitmap.Freeze(); // 跨线程安全
|
||||
});
|
||||
|
||||
// UI 线程显示
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
if (videoImage == null) return;
|
||||
|
||||
if (_videoBitmap == null ||
|
||||
_videoBitmap.PixelWidth != bitmap.PixelWidth ||
|
||||
_videoBitmap.PixelHeight != bitmap.PixelHeight)
|
||||
{
|
||||
_videoBitmap = new WriteableBitmap(bitmap.PixelWidth, bitmap.PixelHeight,
|
||||
96, 96, PixelFormats.Bgra32, null);
|
||||
videoImage.Source = _videoBitmap;
|
||||
}
|
||||
|
||||
_videoBitmap.Lock();
|
||||
bitmap.CopyPixels(new Int32Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight),
|
||||
_videoBitmap.BackBuffer,
|
||||
_videoBitmap.BackBufferStride * bitmap.PixelHeight,
|
||||
_videoBitmap.BackBufferStride);
|
||||
_videoBitmap.AddDirtyRect(new Int32Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight));
|
||||
_videoBitmap.Unlock();
|
||||
});
|
||||
|
||||
//var actualPositions = new List<(double X, double Y)>
|
||||
//{
|
||||
// (290, 510),
|
||||
// (500, 700),
|
||||
// (810, 710),
|
||||
// (120, 880),
|
||||
// (350, 880),
|
||||
// (660, 880)
|
||||
//};
|
||||
|
||||
////判断是否出圈
|
||||
//if (configService.ConfigDic.TryGetValue("JumpRope", out var obj) && obj is ConfigSet cfg)
|
||||
//{
|
||||
// for (int i = 0; i < actualPositions.Count && i < cfg.Points.Count; i++)
|
||||
// {
|
||||
// var (ax, ay) = actualPositions[i];
|
||||
// var pointCfg = cfg.Points[i];
|
||||
|
||||
// if (!IsInsideCircle(ax, ay, pointCfg))
|
||||
// {
|
||||
// Console.WriteLine($"⚠️ 学生{i + 1} 已经出圈!(坐标 {ax},{ay})");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Console.WriteLine($"✅ 学生{i + 1} 在圈内。");
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
//可以进一步进行人体识别等
|
||||
//var humanResult = await Task.Run(() => _humanPredictor.Predicting(buffer, frame.Number));
|
||||
|
||||
//var human = humanResult?.Humans?.FirstOrDefault();
|
||||
//_detectQueue.Enqueue(frame.Number, human, null);
|
||||
}
|
||||
|
||||
private void SetupDragEvents()
|
||||
{
|
||||
// 为所有点添加鼠标事件
|
||||
var points = new[] { TopPoint1, TopPoint2, TopPoint3, BottomPoint1, BottomPoint2, BottomPoint3 };
|
||||
|
||||
foreach (var point in points)
|
||||
{
|
||||
point.MouseLeftButtonDown += Point_MouseLeftButtonDown;
|
||||
point.MouseMove += Point_MouseMove;
|
||||
point.MouseLeftButtonUp += Point_MouseLeftButtonUp;
|
||||
point.MouseEnter += Point_MouseEnter;
|
||||
point.MouseLeave += Point_MouseLeave;
|
||||
}
|
||||
}
|
||||
|
||||
private async void LoadPointsFromDatabase()
|
||||
{
|
||||
try
|
||||
{
|
||||
var app = (App)Application.Current;
|
||||
using var scope = App.AppHost.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
var pointsData = await db.JumpLongPoints.FirstOrDefaultAsync();
|
||||
if (pointsData != null)
|
||||
{
|
||||
// 加载 TopPoint1
|
||||
var topPoint1 = pointsData.TopPoint1;
|
||||
Canvas.SetLeft(TopPoint1, topPoint1.X - 10); // 减去半径以居中
|
||||
Canvas.SetTop(TopPoint1, topPoint1.Y - 10);
|
||||
|
||||
// 加载 TopPoint2
|
||||
var topPoint2 = pointsData.TopPoint2;
|
||||
Canvas.SetLeft(TopPoint2, topPoint2.X - 10);
|
||||
Canvas.SetTop(TopPoint2, topPoint2.Y - 10);
|
||||
|
||||
// 加载 TopPoint3
|
||||
var topPoint3 = pointsData.TopPoint3;
|
||||
Canvas.SetLeft(TopPoint3, topPoint3.X - 10);
|
||||
Canvas.SetTop(TopPoint3, topPoint3.Y - 10);
|
||||
|
||||
// 加载 BottomPoint1
|
||||
var bottomPoint1 = pointsData.BottomPoint1;
|
||||
Canvas.SetLeft(BottomPoint1, bottomPoint1.X - 10);
|
||||
Canvas.SetTop(BottomPoint1, bottomPoint1.Y - 10);
|
||||
|
||||
// 加载 BottomPoint2
|
||||
var bottomPoint2 = pointsData.BottomPoint2;
|
||||
Canvas.SetLeft(BottomPoint2, bottomPoint2.X - 10);
|
||||
Canvas.SetTop(BottomPoint2, bottomPoint2.Y - 10);
|
||||
|
||||
// 加载 BottomPoint3
|
||||
var bottomPoint3 = pointsData.BottomPoint3;
|
||||
Canvas.SetLeft(BottomPoint3, bottomPoint3.X - 10);
|
||||
Canvas.SetTop(BottomPoint3, bottomPoint3.Y - 10);
|
||||
|
||||
UpdateStatus("点数据加载成功");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UpdateStatus($"加载点数据失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
//保存点数据到数据库
|
||||
private void SavePointsToDatabase()
|
||||
{
|
||||
try
|
||||
{
|
||||
var app = (App)Application.Current;
|
||||
using var scope = App.AppHost.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
var pointsData = db.JumpLongPoints.FirstOrDefault();
|
||||
if (pointsData == null)
|
||||
{
|
||||
pointsData = new JumpLongPoints { Id = 1 };
|
||||
db.JumpLongPoints.Add(pointsData);
|
||||
}
|
||||
|
||||
// 保存所有点的位置
|
||||
pointsData.TopPoint1 = new AiSportsMicrospaceDB.Entities.Point
|
||||
{
|
||||
X = Canvas.GetLeft(TopPoint1) + 10,
|
||||
Y = Canvas.GetTop(TopPoint1) + 10
|
||||
};
|
||||
|
||||
pointsData.TopPoint2 = new AiSportsMicrospaceDB.Entities.Point
|
||||
{
|
||||
X = Canvas.GetLeft(TopPoint2) + 10,
|
||||
Y = Canvas.GetTop(TopPoint2) + 10
|
||||
};
|
||||
|
||||
pointsData.TopPoint3 = new AiSportsMicrospaceDB.Entities.Point
|
||||
{
|
||||
X = Canvas.GetLeft(TopPoint3) + 10,
|
||||
Y = Canvas.GetTop(TopPoint3) + 10
|
||||
};
|
||||
|
||||
pointsData.BottomPoint1 = new AiSportsMicrospaceDB.Entities.Point
|
||||
{
|
||||
X = Canvas.GetLeft(BottomPoint1) + 10,
|
||||
Y = Canvas.GetTop(BottomPoint1) + 10
|
||||
};
|
||||
|
||||
pointsData.BottomPoint2 = new AiSportsMicrospaceDB.Entities.Point
|
||||
{
|
||||
X = Canvas.GetLeft(BottomPoint2) + 10,
|
||||
Y = Canvas.GetTop(BottomPoint2) + 10
|
||||
};
|
||||
|
||||
pointsData.BottomPoint3 = new AiSportsMicrospaceDB.Entities.Point
|
||||
{
|
||||
X = Canvas.GetLeft(BottomPoint3) + 10,
|
||||
Y = Canvas.GetTop(BottomPoint3) + 10
|
||||
};
|
||||
|
||||
db.SaveChanges();
|
||||
UpdateStatus("点数据保存成功");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UpdateStatus($"保存点数据失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region 鼠标事件处理
|
||||
|
||||
private void Point_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
_isDragging = true;
|
||||
_draggedEllipse = sender as Ellipse;
|
||||
_dragStartPoint = e.GetPosition(MainCanvas);
|
||||
_draggedEllipse.CaptureMouse();
|
||||
|
||||
// 提升点的Z索引,使其在拖动时显示在最前面
|
||||
Canvas.SetZIndex(_draggedEllipse, 100);
|
||||
}
|
||||
|
||||
private void Point_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (_isDragging && _draggedEllipse != null)
|
||||
{
|
||||
var currentPosition = e.GetPosition(MainCanvas);
|
||||
|
||||
// 计算新的位置
|
||||
double newX = currentPosition.X - 10; // 减去半径
|
||||
double newY = currentPosition.Y - 10;
|
||||
|
||||
// 限制在Canvas范围内
|
||||
newX = Math.Max(0, Math.Min(newX, MainCanvas.ActualWidth - 20));
|
||||
newY = Math.Max(0, Math.Min(newY, MainCanvas.ActualHeight - 20));
|
||||
|
||||
Canvas.SetLeft(_draggedEllipse, newX);
|
||||
Canvas.SetTop(_draggedEllipse, newY);
|
||||
|
||||
// 更新坐标显示
|
||||
UpdateCoordinateDisplay(currentPosition, _draggedEllipse.Tag.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private void Point_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (_isDragging)
|
||||
{
|
||||
_isDragging = false;
|
||||
_draggedEllipse.ReleaseMouseCapture();
|
||||
Canvas.SetZIndex(_draggedEllipse, 0); // 恢复Z索引
|
||||
_draggedEllipse = null;
|
||||
|
||||
// 隐藏坐标显示
|
||||
CoordinateDisplay.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
private void Point_MouseEnter(object sender, MouseEventArgs e)
|
||||
{
|
||||
var ellipse = sender as Ellipse;
|
||||
ellipse.Opacity = 0.8;
|
||||
|
||||
// 显示坐标提示
|
||||
var position = e.GetPosition(MainCanvas);
|
||||
UpdateCoordinateDisplay(position, ellipse.Tag.ToString());
|
||||
}
|
||||
|
||||
private void Point_MouseLeave(object sender, MouseEventArgs e)
|
||||
{
|
||||
var ellipse = sender as Ellipse;
|
||||
ellipse.Opacity = 1.0;
|
||||
|
||||
if (!_isDragging)
|
||||
{
|
||||
CoordinateDisplay.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateCoordinateDisplay(System.Windows.Point position, string pointName)
|
||||
{
|
||||
CoordinateDisplay.Content = $"{pointName}: ({position.X:F0}, {position.Y:F0})";
|
||||
Canvas.SetLeft(CoordinateDisplay, position.X + 10);
|
||||
Canvas.SetTop(CoordinateDisplay, position.Y + 10);
|
||||
CoordinateDisplay.Visibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 按钮事件处理
|
||||
|
||||
private void LoadPointsButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
LoadPointsFromDatabase();
|
||||
}
|
||||
|
||||
private void SavePointsButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
SavePointsToDatabase();
|
||||
}
|
||||
|
||||
private void ResetPointsButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var result = MessageBox.Show("确定要重置为默认点位置吗?", "确认重置",
|
||||
MessageBoxButton.YesNo, MessageBoxImage.Question);
|
||||
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
CreateDefaultPoints();
|
||||
LoadPointsFromDatabase();
|
||||
UpdateStatus("已重置为默认点位置");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void UpdateStatus(string message)
|
||||
{
|
||||
StatusText.Text = $"{DateTime.Now:HH:mm:ss} - {message}";
|
||||
}
|
||||
|
||||
private async void CreateDefaultPoints()
|
||||
{
|
||||
var app = (App)Application.Current;
|
||||
using var scope = App.AppHost.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
var pointsData = db.JumpLongPoints.FirstOrDefault();
|
||||
if (pointsData == null)
|
||||
{
|
||||
pointsData = new JumpLongPoints { Id = 1 };
|
||||
db.JumpLongPoints.Add(pointsData);
|
||||
}
|
||||
var defaultPoints = new JumpLongPoints
|
||||
{
|
||||
Id = 1,
|
||||
TopPoint1 = new AiSportsMicrospaceDB.Entities.Point { X = 245, Y = 741 },
|
||||
TopPoint2 = new AiSportsMicrospaceDB.Entities.Point { X = 1498, Y = 730 },
|
||||
TopPoint3 = new AiSportsMicrospaceDB.Entities.Point { X = 1689, Y = 724 },
|
||||
BottomPoint1 = new AiSportsMicrospaceDB.Entities.Point { X = 191, Y = 918 },
|
||||
BottomPoint2 = new AiSportsMicrospaceDB.Entities.Point { X = 1516, Y = 918 },
|
||||
BottomPoint3 = new AiSportsMicrospaceDB.Entities.Point { X = 1722, Y = 909 },
|
||||
};
|
||||
pointsData = defaultPoints;
|
||||
await db.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user