跳绳页面添加

This commit is contained in:
tanglong 2025-09-26 09:47:43 +08:00
parent fc8fd43196
commit ffa3ea7489
6 changed files with 177 additions and 29 deletions

View File

@ -28,6 +28,10 @@ namespace Wpf_AiSportsMicrospace.Common
IPointTracker _leftElbow;
IPointTracker _rightElbow;
WebcamClient _webcamClient;
private Point? _lastWrist = null; // 上一帧的手腕位置
private DateTime _lastActionTime = DateTime.MinValue; // 上次动作时间
private readonly TimeSpan _cooldown = TimeSpan.FromMilliseconds(800); // 动作冷却,避免误触发
public SportOperate()
{
@ -41,6 +45,7 @@ namespace Wpf_AiSportsMicrospace.Common
_leftElbow.Amplitude = 0.05f;
_rightElbow.Amplitude = 0.05f;
}
public WebcamClient CreateRTSP()
{
_webcamClient = WebcamClient.CreateRTSP("192.168.3.64", "admin", "yd708090", 554u);
@ -59,13 +64,18 @@ namespace Wpf_AiSportsMicrospace.Common
var rightElbowResult = _rightElbow.Tracking(human);
// 节流:每 300ms 最多更新一次 UI
if ((DateTime.Now - _lastSlideTime).TotalMilliseconds < 500) return 0;
_lastSlideTime = DateTime.Now;
//if ((DateTime.Now - _lastSlideTime).TotalMilliseconds < 500) return 0;
//_lastSlideTime = DateTime.Now;
// 根据手势结果选择滑动方向
if (leftResult != 0 && leftElbowResult != 0) return 1;
if (rightResult != 0 & rightElbowResult != 0) return 2;
if (rightResult != 0 & rightElbowResult != 0)
{
var wrist = human.Keypoints.Where(x => x.Name == "right_wrist").FirstOrDefault();
var elbow = human.Keypoints.Where(x => x.Name == "right_elbow").FirstOrDefault();
if (wrist == null || elbow == null) return 0;
return RecognizeRightHandGesture(new Point(wrist.X, wrist.Y), new Point(elbow.X, elbow.Y));
}
return 0;
}
@ -84,5 +94,46 @@ namespace Wpf_AiSportsMicrospace.Common
return 0;
}
public int RecognizeRightHandGesture(Point wrist, Point elbow)
{
// 判断举手:手腕在肘部之上,且垂直距离超过一定阈值
if (wrist.Y + 40 < elbow.Y) // 手腕比肘高 40 像素以上
{
if (CheckCooldown())
return 3; // 举手
}
// 需要至少两帧来判断水平移动方向
if (_lastWrist != null)
{
double dx = wrist.X - _lastWrist.Value.X; // 水平位移
double dy = Math.Abs(wrist.Y - _lastWrist.Value.Y);
// 要求水平位移明显大于垂直位移,且超过一定阈值
if (Math.Abs(dx) > 30 && dy < 40)
{
if (CheckCooldown())
{
if (dx > 0)
return 2; // 右挥手
else
return 1; // 左挥手
}
}
}
_lastWrist = wrist;
return 0;
}
private bool CheckCooldown()
{
if (DateTime.Now - _lastActionTime > _cooldown)
{
_lastActionTime = DateTime.Now;
return true;
}
return false;
}
}
}

View File

@ -15,6 +15,7 @@ using System.Windows.Media;
using System.Windows.Media.Animation;
using Wpf_AiSportsMicrospace.Common;
using Wpf_AiSportsMicrospace.MyUserControl;
using Wpf_AiSportsMicrospace.Views;
using Yunzhi.Database;
using Yztob.AiSports.Inferences.Abstractions;
using Yztob.AiSports.Postures;
@ -96,14 +97,32 @@ namespace Wpf_AiSportsMicrospace
if (item.ImageUri.ToString().EndsWith("1.jpg"))
{
// 跳转到页面1
Dispatcher.BeginInvoke(new Action(() =>
{
GroupJumpRope groupJumpRope = new GroupJumpRope();
groupJumpRope.Owner = Application.Current.MainWindow;
groupJumpRope.Show();
}));
}
else if (item.ImageUri.ToString().EndsWith("2.jpg"))
{
// 跳转到页面2
Dispatcher.BeginInvoke(new Action(() =>
{
GroupJumpRope groupJumpRope = new GroupJumpRope();
groupJumpRope.Owner = Application.Current.MainWindow;
groupJumpRope.Show();
}));
}
else if (item.ImageUri.ToString().EndsWith("3.jpg"))
{
// 跳转到页面3
Dispatcher.BeginInvoke(new Action(() =>
{
GroupJumpRope groupJumpRope = new GroupJumpRope();
groupJumpRope.Owner = Application.Current.MainWindow;
groupJumpRope.Show();
}));
}
}
@ -148,33 +167,33 @@ namespace Wpf_AiSportsMicrospace
if (human == null) return;
//检测挥手动作
var wavingaction = _sportOperate.VerifyWavingAction(human);
// 启动进度条动画;
//SlideCoverFlow(coverFlow.StartSelectedProgress);
////检测挥手动作
//var wavingAction = _sportOperate.VerifyWavingAction(human);
//// 根据手势结果选择滑动方向
//if (wavingAction == 1)
//{
// SlideCoverFlow(coverFlow.SlideRight);
// return;
//}
//if (wavingAction == 2)
//{
// SlideCoverFlow(coverFlow.SlideLeft);
// return;
//}
//检测举手动作
var liftHandAction = _sportOperate.VerifyLiftHandAction(human);
// 根据手势结果
if (liftHandAction == 1)
switch (wavingaction)
{
// 启动进度条动画;
Dispatcher.BeginInvoke(() => coverFlow.StartSelectedProgress());
case 1:
Dispatcher.BeginInvoke(() => coverFlow.SlideLeft());
break;
case 2:
Dispatcher.BeginInvoke(() => coverFlow.SlideRight());
break;
case 3:
Dispatcher.BeginInvoke(() => coverFlow.StartSelectedProgress());
break;
default:
break;
}
////检测举手动作
//var liftHandAction = _sportOperate.VerifyLiftHandAction(human);
//// 根据手势结果
//if (liftHandAction == 1)
//{
// // 启动进度条动画;
// Dispatcher.BeginInvoke(() => coverFlow.StartSelectedProgress());
//}
}
catch (Exception ex)
{

View File

@ -0,0 +1,12 @@
<Window x:Class="Wpf_AiSportsMicrospace.Views.GroupJumpRope"
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.Views"
mc:Ignorable="d"
Title="多人跳绳" Height="450" Width="800">
<Grid>
</Grid>
</Window>

View File

@ -0,0 +1,27 @@
using System;
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.Imaging;
using System.Windows.Shapes;
namespace Wpf_AiSportsMicrospace.Views
{
/// <summary>
/// GroupJumpRope.xaml 的交互逻辑
/// </summary>
public partial class GroupJumpRope : Window
{
public GroupJumpRope()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,12 @@
<Window x:Class="Wpf_AiSportsMicrospace.Views.MusicJumpRope"
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.Views"
mc:Ignorable="d"
Title="MusicJumpRope" Height="450" Width="800">
<Grid>
</Grid>
</Window>

View File

@ -0,0 +1,27 @@
using System;
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.Imaging;
using System.Windows.Shapes;
namespace Wpf_AiSportsMicrospace.Views
{
/// <summary>
/// MusicJumpRope.xaml 的交互逻辑
/// </summary>
public partial class MusicJumpRope : Window
{
public MusicJumpRope()
{
InitializeComponent();
}
}
}