提交
This commit is contained in:
parent
5aa415bb9a
commit
d5733d08f9
@ -1,6 +1,7 @@
|
||||
using AiSportsMicrospaceDB.DBContext;
|
||||
using Common;
|
||||
using HandyControl.Controls;
|
||||
using Microsoft.EntityFrameworkCore.Storage.Json;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using SportExpand;
|
||||
using System;
|
||||
@ -74,17 +75,17 @@ namespace Wpf_AiSportsMicrospace.Common
|
||||
/// <summary>
|
||||
/// 验证右手动作(右手举手优先,然后左右挥手)
|
||||
/// </summary>
|
||||
public int VerifyRightWavingAction(List<Human> humans)
|
||||
public int VerifyRightWavingAction(List<Human> humans)
|
||||
{
|
||||
if (humans == null || humans.Count == 0)
|
||||
return (int)WavingAction.None;
|
||||
|
||||
// 先找到控制点区域的人
|
||||
Human target = null;
|
||||
double cx = AppSettings.ControlPoint.X ;
|
||||
double cy = AppSettings.ControlPoint.Y ;
|
||||
double halfW = AppSettings.AreaSize.X ;
|
||||
double halfH = AppSettings.AreaSize.Y ;
|
||||
double cx = AppSettings.ControlPoint.X;
|
||||
double cy = AppSettings.ControlPoint.Y;
|
||||
double halfW = AppSettings.AreaSize.X;
|
||||
double halfH = AppSettings.AreaSize.Y;
|
||||
|
||||
for (int i = 0; i < humans.Count; i++)
|
||||
{
|
||||
@ -93,7 +94,7 @@ namespace Wpf_AiSportsMicrospace.Common
|
||||
{
|
||||
if (k.Name == "right_ankle")
|
||||
{
|
||||
double x = k.X;
|
||||
double x = k.X;
|
||||
double y = k.Y;
|
||||
if (x >= cx - halfW && x <= cx + halfW &&
|
||||
y >= cy - halfH && y <= cy + halfH)
|
||||
@ -199,20 +200,12 @@ namespace Wpf_AiSportsMicrospace.Common
|
||||
for (int i = 0; i < humans.Count; i++)
|
||||
{
|
||||
var h = humans[i];
|
||||
foreach (var k in h.Keypoints)
|
||||
|
||||
if (IsAnyFootInCircle(h, cx, cy, halfW, halfH))
|
||||
{
|
||||
if (k.Name == "right_ankle")
|
||||
{
|
||||
double x = k.X;
|
||||
double y = k.Y;
|
||||
if (x >= cx - halfW && x <= cx + halfW &&
|
||||
y >= cy - halfH && y <= cy + halfH)
|
||||
{
|
||||
target = h;
|
||||
break;
|
||||
}
|
||||
}
|
||||
target = h;
|
||||
}
|
||||
|
||||
if (target != null) break;
|
||||
}
|
||||
|
||||
@ -222,7 +215,6 @@ namespace Wpf_AiSportsMicrospace.Common
|
||||
// ---- 右手举手优先 ----
|
||||
int rightHandAction = DetectLeftHandRaise(target);
|
||||
return rightHandAction;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -232,9 +224,28 @@ namespace Wpf_AiSportsMicrospace.Common
|
||||
var ruleLeft = RaiseHand.RaiseLeftHand();
|
||||
bool pass = calculator.Calculating(human, ruleLeft);
|
||||
|
||||
|
||||
return pass ? (int)WavingAction.Raising : (int)WavingAction.None;
|
||||
|
||||
return pass ? (int)WavingAction.Raising : (int)WavingAction.None;
|
||||
|
||||
}
|
||||
public bool IsAnyFootInCircle(Human h, double cx, double cy, double halfW, double halfH)
|
||||
{
|
||||
foreach (var k in h.Keypoints)
|
||||
{
|
||||
if (k.Name != "right_ankle" && k.Name != "left_ankle")
|
||||
continue;
|
||||
|
||||
double x = k.X;
|
||||
double y = k.Y;
|
||||
|
||||
if (Math.Abs(x - cx) <= halfW &&
|
||||
Math.Abs(y - cy) <= halfH)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,10 +55,10 @@ namespace Dto
|
||||
public MusicJumpRopeContext()
|
||||
{
|
||||
CirclePositions = new List<(double XNorm, double YNorm)>
|
||||
{
|
||||
(0.50, 0.88),
|
||||
(0.78, 0.88),
|
||||
};
|
||||
{
|
||||
(0.50, 0.88),
|
||||
(0.78, 0.88),
|
||||
};
|
||||
|
||||
MusicBeatsDic = MusicBeats["1"].GroupBy(b => (int)Math.Ceiling(b) - 1).ToDictionary(g => g.Key, g => g.ToList());
|
||||
|
||||
|
||||
@ -10,6 +10,7 @@ using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Threading;
|
||||
using Views.JumpLong;
|
||||
using Views.JumpRope;
|
||||
using Views.SquatFu;
|
||||
using Wpf_AiSportsMicrospace.Common;
|
||||
@ -173,7 +174,8 @@ namespace Wpf_AiSportsMicrospace
|
||||
}
|
||||
else
|
||||
{
|
||||
var newPage = new TrainingRecords();
|
||||
//var newPage = new TrainingRecords();
|
||||
var newPage = new StandingLeap();
|
||||
mainWin?.SwitchPageWithMaskAnimation(newPage, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using AiSportsMicrospaceDB.DBContext;
|
||||
using AiSportsMicrospaceDB.Entities;
|
||||
using Common;
|
||||
using Dto;
|
||||
using Enum;
|
||||
@ -49,6 +50,8 @@ namespace Views.JumpLong
|
||||
private MediaPlayer _mediaPlayer = new MediaPlayer();
|
||||
private readonly SportDetectionQueue _detectQueue;
|
||||
|
||||
private JumpLongPoints _Points;
|
||||
|
||||
private int _sportType = 0; // 0:未开始 1:运动中 2:运动结束展示排行榜
|
||||
|
||||
#endregion
|
||||
@ -66,7 +69,6 @@ namespace Views.JumpLong
|
||||
|
||||
_sport = SportBase.Create("standing-long-jump");
|
||||
_sport.OnTicked += this.OnSportTick;
|
||||
_mainWin.HumanFrameUpdated += this.OnFrameUpdated;
|
||||
_measureApparatus = new ApparatusLongJumpDelineation();
|
||||
_measureApparatus.MeasureLength = 300;
|
||||
var _isCalibrated = this.ReactangleCalibrating(1920, 1080);
|
||||
@ -79,6 +81,14 @@ namespace Views.JumpLong
|
||||
{
|
||||
// 播放音乐
|
||||
PlayMusic("raisehand.mp3");
|
||||
|
||||
var app = (App)Application.Current;
|
||||
using var scope = App.AppHost.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
|
||||
_Points = db.JumpLongPoints.FirstOrDefault(x => x.Code == AppSettings.Code);
|
||||
|
||||
_mainWin.HumanFrameUpdated += OnFrameUpdated;
|
||||
}
|
||||
|
||||
|
||||
@ -279,21 +289,6 @@ namespace Views.JumpLong
|
||||
// 关闭跳远抽帧线程
|
||||
}
|
||||
|
||||
//关闭成绩展示 显示跳远页面
|
||||
private void closRope()
|
||||
{
|
||||
//关闭动画
|
||||
//var fadeInAnimation = new DoubleAnimation
|
||||
//{
|
||||
// From = 1,
|
||||
// To = 0,
|
||||
// Duration = TimeSpan.FromSeconds(1)
|
||||
//};
|
||||
// RankingGrid.BeginAnimation(UIElement.OpacityProperty, fadeInAnimation);
|
||||
RankingGrid.Opacity = 0;
|
||||
_sportType = 0;
|
||||
PlayMusic("raisehand.mp3");
|
||||
}
|
||||
private bool ReactangleCalibrating(int frameWidth, int frameHeight)
|
||||
{
|
||||
|
||||
@ -429,23 +424,16 @@ namespace Views.JumpLong
|
||||
if (rightAnkle == null)
|
||||
continue;
|
||||
|
||||
//double xNorm = rightAnkle.X / 1920;
|
||||
//double yNorm = rightAnkle.Y / 1080;
|
||||
|
||||
|
||||
var app = (App)Application.Current;
|
||||
using var scope = App.AppHost.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
var points = db.JumpLongPoints.FirstOrDefault(x => x.Code == AppSettings.Code);
|
||||
|
||||
// 检测起跳区域的人
|
||||
|
||||
var isinx = (rightAnkle.X < points.TopPoint3.X && rightAnkle.X > points.TopPoint2.X) || (rightAnkle.X < points.BottomPoint3.X && rightAnkle.X > points.BottomPoint2.X);
|
||||
if (points.TopPoint3.X < points.TopPoint2.X)
|
||||
var isinx = (rightAnkle.X < _Points.TopPoint3.X && rightAnkle.X > _Points.TopPoint2.X) || (rightAnkle.X < _Points.BottomPoint3.X && rightAnkle.X > _Points.BottomPoint2.X);
|
||||
if (_Points.TopPoint3.X < _Points.TopPoint2.X)
|
||||
{
|
||||
isinx = (rightAnkle.X > points.TopPoint3.X && rightAnkle.X < points.TopPoint2.X) || (rightAnkle.X > points.BottomPoint3.X && rightAnkle.X < points.BottomPoint2.X);
|
||||
isinx = (rightAnkle.X > _Points.TopPoint3.X && rightAnkle.X < _Points.TopPoint2.X) || (rightAnkle.X > _Points.BottomPoint3.X && rightAnkle.X < _Points.BottomPoint2.X);
|
||||
}
|
||||
var isiny = (rightAnkle.Y > points.TopPoint3.Y && rightAnkle.X < points.BottomPoint3.Y) || (rightAnkle.Y < points.TopPoint2.Y && rightAnkle.X > points.BottomPoint2.Y);
|
||||
var isiny = (rightAnkle.Y > _Points.TopPoint3.Y && rightAnkle.X < _Points.BottomPoint3.Y) || (rightAnkle.Y < _Points.TopPoint2.Y && rightAnkle.X > _Points.BottomPoint2.Y);
|
||||
if (!isinx || !isiny) continue;
|
||||
|
||||
|
||||
|
||||
@ -84,8 +84,6 @@ namespace Wpf_AiSportsMicrospace.Views
|
||||
using var scope = App.AppHost.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
var cfg = await db.GroupPoints.FirstOrDefaultAsync(x => x.Code == AppSettings.Code);
|
||||
//var pointlist = JsonSerializer.Deserialize<List<(double, double)>>(cfg!.PointsJson);
|
||||
|
||||
List<(double XNorm, double YNorm)> pointlist = new List<(double XNorm, double YNorm)>();
|
||||
|
||||
var points = new[] { cfg.Point1, cfg.Point2, cfg.Point3,
|
||||
@ -101,6 +99,8 @@ namespace Wpf_AiSportsMicrospace.Views
|
||||
}
|
||||
_groupJumpRopeContext.CirclePositions = pointlist;
|
||||
|
||||
_mainWin.HumanFrameUpdated += OnHumanFrameUpdated;
|
||||
|
||||
DrawCirclesWithText();
|
||||
|
||||
// 播放音乐
|
||||
@ -350,90 +350,6 @@ namespace Wpf_AiSportsMicrospace.Views
|
||||
_mainWin.WebcamClient.StartExtract();
|
||||
}
|
||||
|
||||
private DateTime? _raiseStartTime;
|
||||
private bool _firstHandTriggered;
|
||||
private int _lastCountdownSecond = 3;
|
||||
private DateTime? _countdownStartTime;
|
||||
public int DetectRightHandRaise(Human human)
|
||||
{
|
||||
|
||||
var calculator = PostureCalculate.CreateCalculator();
|
||||
var rule = RaiseHand.RaiseRightHand();
|
||||
var pass = calculator.Calculating(human, rule);
|
||||
|
||||
const double holdDuration = 1; // 持续时间(秒)
|
||||
const int countdownSeconds = 3; // 倒计时长度
|
||||
|
||||
// ---------- 第一步:持续举手触发倒计时 ----------
|
||||
if (!_firstHandTriggered)
|
||||
{
|
||||
if (pass)
|
||||
{
|
||||
_raiseStartTime ??= DateTime.Now;
|
||||
var holdElapsed = (DateTime.Now - _raiseStartTime.Value).TotalSeconds;
|
||||
if (holdElapsed >= holdDuration)
|
||||
{
|
||||
// 举手达到指定时间,启动倒计时
|
||||
_firstHandTriggered = true;
|
||||
_countdownStartTime = DateTime.Now;
|
||||
_lastCountdownSecond = countdownSeconds;
|
||||
return (int)WavingAction.FirstHand;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 手放下,重置举手开始时间
|
||||
_raiseStartTime = DateTime.Now;
|
||||
}
|
||||
|
||||
// 没有任何中心区域内的人举手
|
||||
return (int)WavingAction.None;
|
||||
}
|
||||
|
||||
// ---------- 第二步:倒计时逻辑 ----------
|
||||
var countdownElapsed = (DateTime.Now - _countdownStartTime.Value).TotalSeconds;
|
||||
int currentSecond = countdownSeconds - (int)Math.Floor(countdownElapsed);
|
||||
|
||||
if (currentSecond > 0 && currentSecond != _lastCountdownSecond)
|
||||
{
|
||||
_lastCountdownSecond = currentSecond;
|
||||
Console.WriteLine($"倒计时:{currentSecond}");
|
||||
return (int)WavingAction.Raising; // 倒计时中
|
||||
}
|
||||
|
||||
if (countdownElapsed >= countdownSeconds)
|
||||
{
|
||||
ResetRaiseState();
|
||||
return (int)WavingAction.RaiseHand; // 举手完成
|
||||
}
|
||||
|
||||
return (int)WavingAction.Raising;
|
||||
}
|
||||
|
||||
|
||||
public int DetectLeftHandRaise(Human human)
|
||||
{
|
||||
var calculator = PostureCalculate.CreateCalculator();
|
||||
var rule = RaiseHand.RaiseLeftHand();
|
||||
var pass = calculator.Calculating(human, rule);
|
||||
|
||||
if (pass)
|
||||
{
|
||||
// 一旦检测到左手举起,立即返回
|
||||
return (int)WavingAction.RaiseHand;
|
||||
}
|
||||
|
||||
// 没有检测到举手
|
||||
return (int)WavingAction.None;
|
||||
}
|
||||
|
||||
private void ResetRaiseState()
|
||||
{
|
||||
_raiseStartTime = null;
|
||||
_countdownStartTime = null;
|
||||
_firstHandTriggered = false;
|
||||
_lastCountdownSecond = 3;
|
||||
}
|
||||
private void DrawCirclesWithText()
|
||||
{
|
||||
userBox.Children.Clear();
|
||||
@ -445,8 +361,8 @@ namespace Wpf_AiSportsMicrospace.Views
|
||||
for (int i = 0; i < _groupJumpRopeContext.CirclePositions.Count; i++)
|
||||
{
|
||||
var pos = _groupJumpRopeContext.CirclePositions[i];
|
||||
double x = pos.XNorm ;
|
||||
double y = pos.YNorm ;
|
||||
double x = pos.XNorm;
|
||||
double y = pos.YNorm;
|
||||
|
||||
// 绘制发光圆
|
||||
var userItem = AddUserItem(x, y, i);
|
||||
@ -473,54 +389,46 @@ namespace Wpf_AiSportsMicrospace.Views
|
||||
}
|
||||
private void UpdateCircleCounts(List<Human> humans)
|
||||
{
|
||||
double radiusNormX = 150;
|
||||
double radiusNormY = 150;
|
||||
double halfW = AppSettings.AreaSize.X;
|
||||
double halfH = AppSettings.AreaSize.Y;
|
||||
|
||||
for (int i = 0; i < _groupJumpRopeContext.CirclePositions.Count; i++)
|
||||
int circleCount = _groupJumpRopeContext.CirclePositions.Count;
|
||||
|
||||
for (int i = 0; i < circleCount; i++)
|
||||
{
|
||||
var circleX = _groupJumpRopeContext.CirclePositions[i].XNorm;
|
||||
var circleY = _groupJumpRopeContext.CirclePositions[i].YNorm;
|
||||
var circle = _groupJumpRopeContext.CirclePositions[i];
|
||||
double cx = circle.XNorm;
|
||||
double cy = circle.YNorm;
|
||||
|
||||
Human humanInCircle = null;
|
||||
Human targetHuman = null;
|
||||
|
||||
// 找圈内的人
|
||||
foreach (var hu in humans)
|
||||
// 1️⃣ 找圈内的人(单脚命中即可)
|
||||
foreach (var h in humans)
|
||||
{
|
||||
var rightFoot = hu.Keypoints.FirstOrDefault(k => k.Name == "right_ankle");
|
||||
var leftFoot = hu.Keypoints.FirstOrDefault(k => k.Name == "left_ankle");
|
||||
if (rightFoot == null || leftFoot == null)
|
||||
continue;
|
||||
|
||||
double xRightNorm = rightFoot.X ;
|
||||
double xLeftNorm = leftFoot.X ;
|
||||
double yRightNorm = rightFoot.Y ;
|
||||
double yLeftNorm = leftFoot.Y ;
|
||||
|
||||
bool outOfCircle =
|
||||
xRightNorm < (circleX - radiusNormX) || xRightNorm > (circleX + radiusNormX) ||
|
||||
xLeftNorm < (circleX - radiusNormX) || xLeftNorm > (circleX + radiusNormX) ||
|
||||
yRightNorm < (circleY - radiusNormY) || yRightNorm > (circleY + radiusNormY) ||
|
||||
yLeftNorm < (circleY - radiusNormY) || yLeftNorm > (circleY + radiusNormY);
|
||||
|
||||
if (!outOfCircle)
|
||||
if (sportOperate.IsAnyFootInCircle(h, cx, cy, halfW, halfH))
|
||||
{
|
||||
humanInCircle = hu;
|
||||
break; // 每圈只处理一个人
|
||||
targetHuman = h;
|
||||
break; // 每个圈只认一个人
|
||||
}
|
||||
}
|
||||
|
||||
// 根据是否有人和跳绳数字判断状态
|
||||
bool hasHuman = humanInCircle != null;
|
||||
bool hasHuman = targetHuman != null;
|
||||
|
||||
// 2️⃣ 更新视觉状态
|
||||
lock (_updateLock)
|
||||
{
|
||||
_groupJumpRopeContext.UserList[i].ImageState = GetJumpState(i, hasHuman);
|
||||
_groupJumpRopeContext.UserList[i].ImageState =
|
||||
GetJumpState(i, hasHuman);
|
||||
}
|
||||
|
||||
// 推送计数
|
||||
// 3️⃣ 推送跳绳计数
|
||||
if (hasHuman)
|
||||
_groupJumpRopeContext.Sports[i].Pushing(humanInCircle);
|
||||
{
|
||||
_groupJumpRopeContext.Sports[i].Pushing(targetHuman);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string GetJumpState(int circleIndex, bool humanInCircle)
|
||||
{
|
||||
if (!humanInCircle)
|
||||
@ -567,7 +475,7 @@ namespace Wpf_AiSportsMicrospace.Views
|
||||
userItem.HorizontalAlignment = HorizontalAlignment.Left;
|
||||
userItem.ImageState = "1";
|
||||
//userItem.Margin = new Thickness(centerX - (index == 0 ? 80 : index == 6 ? 190 : 135), centerY - 540, 0, 0);
|
||||
userItem.Margin = new Thickness(centerX - 25 - 100, centerY - 490 , 0, 0);
|
||||
userItem.Margin = new Thickness(centerX - 25 - 100, centerY - 490, 0, 0);
|
||||
userBox.Children.Add(userItem);
|
||||
_groupJumpRopeContext.UserList.Add(userItem);
|
||||
_groupJumpRopeContext.UserNumberList.Add("0");
|
||||
@ -645,21 +553,6 @@ namespace Wpf_AiSportsMicrospace.Views
|
||||
//rankingGrid.BeginAnimation(UIElement.OpacityProperty, fadeIn);
|
||||
}
|
||||
|
||||
/*
|
||||
* 控制元素隐藏(渐隐动画
|
||||
* time: 动画持续时间(毫秒)
|
||||
* name: 元素名称
|
||||
*/
|
||||
public void HideElement(string name, int time)
|
||||
{
|
||||
var Element = FindName(name) as Grid;
|
||||
if (Element == null) return;
|
||||
|
||||
var fadeOut = new DoubleAnimation(1, 0, TimeSpan.FromMilliseconds(time));
|
||||
fadeOut.Completed += (s, e) => Element.Visibility = Visibility.Collapsed;
|
||||
Element.BeginAnimation(UIElement.OpacityProperty, fadeOut);
|
||||
}
|
||||
|
||||
/*
|
||||
* 控制元素限时(渐隐动画
|
||||
* time: 动画持续时间(毫秒)
|
||||
|
||||
@ -23,7 +23,7 @@ using System.Windows.Media.Animation;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
using System.Windows.Threading;
|
||||
using System.Windows.Threading;
|
||||
using Wpf_AiSportsMicrospace.Common;
|
||||
using Wpf_AiSportsMicrospace.Dto;
|
||||
using Wpf_AiSportsMicrospace.Enum;
|
||||
@ -75,26 +75,16 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope
|
||||
popSilder1.MusicBeats = _musicJumpRopeContext.MusicBeats["1"];
|
||||
popSilder2.MusicBeats = _musicJumpRopeContext.MusicBeats["1"];
|
||||
|
||||
//Random rnd = new Random();
|
||||
|
||||
//// 模拟 20 次随机更新
|
||||
//for (int i = 0; i < 200; i++)
|
||||
//{
|
||||
// // 随机左右进度变化,保证总和=1
|
||||
// double left = rnd.NextDouble(); // 0~1
|
||||
// PkBar.LeftProgress = left; // RightProgress 自动 1-left
|
||||
|
||||
// await Task.Delay(1000); // 200ms 间隔,不卡UI线程
|
||||
//}
|
||||
|
||||
var app = (App)Application.Current;
|
||||
using var scope = App.AppHost.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
var cfg = await db.GroupPoints.FirstOrDefaultAsync(x => x.Code == AppSettings.Code);
|
||||
//var pointlist = JsonSerializer.Deserialize<List<(double, double)>>(cfg!.PointsJson);
|
||||
|
||||
List<(double XNorm, double YNorm)> pointlist = [(cfg.Point3.X, cfg.Point3.Y), (cfg.Point5.X, cfg.Point5.Y)];
|
||||
List<(double XNorm, double YNorm)> pointlist = [(cfg.ControlPoint.X, cfg.ControlPoint.Y), (cfg.Point3.X, cfg.Point3.Y)];
|
||||
_musicJumpRopeContext.UpdateCirclePositions(pointlist);
|
||||
|
||||
_mainWin.HumanFrameUpdated += OnHumanFrameUpdated;
|
||||
}
|
||||
|
||||
private void UserControl_Unloaded(object sender, RoutedEventArgs e)
|
||||
@ -187,50 +177,49 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope
|
||||
{
|
||||
if (humans == null || humans.Count == 0) return;
|
||||
|
||||
|
||||
switch (_currentGameState)
|
||||
{
|
||||
case GameState.NotStarted:
|
||||
if (!_isCountdownStarted)
|
||||
switch (_currentGameState)
|
||||
{
|
||||
case GameState.NotStarted:
|
||||
if (!_isCountdownStarted)
|
||||
{
|
||||
int leftWaving = sportOperate.VerifyLeftWavingAction(humans);
|
||||
if (leftWaving == 5)
|
||||
{
|
||||
int leftWaving = sportOperate.VerifyLeftWavingAction(humans);
|
||||
if (leftWaving == 5)
|
||||
{
|
||||
_mainWin.HumanFrameUpdated -= OnHumanFrameUpdated;
|
||||
_mainWin.WebcamClient.StopExtract();
|
||||
_mainWin.HumanFrameUpdated -= OnHumanFrameUpdated;
|
||||
_mainWin.WebcamClient.StopExtract();
|
||||
|
||||
// 举左手逻辑,例如结束动画或退出
|
||||
var newPage = new Home();
|
||||
_mainWin?.SwitchPageWithMaskAnimation(newPage, true);
|
||||
return; // 提前退出
|
||||
}
|
||||
// 举左手逻辑,例如结束动画或退出
|
||||
var newPage = new Home();
|
||||
_mainWin?.SwitchPageWithMaskAnimation(newPage, true);
|
||||
return; // 提前退出
|
||||
}
|
||||
}
|
||||
|
||||
int rightWaving = sportOperate.VerifyRightWavingAction(humans);
|
||||
if (rightWaving >= 3 && RankingGrid.Visibility != Visibility.Visible)
|
||||
int rightWaving = sportOperate.VerifyRightWavingAction(humans);
|
||||
if (rightWaving >= 3 && RankingGrid.Visibility != Visibility.Visible)
|
||||
{
|
||||
switch (rightWaving)
|
||||
{
|
||||
switch (rightWaving)
|
||||
{
|
||||
case (int)WavingAction.FirstHand:
|
||||
StartCountdown(3);
|
||||
_isCountdownStarted = true;
|
||||
break;
|
||||
case (int)WavingAction.Raising:
|
||||
UpdateCountdown();
|
||||
break;
|
||||
case (int)WavingAction.RaiseHand:
|
||||
FinishCountdown();
|
||||
_currentGameState = GameState.Running;
|
||||
break;
|
||||
}
|
||||
case (int)WavingAction.FirstHand:
|
||||
StartCountdown(3);
|
||||
_isCountdownStarted = true;
|
||||
break;
|
||||
case (int)WavingAction.Raising:
|
||||
UpdateCountdown();
|
||||
break;
|
||||
case (int)WavingAction.RaiseHand:
|
||||
FinishCountdown();
|
||||
_currentGameState = GameState.Running;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case GameState.Running:
|
||||
UpdateCircleCounts(humans);
|
||||
break;
|
||||
}
|
||||
|
||||
case GameState.Running:
|
||||
UpdateCircleCounts(humans);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -428,88 +417,6 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope
|
||||
Element.BeginAnimation(UIElement.OpacityProperty, fadeIn);
|
||||
}
|
||||
|
||||
private DateTime? _raiseStartTime;
|
||||
private bool _firstHandTriggered;
|
||||
private int _lastCountdownSecond = 3;
|
||||
private DateTime? _countdownStartTime;
|
||||
public int DetectRightHandRaise(Human human)
|
||||
{
|
||||
|
||||
var calculator = PostureCalculate.CreateCalculator();
|
||||
var rule = RaiseHand.RaiseRightHand();
|
||||
var pass = calculator.Calculating(human, rule);
|
||||
|
||||
const double holdDuration = 1; // 持续时间(秒)
|
||||
const int countdownSeconds = 3; // 倒计时长度
|
||||
|
||||
// ---------- 第一步:持续举手触发倒计时 ----------
|
||||
if (!_firstHandTriggered)
|
||||
{
|
||||
if (pass)
|
||||
{
|
||||
_raiseStartTime ??= DateTime.Now;
|
||||
var holdElapsed = (DateTime.Now - _raiseStartTime.Value).TotalSeconds;
|
||||
if (holdElapsed >= holdDuration)
|
||||
{
|
||||
// 举手达到指定时间,启动倒计时
|
||||
_firstHandTriggered = true;
|
||||
_countdownStartTime = DateTime.Now;
|
||||
_lastCountdownSecond = countdownSeconds;
|
||||
return (int)WavingAction.FirstHand;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 手放下,重置举手开始时间
|
||||
_raiseStartTime = DateTime.Now;
|
||||
}
|
||||
|
||||
// 没有任何中心区域内的人举手
|
||||
return (int)WavingAction.None;
|
||||
}
|
||||
|
||||
// ---------- 第二步:倒计时逻辑 ----------
|
||||
var countdownElapsed = (DateTime.Now - _countdownStartTime.Value).TotalSeconds;
|
||||
int currentSecond = countdownSeconds - (int)Math.Floor(countdownElapsed);
|
||||
|
||||
if (currentSecond > 0 && currentSecond != _lastCountdownSecond)
|
||||
{
|
||||
_lastCountdownSecond = currentSecond;
|
||||
Console.WriteLine($"倒计时:{currentSecond}");
|
||||
return (int)WavingAction.Raising; // 倒计时中
|
||||
}
|
||||
|
||||
if (countdownElapsed >= countdownSeconds)
|
||||
{
|
||||
ResetRaiseState();
|
||||
return (int)WavingAction.RaiseHand; // 举手完成
|
||||
}
|
||||
|
||||
return (int)WavingAction.Raising;
|
||||
}
|
||||
public int DetectLeftHandRaise(Human human)
|
||||
{
|
||||
var calculator = PostureCalculate.CreateCalculator();
|
||||
var rule = RaiseHand.RaiseLeftHand();
|
||||
var pass = calculator.Calculating(human, rule);
|
||||
|
||||
if (pass)
|
||||
{
|
||||
// 一旦检测到左手举起,立即返回
|
||||
return (int)WavingAction.RaiseHand;
|
||||
}
|
||||
|
||||
// 没有检测到举手
|
||||
return (int)WavingAction.None;
|
||||
}
|
||||
|
||||
private void ResetRaiseState()
|
||||
{
|
||||
_raiseStartTime = null;
|
||||
_countdownStartTime = null;
|
||||
_firstHandTriggered = false;
|
||||
_lastCountdownSecond = 3;
|
||||
}
|
||||
|
||||
private void DrawCirclesWithText()
|
||||
{
|
||||
@ -579,7 +486,6 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope
|
||||
//UpdateScore(right, score2);
|
||||
score1.Text = (right * 10).ToString();
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@ -588,33 +494,6 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateScore(double to, TextBlock score)
|
||||
{
|
||||
DoubleAnimation animation = new DoubleAnimation
|
||||
{
|
||||
From = double.Parse(score1.Text),
|
||||
To = to,
|
||||
Duration = TimeSpan.FromSeconds(0.2),
|
||||
EasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseOut },
|
||||
FillBehavior = FillBehavior.HoldEnd
|
||||
};
|
||||
score.BeginAnimation(TextBlock.TextProperty, animation);
|
||||
}
|
||||
|
||||
//private void ChangeImgState(int index , string state)
|
||||
//{
|
||||
// if(index== 0)
|
||||
// {
|
||||
// left1.Visibility = state == "1" ? Visibility.Visible : Visibility.Hidden;
|
||||
// left2.Visibility = state == "2" ? Visibility.Visible : Visibility.Hidden;
|
||||
// left3.Visibility = state == "3" ? Visibility.Visible : Visibility.Hidden;
|
||||
// }else if (index == 1)
|
||||
// {
|
||||
// right1.Visibility = state == "1" ? Visibility.Visible : Visibility.Hidden;
|
||||
// right2.Visibility = state == "1" ? Visibility.Visible : Visibility.Hidden;
|
||||
// right3.Visibility = state == "1" ? Visibility.Visible : Visibility.Hidden;
|
||||
// }
|
||||
//}
|
||||
|
||||
public void ShowMusicAnimation()
|
||||
{
|
||||
@ -626,54 +505,40 @@ namespace Wpf_AiSportsMicrospace.Views.JumpRope
|
||||
|
||||
private void UpdateCircleCounts(List<Human> humans)
|
||||
{
|
||||
double radiusNormX = 0.07;
|
||||
double radiusNormY = 0.14;
|
||||
double halfW = AppSettings.AreaSize.X;
|
||||
double halfH = AppSettings.AreaSize.Y;
|
||||
|
||||
for (int i = 0; i < _musicJumpRopeContext.CirclePositions.Count; i++)
|
||||
{
|
||||
var circleX = _musicJumpRopeContext.CirclePositions[i].XNorm;
|
||||
var circleY = _musicJumpRopeContext.CirclePositions[i].YNorm;
|
||||
var circle = _musicJumpRopeContext.CirclePositions[i];
|
||||
double cx = circle.XNorm;
|
||||
double cy = circle.YNorm;
|
||||
|
||||
Human humanInCircle = null;
|
||||
|
||||
// 找圈内的人
|
||||
foreach (var hu in humans)
|
||||
// 1️⃣ 找圈内的人(单脚命中即可)
|
||||
foreach (var h in humans)
|
||||
{
|
||||
var rightFoot = hu.Keypoints.FirstOrDefault(k => k.Name == "right_ankle");
|
||||
var leftFoot = hu.Keypoints.FirstOrDefault(k => k.Name == "left_ankle");
|
||||
if (rightFoot == null || leftFoot == null)
|
||||
continue;
|
||||
|
||||
double xRightNorm = rightFoot.X / userBox.ActualWidth;
|
||||
double xLeftNorm = leftFoot.X / userBox.ActualWidth;
|
||||
double yRightNorm = rightFoot.Y / userBox.ActualHeight;
|
||||
double yLeftNorm = leftFoot.Y / userBox.ActualHeight;
|
||||
|
||||
bool outOfCircle =
|
||||
xRightNorm < (circleX - radiusNormX) || xRightNorm > (circleX + radiusNormX) ||
|
||||
xLeftNorm < (circleX - radiusNormX) || xLeftNorm > (circleX + radiusNormX) ||
|
||||
yRightNorm < (circleY - radiusNormY) || yRightNorm > (circleY + radiusNormY) ||
|
||||
yLeftNorm < (circleY - radiusNormY) || yLeftNorm > (circleY + radiusNormY);
|
||||
|
||||
if (!outOfCircle)
|
||||
if (sportOperate.IsAnyFootInCircle(h, cx, cy, halfW, halfH))
|
||||
{
|
||||
humanInCircle = hu;
|
||||
break; // 每圈只处理一个人
|
||||
humanInCircle = h;
|
||||
break; // 每个圈只认一个人
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 根据是否有人和跳绳数字判断状态
|
||||
bool hasHuman = humanInCircle != null;
|
||||
lock (_updateLock)
|
||||
{
|
||||
_musicJumpRopeContext.UserList[i].ImageState = GetJumpState(i, hasHuman);
|
||||
//var state = GetJumpState(i, hasHuman);
|
||||
//ChangeImgState(i, state);
|
||||
}
|
||||
|
||||
// 推送计数
|
||||
//if (hasHuman)
|
||||
_musicJumpRopeContext.Sports[i].Pushing(humanInCircle);
|
||||
// 3️⃣ 推送计数
|
||||
if (hasHuman)
|
||||
{
|
||||
_musicJumpRopeContext.Sports[i].Pushing(humanInCircle);
|
||||
}
|
||||
}
|
||||
}
|
||||
private string GetJumpState(int circleIndex, bool humanInCircle)
|
||||
|
||||
@ -63,7 +63,7 @@ namespace Wpf_AiSportsMicrospace.Views
|
||||
using var scope = App.AppHost.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
var BaseData = await db.BasicConfig.FirstOrDefaultAsync(x => x.Code == AppSettings.Code);
|
||||
if (BaseData==null)
|
||||
if (BaseData == null)
|
||||
{
|
||||
this.ShowError("相机主机地址/IP不能为空。");
|
||||
return;
|
||||
@ -200,14 +200,19 @@ namespace Wpf_AiSportsMicrospace.Views
|
||||
{
|
||||
try
|
||||
{
|
||||
string code = Utils.GetMacAddress();
|
||||
var app = (App)Application.Current;
|
||||
using var scope = App.AppHost.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
var pointsData = db.JumpLongPoints.FirstOrDefault(x => x.Code == AppSettings.Code);
|
||||
var pointsData = db.JumpLongPoints.FirstOrDefault(x => x.Code == code);
|
||||
|
||||
if (pointsData == null)
|
||||
{
|
||||
pointsData = new JumpLongPoints();
|
||||
|
||||
pointsData.Code = code;
|
||||
|
||||
|
||||
// 保存所有点的位置
|
||||
pointsData.TopPoint1 = new AiSportsMicrospaceDB.Entities.Point
|
||||
{
|
||||
@ -247,7 +252,50 @@ namespace Wpf_AiSportsMicrospace.Views
|
||||
|
||||
db.JumpLongPoints.Add(pointsData);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 保存所有点的位置
|
||||
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.JumpLongPoints.Update(pointsData);
|
||||
}
|
||||
|
||||
db.SaveChanges();
|
||||
|
||||
UpdateStatus("点数据保存成功");
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user