update:添加循环跳远,手势返回等。
This commit is contained in:
parent
1c1b0cce0d
commit
ba381d50bc
@ -29,11 +29,6 @@
|
||||
<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>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 3.1 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.8 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 85 KiB |
@ -12,18 +12,25 @@
|
||||
<ImageBrush ImageSource="/Resources/Img/test_img/test_home_bg.png" Stretch="UniformToFill"/>
|
||||
</Grid.Background>
|
||||
<Grid Height="1080" Width="1920" x:Name="userBox" >
|
||||
<Image Source="/Resources/Img/test_img/jump_long/title.png" HorizontalAlignment="Center" VerticalAlignment="Top" Width="615" Margin="0,0,0,0"/>
|
||||
<Image Source="/Resources/Img/test_img/jump_long/mat.png" HorizontalAlignment="Center" VerticalAlignment="Top" Width="1190" Margin="0,600,0,0"/>
|
||||
<Image Source="/Resources/Img/test_img/jump_long/people.png" HorizontalAlignment="Left" VerticalAlignment="Top" Width="244" Margin="1278,282,0,0" Height="458"/>
|
||||
<Label x:Name="sportCounts" Height="50" Width="200" HorizontalAlignment="Left" BorderBrush="Black" BorderThickness="2"></Label>
|
||||
<Label x:Name="sportTimes" Height="50" Width="200" HorizontalAlignment="Center" BorderBrush="Black" BorderThickness="2" ></Label>
|
||||
<Image x:Name="videoImage" Stretch="Uniform" />
|
||||
<Image x:Name="centerImg1" Source="/Resources/Img/test_img/jump_long/title.png" HorizontalAlignment="Center" VerticalAlignment="Top" Width="615" Margin="0,0,0,0"/>
|
||||
<Image x:Name="centerImg2" Source="/Resources/Img/test_img/jump_long/mat.png" HorizontalAlignment="Center" VerticalAlignment="Top" Width="1337" Margin="0,556,0,0" Height="210"/>
|
||||
<Image
|
||||
x:Name="centerImg3"
|
||||
gif:ImageBehavior.AnimatedSource="/Resources/Img/test_img/jump_long/right_hand.gif"
|
||||
gif:ImageBehavior.RepeatBehavior="Forever"
|
||||
gif:ImageBehavior.AnimateInDesignMode="True"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Top" Margin="1242,301,0,0" Height="438" Width="360"/>
|
||||
<Image
|
||||
x:Name="centerImg4"
|
||||
gif:ImageBehavior.AnimatedSource="/Resources/Img/test_img/jump_long/jumping.gif"
|
||||
gif:ImageBehavior.RepeatBehavior="Forever"
|
||||
gif:ImageBehavior.AnimateInDesignMode="True"
|
||||
HorizontalAlignment="Left" VerticalAlignment="Top" Margin="824,72,0,0" Width="824" Height="610"/>
|
||||
<Grid Width="1920" Height="1080" Background="#80000000" x:Name="TipBox" Opacity="0">
|
||||
<Image Source="/Resources/Img/test_img/jump_long/tip.png" HorizontalAlignment="Center" VerticalAlignment="Center" Width="1416" Margin="0,0,0,-700"/>
|
||||
</Grid>
|
||||
|
||||
|
||||
|
||||
|
||||
<!--成绩-->
|
||||
<Grid x:Name="RankingGrid" Margin="0,0,0,0" Height="1080" Width="1920" Opacity="0">
|
||||
<Image
|
||||
@ -35,15 +42,34 @@
|
||||
/>
|
||||
|
||||
|
||||
|
||||
<Grid Width="1380" Height="697" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,180,0,0" x:Name="ScoreGrid">
|
||||
<!--<Border Background="#FEDE50" CornerRadius="20"/>-->
|
||||
<Image Source="/Resources/Img/test_img/jump_long/rotate_img.png" Width="1000" Height="1000" Margin="205,-454,175,151" RenderTransformOrigin="0.5,0.5">
|
||||
<Image.RenderTransform>
|
||||
<RotateTransform x:Name="rotateTransform" Angle="0"/>
|
||||
</Image.RenderTransform>
|
||||
<Image.Triggers>
|
||||
<EventTrigger RoutedEvent="Loaded">
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetName="rotateTransform"
|
||||
Storyboard.TargetProperty="Angle"
|
||||
From="0"
|
||||
To="360"
|
||||
Duration="0:0:6"
|
||||
RepeatBehavior="Forever"/>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</EventTrigger>
|
||||
</Image.Triggers>
|
||||
</Image>
|
||||
|
||||
<Image Source="/Resources/Img/test_img/jump_long/head_top.png" HorizontalAlignment="Center" VerticalAlignment="Top" Height="110" Margin="0,-104,0,0" />
|
||||
<Image Source="/Resources/Img/test_img/jump_long/win_bg.png" HorizontalAlignment="Center" VerticalAlignment="Center" Width="1530" Height="770" />
|
||||
<Border Background="#ff8600" CornerRadius="20" Width="300" Height="90" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,20,0,0" >
|
||||
<Grid>
|
||||
<TextBlock Text="跳远成绩" FontSize="22" TextAlignment="Center" Padding="0,10,0,0" FontWeight="Bold" Foreground="#80ffffff" />
|
||||
<TextBlock Text="165cm" FontSize="49" TextAlignment="Center" Padding="0,35,0,0" FontWeight="Bold" Foreground="#fff" FontStyle="Italic" />
|
||||
<TextBlock Text="跳远成绩" FontSize="22" TextAlignment="Center" Padding="0,10,0,0" FontWeight="Bold" Foreground="#80ffffff" />
|
||||
<TextBlock x:Name="count" Text="165cm" FontSize="49" TextAlignment="Center" Padding="0,35,0,0" FontWeight="Bold" Foreground="#fff" FontStyle="Italic" />
|
||||
</Grid>
|
||||
</Border>
|
||||
<StackPanel Margin="60,130,50,30" Orientation="Horizontal">
|
||||
@ -67,17 +93,21 @@
|
||||
<TextBlock Text="380°" FontSize="55" FontWeight="Bold" FontStyle="Italic" Margin="54,81,-54,-81" />
|
||||
<TextBlock Text="2" FontSize="55" FontWeight="Bold" FontStyle="Italic" Margin="432,81,-432,-81" />
|
||||
<TextBlock Text="105cm" FontSize="55" FontWeight="Bold" FontStyle="Italic" Margin="54,373,-54,-373" />
|
||||
<TextBlock Text="00:11" FontSize="55" FontWeight="Bold" FontStyle="Italic" Margin="397,373,-397,-373" />
|
||||
<TextBlock x:Name="time" Text="00:11" FontSize="55" FontWeight="Bold" FontStyle="Italic" Margin="397,373,-397,-373" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
|
||||
|
||||
<Grid Margin="0,0,0,50" VerticalAlignment="Bottom" Height="182" Width="340" >
|
||||
<Grid Margin="0,0,700,50" VerticalAlignment="Bottom" Height="182" Width="340" >
|
||||
<Image Source="/Resources/Img/Album/change_left.png" HorizontalAlignment="Left" VerticalAlignment="Top" Width="330" Margin="0,103,0,0" />
|
||||
<Image gif:ImageBehavior.AnimatedSource="/Resources/Img/Album/3.gif" gif:ImageBehavior.RepeatBehavior="Forever" gif:ImageBehavior.AnimateInDesignMode="True" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="-20,10,30,20" />
|
||||
</Grid>
|
||||
<Grid Margin="700,0,0,50" VerticalAlignment="Bottom" Height="182" Width="340" >
|
||||
<Image Source="/Resources/Img/Album/change_bg.png" HorizontalAlignment="Left" VerticalAlignment="Top" Width="330" Margin="0,103,0,0" />
|
||||
<TextBlock Text="10s" x:Name="countDown" FontSize="28" FontWeight="Bold" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="65,127,0,0" Foreground="red"/>
|
||||
<TextBlock Text="后继续挑战" FontSize="28" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="30,127,0,0" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
@ -46,6 +46,9 @@ namespace Views.JumpLong
|
||||
private ApparatusLongJumpDelineation _measureApparatus;
|
||||
private MediaPlayer _mediaPlayer = new MediaPlayer();
|
||||
private readonly SportDetectionQueue _detectQueue;
|
||||
|
||||
private int _sportType = 0; // 0:未开始 1:运动中 2:运动结束展示排行榜
|
||||
|
||||
#endregion
|
||||
|
||||
public StandingLeap()
|
||||
@ -53,7 +56,6 @@ namespace Views.JumpLong
|
||||
InitializeComponent();
|
||||
Loaded += UserControl_Loaded;
|
||||
Unloaded += UserControl_Unloaded;
|
||||
|
||||
_humanPredictor = HumanPredictorFactory.Create(HumanPredictorType.SingleHigh);
|
||||
_humanGraphicsRenderer = new HumanGraphicsRenderer();
|
||||
_humanGraphicsRenderer.DrawLabel = false;
|
||||
@ -62,19 +64,13 @@ namespace Views.JumpLong
|
||||
|
||||
_sport = SportBase.Create("standing-long-jump");
|
||||
_sport.OnTicked += this.OnSportTick;
|
||||
//if (_sport?.IsCounting == true)
|
||||
_sport.Start();
|
||||
|
||||
_mainWin.HumanFrameUpdated += this.OnFrameUpdated;
|
||||
_measureApparatus = new ApparatusLongJumpDelineation();
|
||||
_measureApparatus.MeasureLength = 300;
|
||||
var _isCalibrated = this.ReactangleCalibrating(1920, 1080);
|
||||
_sport.MeasureApparatus = _measureApparatus;
|
||||
|
||||
_detectQueue.Sport = _sport;
|
||||
_detectQueue.Start();
|
||||
|
||||
// 开始抽帧线程
|
||||
_mainWin.FacialRecognitionEvent += HumanPredicting;
|
||||
}
|
||||
|
||||
private async void UserControl_Loaded(object sender, RoutedEventArgs e)
|
||||
@ -83,6 +79,47 @@ namespace Views.JumpLong
|
||||
PlayMusic("raisehand.mp3");
|
||||
}
|
||||
|
||||
|
||||
//举手检测
|
||||
private void OnFrameUpdated(object sender, List<Human> humans)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (humans == null || humans.Count == 0) return;
|
||||
|
||||
//举手检测 未开始 :退出& 开始 运动中:不检测 2.结束:继续测试 & 退出
|
||||
if (_sportType != 1)
|
||||
{
|
||||
//左手返回
|
||||
int leftWaving = DetectLeftHandRaise(humans);
|
||||
if (leftWaving == 5)
|
||||
{
|
||||
_mainWin.HumanFrameUpdated -= this.OnFrameUpdated;
|
||||
_mainWin.WebcamClient.StopExtract();
|
||||
|
||||
// 举左手逻辑,例如结束动画或退出
|
||||
var newPage = new Home();
|
||||
_mainWin?.SwitchPageWithMaskAnimation(newPage, true);
|
||||
return; // 提前退出
|
||||
}
|
||||
|
||||
//右手判断
|
||||
int rightWaving = DetectRightHandRaise(humans);
|
||||
if (rightWaving >= 3 && _sportType == 0) //举手完成 开始跳远检测
|
||||
{
|
||||
Utils.PlayBackgroundMusic("countdown_3.mp3", false);
|
||||
_sportType = 1;
|
||||
StartSport();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("OnFrameExtracted error: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void UserControl_Unloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_sport.Stop();
|
||||
@ -110,6 +147,7 @@ namespace Views.JumpLong
|
||||
}
|
||||
}
|
||||
|
||||
//播放音乐
|
||||
private void PlayMusic(string musicFileName)
|
||||
{
|
||||
// 获取项目根目录
|
||||
@ -158,6 +196,7 @@ namespace Views.JumpLong
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
private void MediaPlayer_MediaEnded(object sender, EventArgs e)
|
||||
{
|
||||
@ -168,24 +207,29 @@ namespace Views.JumpLong
|
||||
private void OnSportTick(int counts, int times)
|
||||
{
|
||||
var ts = TimeSpan.FromSeconds(times);
|
||||
Dispatcher.BeginInvoke(() =>
|
||||
_ = Dispatcher.BeginInvoke(() =>
|
||||
{
|
||||
//sportCounts.Content = _sport.GetFormatCounts(); //counts.ToString();
|
||||
//sportTimes.Content = _sport.GetFormatTimes();//ts.ToString(@"mm\'ss\""");
|
||||
count.Text = _sport.GetFormatCounts();
|
||||
time.Text = _sport.GetFormatTimes();
|
||||
ShowRope();
|
||||
//触发停止
|
||||
if (!_sport.IsCounting)
|
||||
var counts = _sport.GetFormatCounts();
|
||||
if (double.Parse(counts[..^1]) > 0 && _sportType == 1) //正向跳远时候&&处于测试阶段时候触发更新
|
||||
{
|
||||
_sport.Stop();
|
||||
_sport.Start();
|
||||
_sport.Stop();//关闭运动
|
||||
_mainWin.FacialRecognitionEvent -= this.HumanPredicting;
|
||||
count.Text = counts;
|
||||
time.Text = _sport.GetFormatTimes();
|
||||
ShowRope();
|
||||
if (!_sport.IsCounting)
|
||||
{
|
||||
_sport.Stop();
|
||||
_sport.Start();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//展示成绩
|
||||
private void ShowRope()
|
||||
private async void ShowRope()
|
||||
{
|
||||
// 渐变出现动画
|
||||
var fadeInAnimation = new DoubleAnimation
|
||||
@ -194,18 +238,56 @@ namespace Views.JumpLong
|
||||
To = 1,
|
||||
Duration = TimeSpan.FromSeconds(1.5)
|
||||
};
|
||||
var fadeInAnimation1 = new DoubleAnimation
|
||||
{
|
||||
From = 1,
|
||||
To = 0,
|
||||
Duration = TimeSpan.FromSeconds(1.5)
|
||||
};
|
||||
//videoImage.Opacity = 0;
|
||||
//centerImg1.Opacity = 1;
|
||||
//centerImg2.Opacity = 1;
|
||||
//centerImg3.Opacity = 1;
|
||||
_sportType = 2;
|
||||
RankingGrid.BeginAnimation(UIElement.OpacityProperty, fadeInAnimation);
|
||||
|
||||
|
||||
//_mainWin.WebcamClient.OnExtractFrame -= this.OnFrameExtracted;
|
||||
for (int i = 12; i >= 0; i--)
|
||||
{
|
||||
countDown.Text = i.ToString() + "s";
|
||||
if (i == 1)
|
||||
{
|
||||
RankingGrid.BeginAnimation(UIElement.OpacityProperty, fadeInAnimation1);
|
||||
_sportType = 0;
|
||||
PlayMusic("raisehand.mp3");
|
||||
}
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
// 关闭跳远抽帧线程
|
||||
}
|
||||
private bool ReactangleCalibrating(int frameWidth, int frameHeight)
|
||||
|
||||
//关闭成绩展示 显示跳远页面
|
||||
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)
|
||||
{
|
||||
|
||||
var mainWin = Application.Current.MainWindow as Main;
|
||||
var app = (App)Application.Current;
|
||||
using var scope = App.AppHost.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
var points = db.JumpLongPoints.FirstOrDefault();
|
||||
var points = db.JumpLongPoints.FirstOrDefault();
|
||||
var boxes = new List<BoundingBox>()
|
||||
{
|
||||
new BoundingBox(){
|
||||
@ -256,5 +338,245 @@ namespace Views.JumpLong
|
||||
|
||||
return _measureApparatus.Calibrating(boxes);
|
||||
}
|
||||
|
||||
|
||||
public int DetectLeftHandRaise(List<Human> humans)
|
||||
{
|
||||
if (humans == null || humans.Count == 0)
|
||||
return (int)WavingAction.None;
|
||||
|
||||
|
||||
foreach (var human in humans)
|
||||
{
|
||||
if (human?.Keypoints == null)
|
||||
continue;
|
||||
|
||||
|
||||
// --- 筛选右脚踝坐标 ---
|
||||
var rightAnkle = human.Keypoints.FirstOrDefault(k => k.Name == "right_ankle");
|
||||
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();
|
||||
|
||||
// 检测起跳区域的人
|
||||
|
||||
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);
|
||||
}
|
||||
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;
|
||||
|
||||
// 获取左手关键点
|
||||
var leftWrist = human.Keypoints.FirstOrDefault(k => k.Name == "left_wrist");
|
||||
var leftElbow = human.Keypoints.FirstOrDefault(k => k.Name == "left_elbow");
|
||||
|
||||
if (leftWrist == null || leftElbow == null)
|
||||
continue;
|
||||
|
||||
const double raiseThreshold = 60; // 举手阈值
|
||||
|
||||
// 判断左手是否举起
|
||||
double verticalRise = leftElbow.Y - leftWrist.Y;
|
||||
if (verticalRise >= raiseThreshold)
|
||||
{
|
||||
return (int)WavingAction.RaiseHand; // 一旦检测到左手举起,立即返回
|
||||
}
|
||||
}
|
||||
|
||||
return (int)WavingAction.None; // 没有检测到举手
|
||||
}
|
||||
|
||||
private DateTime? _raiseStartTime;
|
||||
private bool _firstHandTriggered;
|
||||
private int _lastCountdownSecond = 3;
|
||||
private DateTime? _countdownStartTime;
|
||||
public int DetectRightHandRaise(List<Human> humans)
|
||||
{
|
||||
if (humans == null || humans.Count == 0)
|
||||
return (int)WavingAction.None;
|
||||
|
||||
foreach (var human in humans)
|
||||
{
|
||||
if (human?.Keypoints == null)
|
||||
continue;
|
||||
|
||||
// --- 筛选右脚踝坐标 ---
|
||||
var rightAnkle = human.Keypoints.FirstOrDefault(k => k.Name == "right_ankle");
|
||||
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();
|
||||
|
||||
// 检测起跳区域的人
|
||||
|
||||
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);
|
||||
}
|
||||
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;
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
double verticalRise = rightElbow.Y - rightWrist.Y;
|
||||
handRaised = verticalRise >= raiseThreshold;
|
||||
}
|
||||
|
||||
// ---------- 第一步:持续举手触发倒计时 ----------
|
||||
if (!_firstHandTriggered)
|
||||
{
|
||||
|
||||
if (handRaised)
|
||||
{
|
||||
_raiseStartTime ??= DateTime.Now;
|
||||
var holdElapsed = (DateTime.Now - _raiseStartTime.Value).TotalSeconds;
|
||||
if (holdElapsed >= holdDuration)
|
||||
{
|
||||
// 举手达到指定时间,启动倒计时
|
||||
_firstHandTriggered = true;
|
||||
ResetRaiseState();
|
||||
return (int)WavingAction.FirstHand;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 手放下,重置举手开始时间
|
||||
_raiseStartTime = DateTime.Now;
|
||||
}
|
||||
|
||||
continue; // 本人未触发,检测下一个人
|
||||
}
|
||||
|
||||
// ---------- 第二步:倒计时逻辑 ----------
|
||||
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;
|
||||
}
|
||||
|
||||
// 没有任何中心区域内的人举手
|
||||
return (int)WavingAction.None;
|
||||
}
|
||||
|
||||
private void ResetRaiseState()
|
||||
{
|
||||
_raiseStartTime = null;
|
||||
_countdownStartTime = null;
|
||||
_firstHandTriggered = false;
|
||||
_lastCountdownSecond = 3;
|
||||
}
|
||||
|
||||
private void StartSport()
|
||||
{
|
||||
|
||||
|
||||
//if (_sport?.IsCounting == true)
|
||||
//_mainWin.WebcamClient.OnExtractFrame += this.OnFrameExtracted;
|
||||
_sport.Start();
|
||||
_detectQueue.Start();
|
||||
|
||||
// 开始跳远抽帧线程
|
||||
_mainWin.FacialRecognitionEvent += this.HumanPredicting;
|
||||
}
|
||||
|
||||
private WriteableBitmap _videoBitmap;
|
||||
private int _lastFrameNumber = -1;
|
||||
private async void OnFrameExtracted(VideoFrame frame)
|
||||
{
|
||||
if (frame == null) return;
|
||||
|
||||
// 跳帧:每秒只渲染 10~15 帧,降低 CPU 占用
|
||||
|
||||
if (frame.Number % 2 != 0) return;
|
||||
|
||||
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();
|
||||
|
||||
videoImage.Opacity = 1;
|
||||
centerImg1.Opacity = 0;
|
||||
centerImg2.Opacity = 0;
|
||||
centerImg3.Opacity = 0;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,8 +68,11 @@
|
||||
<None Remove="Resources\Img\play_img\play_vs.png" />
|
||||
<None Remove="Resources\Img\test_img\jump_long\bottom.png" />
|
||||
<None Remove="Resources\Img\test_img\jump_long\head_top.png" />
|
||||
<None Remove="Resources\Img\test_img\jump_long\jumping.gif" />
|
||||
<None Remove="Resources\Img\test_img\jump_long\mat.png" />
|
||||
<None Remove="Resources\Img\test_img\jump_long\people.png" />
|
||||
<None Remove="Resources\Img\test_img\jump_long\right_hand.gif" />
|
||||
<None Remove="Resources\Img\test_img\jump_long\rotate_img.png" />
|
||||
<None Remove="Resources\Img\test_img\jump_long\tip.png" />
|
||||
<None Remove="Resources\Img\test_img\jump_long\title.png" />
|
||||
<None Remove="Resources\Img\test_img\jump_long\top.png" />
|
||||
@ -119,12 +122,21 @@
|
||||
<Resource Include="Resources\Img\test_img\jump_long\head_top.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Resource>
|
||||
<Resource Include="Resources\Img\test_img\jump_long\jumping.gif">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Resource>
|
||||
<Resource Include="Resources\Img\test_img\jump_long\mat.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Resource>
|
||||
<Resource Include="Resources\Img\test_img\jump_long\people.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Resource>
|
||||
<Resource Include="Resources\Img\test_img\jump_long\right_hand.gif">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Resource>
|
||||
<Resource Include="Resources\Img\test_img\jump_long\rotate_img.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Resource>
|
||||
<Resource Include="Resources\Img\test_img\jump_long\tip.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Resource>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user