This commit is contained in:
tanglong 2025-10-15 10:01:58 +08:00
parent 027cffa506
commit 29360dcb96
4 changed files with 148 additions and 116 deletions

View File

@ -65,57 +65,65 @@ namespace Wpf_AiSportsMicrospace.Common
return _webcamClient; return _webcamClient;
} }
public int VerifyWavingAction(Human human) public int VerifyWavingAction(List<Human> humans)
{ {
var nose = human.Keypoints.FirstOrDefault(k => k.Name == "right_ankle"); if (humans == null || humans.Count == 0)
if (nose == null)
return (int)WavingAction.None; return (int)WavingAction.None;
double xNorm = nose.X / 1920; foreach (var human in humans)
double yNorm = nose.Y / 1080;
if (!(xNorm >= 0.44 && xNorm <= 0.57 && yNorm >= 0.81))
return (int)WavingAction.None;
var leftWrist = human.Keypoints.FirstOrDefault(x => x.Name == "left_wrist");
var leftElbow = human.Keypoints.FirstOrDefault(x => x.Name == "left_elbow");
var rightWrist = human.Keypoints.FirstOrDefault(x => x.Name == "right_wrist");
var rightElbow = human.Keypoints.FirstOrDefault(x => x.Name == "right_elbow");
// --- 左手挥手 ---
if (leftWrist != null && leftElbow != null)
{ {
int leftResult = DetectHorizontalWave( var rightAnkle = human.Keypoints.FirstOrDefault(k => k.Name == "right_ankle");
new Point(leftWrist.X, leftWrist.Y), if (rightAnkle == null)
new Point(leftElbow.X, leftElbow.Y), continue;
ref _lastLeftWrist,
ref _leftWristDeltaX,
true);
if (leftResult != (int)WavingAction.None)
return leftResult;
}
// --- 右手举手优先判断 --- double xNorm = rightAnkle.X / 1920;
int rightHandAction = DetectRightHandRaise(human); double yNorm = rightAnkle.Y / 1080;
if (rightHandAction != (int)WavingAction.None)
return rightHandAction;
// --- 右手挥手,仅当未举手时判断 --- // 仅检测中心区域内的人
if (rightWrist != null && rightElbow != null) if (!(xNorm >= 0.44 && xNorm <= 0.57 && yNorm >= 0.81))
{ continue;
int rightWaveResult = DetectHorizontalWave(
new Point(rightWrist.X, rightWrist.Y), var leftWrist = human.Keypoints.FirstOrDefault(x => x.Name == "left_wrist");
new Point(rightElbow.X, rightElbow.Y), var leftElbow = human.Keypoints.FirstOrDefault(x => x.Name == "left_elbow");
ref _lastRightWrist, var rightWrist = human.Keypoints.FirstOrDefault(x => x.Name == "right_wrist");
ref _rightWristDeltaX, var rightElbow = human.Keypoints.FirstOrDefault(x => x.Name == "right_elbow");
false);
if (rightWaveResult != (int)WavingAction.None) // --- 右手举手优先 ---
return rightWaveResult; int rightHandAction = DetectRightHandRaise(human);
if (rightHandAction != (int)WavingAction.None)
return rightHandAction;
// --- 左手挥手 ---
if (leftWrist != null && leftElbow != null)
{
int leftResult = DetectHorizontalWave(
new Point(leftWrist.X, leftWrist.Y),
new Point(leftElbow.X, leftElbow.Y),
ref _lastLeftWrist,
ref _leftWristDeltaX,
true);
if (leftResult != (int)WavingAction.None)
return leftResult;
}
// --- 右手挥手 ---
if (rightWrist != null && rightElbow != null)
{
int rightWaveResult = DetectHorizontalWave(
new Point(rightWrist.X, rightWrist.Y),
new Point(rightElbow.X, rightElbow.Y),
ref _lastRightWrist,
ref _rightWristDeltaX,
false);
if (rightWaveResult != (int)WavingAction.None)
return rightWaveResult;
}
} }
return (int)WavingAction.None; return (int)WavingAction.None;
} }
/// <summary> /// <summary>
/// 检测右手举手状态 /// 检测右手举手状态
/// </summary> /// </summary>

View File

@ -87,7 +87,7 @@ namespace Wpf_AiSportsMicrospace.Views
if (human == null) return; if (human == null) return;
//检测挥手动作 //检测挥手动作
var wavingaction = sportOperate.VerifyWavingAction(human); var wavingaction = sportOperate.VerifyWavingAction(humans);
switch (wavingaction) switch (wavingaction)
{ {

View File

@ -71,7 +71,7 @@ namespace Wpf_AiSportsMicrospace
if (human == null) return; if (human == null) return;
//检测挥手动作 //检测挥手动作
var wavingaction = _mainWin.SportOperate.VerifyWavingAction(human); var wavingaction = _mainWin.SportOperate.VerifyWavingAction(humans);
switch (wavingaction) switch (wavingaction)
{ {

View File

@ -158,38 +158,37 @@ namespace Wpf_AiSportsMicrospace.Views
if (humans == null || humans.Count == 0) return; if (humans == null || humans.Count == 0) return;
int wavingaction = 0; int wavingaction = 0;
foreach (var human in humans)
wavingaction = DetectRightHandRaise(humans);
if (wavingaction < 3)
return;
switch (wavingaction)
{ {
wavingaction = DetectRightHandRaise(human); case (int)WavingAction.FirstHand:
// 第一次举手,初始化倒计时
StartCountdown(3);
break;
if (wavingaction < 3) case (int)WavingAction.Raising:
continue; // 持续倒计时中
UpdateCountdown();
break;
switch (wavingaction) case (int)WavingAction.RaiseHand:
{ // 举手完成,倒计时结束
case (int)WavingAction.FirstHand: FinishCountdown();
// 第一次举手,初始化倒计时 break;
StartCountdown(3);
break;
case (int)WavingAction.Raising: default:
// 持续倒计时中 // 没检测到动作,重置倒计时显示
UpdateCountdown(); Utils.StopBackgroundMusic();
break; countdownText.Text = "3";
countdownGrid.Visibility = Visibility.Hidden;
case (int)WavingAction.RaiseHand: break;
// 举手完成,倒计时结束
FinishCountdown();
break;
default:
// 没检测到动作,重置倒计时显示
Utils.StopBackgroundMusic();
countdownText.Text = "3";
countdownGrid.Visibility = Visibility.Hidden;
break;
}
} }
} }
else else
{ {
@ -273,66 +272,91 @@ namespace Wpf_AiSportsMicrospace.Views
private bool _firstHandTriggered; private bool _firstHandTriggered;
private int _lastCountdownSecond = 3; private int _lastCountdownSecond = 3;
private DateTime? _countdownStartTime; private DateTime? _countdownStartTime;
public int DetectRightHandRaise(Human human) public int DetectRightHandRaise(List<Human> humans)
{ {
var rightWrist = human.Keypoints.FirstOrDefault(k => k.Name == "right_wrist"); if (humans == null || humans.Count == 0)
var rightElbow = human.Keypoints.FirstOrDefault(k => k.Name == "right_elbow"); return (int)WavingAction.None;
const double raiseThreshold = 60; // 举手阈值 foreach (var human in humans)
const double holdDuration = 1; // 持续 2 秒触发倒计时
const int countdownSeconds = 3; // 倒计时长度
bool handRaised = false;
if (rightWrist != null && rightElbow != null)
{ {
double verticalRise = rightElbow.Y - rightWrist.Y; if (human?.Keypoints == null)
handRaised = verticalRise >= raiseThreshold; continue;
}
// ---------- 第一步:持续举手触发倒计时 ---------- // --- 筛选右脚踝坐标 ---
if (!_firstHandTriggered) var rightAnkle = human.Keypoints.FirstOrDefault(k => k.Name == "right_ankle");
{ if (rightAnkle == null)
if (handRaised) continue;
double xNorm = rightAnkle.X / 1920;
double yNorm = rightAnkle.Y / 1080;
// 仅检测中心区域内的人
if (!(xNorm >= 0.44 && xNorm <= 0.57 && yNorm >= 0.81))
continue;
// --- 获取右臂关键点 ---
var rightWrist = human.Keypoints.FirstOrDefault(k => k.Name == "right_wrist");
var rightElbow = human.Keypoints.FirstOrDefault(k => k.Name == "right_elbow");
const double raiseThreshold = 60; // 举手阈值
const double holdDuration = 1; // 持续时间(秒)
const int countdownSeconds = 3; // 倒计时长度
bool handRaised = false;
if (rightWrist != null && rightElbow != null)
{ {
_raiseStartTime ??= DateTime.Now; double verticalRise = rightElbow.Y - rightWrist.Y;
var holdElapsed = (DateTime.Now - _raiseStartTime.Value).TotalSeconds; handRaised = verticalRise >= raiseThreshold;
if (holdElapsed >= holdDuration) }
// ---------- 第一步:持续举手触发倒计时 ----------
if (!_firstHandTriggered)
{
if (handRaised)
{ {
// 举手达到 2 秒,启动倒计时 _raiseStartTime ??= DateTime.Now;
_firstHandTriggered = true; var holdElapsed = (DateTime.Now - _raiseStartTime.Value).TotalSeconds;
_countdownStartTime = DateTime.Now; if (holdElapsed >= holdDuration)
_lastCountdownSecond = countdownSeconds; {
return (int)WavingAction.FirstHand; // 举手达到指定时间,启动倒计时
_firstHandTriggered = true;
_countdownStartTime = DateTime.Now;
_lastCountdownSecond = countdownSeconds;
return (int)WavingAction.FirstHand;
}
} }
else
{
// 手放下,重置举手开始时间
_raiseStartTime = DateTime.Now;
}
continue; // 本人未触发,检测下一个人
} }
else
// ---------- 第二步:倒计时逻辑 ----------
var countdownElapsed = (DateTime.Now - _countdownStartTime.Value).TotalSeconds;
int currentSecond = countdownSeconds - (int)Math.Floor(countdownElapsed);
if (currentSecond > 0 && currentSecond != _lastCountdownSecond)
{ {
// 手放下,重置举手开始时间 _lastCountdownSecond = currentSecond;
_raiseStartTime = DateTime.Now; Console.WriteLine($"倒计时:{currentSecond}");
return (int)WavingAction.Raising; // 倒计时中
} }
return (int)WavingAction.None; // 倒计时未开始 if (countdownElapsed >= countdownSeconds)
{
ResetRaiseState();
return (int)WavingAction.RaiseHand; // 举手完成
}
return (int)WavingAction.Raising;
} }
// ---------- 第二步:倒计时逻辑(独立于手状态) ---------- // 没有任何中心区域内的人举手
var countdownElapsed = (DateTime.Now - _countdownStartTime.Value).TotalSeconds; return (int)WavingAction.None;
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; // 倒计时中
} }
private void ResetRaiseState() private void ResetRaiseState()