update:添加循环跳远,手势返回等。
This commit is contained in:
parent
1c1b0cce0d
commit
ba381d50bc
@ -29,11 +29,6 @@
|
|||||||
<conv:DotColorConverter x:Key="DotColorConverter"/>
|
<conv:DotColorConverter x:Key="DotColorConverter"/>
|
||||||
<!--<conv:SpacingConverter x:Key="SpacingConverter"/>-->
|
<!--<conv:SpacingConverter x:Key="SpacingConverter"/>-->
|
||||||
|
|
||||||
<!-- 其他自定义样式 -->
|
|
||||||
<Style x:Key="PrimaryButtonStyle" TargetType="Button" BasedOn="{StaticResource ButtonPrimary}">
|
|
||||||
<Setter Property="FontFamily" Value="{StaticResource AppFont}"/>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</Application.Resources>
|
</Application.Resources>
|
||||||
</Application>
|
</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"/>
|
<ImageBrush ImageSource="/Resources/Img/test_img/test_home_bg.png" Stretch="UniformToFill"/>
|
||||||
</Grid.Background>
|
</Grid.Background>
|
||||||
<Grid Height="1080" Width="1920" x:Name="userBox" >
|
<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 x:Name="videoImage" Stretch="Uniform" />
|
||||||
<Image Source="/Resources/Img/test_img/jump_long/mat.png" HorizontalAlignment="Center" VerticalAlignment="Top" Width="1190" Margin="0,600,0,0"/>
|
<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 Source="/Resources/Img/test_img/jump_long/people.png" HorizontalAlignment="Left" VerticalAlignment="Top" Width="244" Margin="1278,282,0,0" Height="458"/>
|
<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"/>
|
||||||
<Label x:Name="sportCounts" Height="50" Width="200" HorizontalAlignment="Left" BorderBrush="Black" BorderThickness="2"></Label>
|
<Image
|
||||||
<Label x:Name="sportTimes" Height="50" Width="200" HorizontalAlignment="Center" BorderBrush="Black" BorderThickness="2" ></Label>
|
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">
|
<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"/>
|
<Image Source="/Resources/Img/test_img/jump_long/tip.png" HorizontalAlignment="Center" VerticalAlignment="Center" Width="1416" Margin="0,0,0,-700"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--成绩-->
|
<!--成绩-->
|
||||||
<Grid x:Name="RankingGrid" Margin="0,0,0,0" Height="1080" Width="1920" Opacity="0">
|
<Grid x:Name="RankingGrid" Margin="0,0,0,0" Height="1080" Width="1920" Opacity="0">
|
||||||
<Image
|
<Image
|
||||||
@ -35,15 +42,34 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<Grid Width="1380" Height="697" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,180,0,0" x:Name="ScoreGrid">
|
<Grid Width="1380" Height="697" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,180,0,0" x:Name="ScoreGrid">
|
||||||
<!--<Border Background="#FEDE50" CornerRadius="20"/>-->
|
<!--<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/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" />
|
<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" >
|
<Border Background="#ff8600" CornerRadius="20" Width="300" Height="90" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="0,20,0,0" >
|
||||||
<Grid>
|
<Grid>
|
||||||
<TextBlock Text="跳远成绩" FontSize="22" TextAlignment="Center" Padding="0,10,0,0" FontWeight="Bold" Foreground="#80ffffff" />
|
<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 x:Name="count" Text="165cm" FontSize="49" TextAlignment="Center" Padding="0,35,0,0" FontWeight="Bold" Foreground="#fff" FontStyle="Italic" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
<StackPanel Margin="60,130,50,30" Orientation="Horizontal">
|
<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="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="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="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>
|
</Grid>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
|
||||||
|
<Grid Margin="0,0,700,50" VerticalAlignment="Bottom" Height="182" Width="340" >
|
||||||
<Grid Margin="0,0,0,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 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" />
|
<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>
|
||||||
|
<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>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@ -46,6 +46,9 @@ namespace Views.JumpLong
|
|||||||
private ApparatusLongJumpDelineation _measureApparatus;
|
private ApparatusLongJumpDelineation _measureApparatus;
|
||||||
private MediaPlayer _mediaPlayer = new MediaPlayer();
|
private MediaPlayer _mediaPlayer = new MediaPlayer();
|
||||||
private readonly SportDetectionQueue _detectQueue;
|
private readonly SportDetectionQueue _detectQueue;
|
||||||
|
|
||||||
|
private int _sportType = 0; // 0:未开始 1:运动中 2:运动结束展示排行榜
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public StandingLeap()
|
public StandingLeap()
|
||||||
@ -53,7 +56,6 @@ namespace Views.JumpLong
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
Loaded += UserControl_Loaded;
|
Loaded += UserControl_Loaded;
|
||||||
Unloaded += UserControl_Unloaded;
|
Unloaded += UserControl_Unloaded;
|
||||||
|
|
||||||
_humanPredictor = HumanPredictorFactory.Create(HumanPredictorType.SingleHigh);
|
_humanPredictor = HumanPredictorFactory.Create(HumanPredictorType.SingleHigh);
|
||||||
_humanGraphicsRenderer = new HumanGraphicsRenderer();
|
_humanGraphicsRenderer = new HumanGraphicsRenderer();
|
||||||
_humanGraphicsRenderer.DrawLabel = false;
|
_humanGraphicsRenderer.DrawLabel = false;
|
||||||
@ -62,19 +64,13 @@ namespace Views.JumpLong
|
|||||||
|
|
||||||
_sport = SportBase.Create("standing-long-jump");
|
_sport = SportBase.Create("standing-long-jump");
|
||||||
_sport.OnTicked += this.OnSportTick;
|
_sport.OnTicked += this.OnSportTick;
|
||||||
//if (_sport?.IsCounting == true)
|
_mainWin.HumanFrameUpdated += this.OnFrameUpdated;
|
||||||
_sport.Start();
|
|
||||||
|
|
||||||
_measureApparatus = new ApparatusLongJumpDelineation();
|
_measureApparatus = new ApparatusLongJumpDelineation();
|
||||||
_measureApparatus.MeasureLength = 300;
|
_measureApparatus.MeasureLength = 300;
|
||||||
var _isCalibrated = this.ReactangleCalibrating(1920, 1080);
|
var _isCalibrated = this.ReactangleCalibrating(1920, 1080);
|
||||||
_sport.MeasureApparatus = _measureApparatus;
|
_sport.MeasureApparatus = _measureApparatus;
|
||||||
|
|
||||||
_detectQueue.Sport = _sport;
|
_detectQueue.Sport = _sport;
|
||||||
_detectQueue.Start();
|
|
||||||
|
|
||||||
// 开始抽帧线程
|
|
||||||
_mainWin.FacialRecognitionEvent += HumanPredicting;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void UserControl_Loaded(object sender, RoutedEventArgs e)
|
private async void UserControl_Loaded(object sender, RoutedEventArgs e)
|
||||||
@ -83,6 +79,47 @@ namespace Views.JumpLong
|
|||||||
PlayMusic("raisehand.mp3");
|
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)
|
private void UserControl_Unloaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
_sport.Stop();
|
_sport.Stop();
|
||||||
@ -110,6 +147,7 @@ namespace Views.JumpLong
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//播放音乐
|
||||||
private void PlayMusic(string musicFileName)
|
private void PlayMusic(string musicFileName)
|
||||||
{
|
{
|
||||||
// 获取项目根目录
|
// 获取项目根目录
|
||||||
@ -158,6 +196,7 @@ namespace Views.JumpLong
|
|||||||
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
private void MediaPlayer_MediaEnded(object sender, EventArgs e)
|
private void MediaPlayer_MediaEnded(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
@ -168,24 +207,29 @@ namespace Views.JumpLong
|
|||||||
private void OnSportTick(int counts, int times)
|
private void OnSportTick(int counts, int times)
|
||||||
{
|
{
|
||||||
var ts = TimeSpan.FromSeconds(times);
|
var ts = TimeSpan.FromSeconds(times);
|
||||||
Dispatcher.BeginInvoke(() =>
|
_ = Dispatcher.BeginInvoke(() =>
|
||||||
{
|
{
|
||||||
//sportCounts.Content = _sport.GetFormatCounts(); //counts.ToString();
|
//sportCounts.Content = _sport.GetFormatCounts(); //counts.ToString();
|
||||||
//sportTimes.Content = _sport.GetFormatTimes();//ts.ToString(@"mm\'ss\""");
|
//sportTimes.Content = _sport.GetFormatTimes();//ts.ToString(@"mm\'ss\""");
|
||||||
count.Text = _sport.GetFormatCounts();
|
var counts = _sport.GetFormatCounts();
|
||||||
|
if (double.Parse(counts[..^1]) > 0 && _sportType == 1) //正向跳远时候&&处于测试阶段时候触发更新
|
||||||
|
{
|
||||||
|
_sport.Stop();//关闭运动
|
||||||
|
_mainWin.FacialRecognitionEvent -= this.HumanPredicting;
|
||||||
|
count.Text = counts;
|
||||||
time.Text = _sport.GetFormatTimes();
|
time.Text = _sport.GetFormatTimes();
|
||||||
ShowRope();
|
ShowRope();
|
||||||
//触发停止
|
|
||||||
if (!_sport.IsCounting)
|
if (!_sport.IsCounting)
|
||||||
{
|
{
|
||||||
_sport.Stop();
|
_sport.Stop();
|
||||||
_sport.Start();
|
_sport.Start();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//展示成绩
|
//展示成绩
|
||||||
private void ShowRope()
|
private async void ShowRope()
|
||||||
{
|
{
|
||||||
// 渐变出现动画
|
// 渐变出现动画
|
||||||
var fadeInAnimation = new DoubleAnimation
|
var fadeInAnimation = new DoubleAnimation
|
||||||
@ -194,9 +238,47 @@ namespace Views.JumpLong
|
|||||||
To = 1,
|
To = 1,
|
||||||
Duration = TimeSpan.FromSeconds(1.5)
|
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);
|
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 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)
|
private bool ReactangleCalibrating(int frameWidth, int frameHeight)
|
||||||
{
|
{
|
||||||
@ -256,5 +338,245 @@ namespace Views.JumpLong
|
|||||||
|
|
||||||
return _measureApparatus.Calibrating(boxes);
|
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\play_img\play_vs.png" />
|
||||||
<None Remove="Resources\Img\test_img\jump_long\bottom.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\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\mat.png" />
|
||||||
<None Remove="Resources\Img\test_img\jump_long\people.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\tip.png" />
|
||||||
<None Remove="Resources\Img\test_img\jump_long\title.png" />
|
<None Remove="Resources\Img\test_img\jump_long\title.png" />
|
||||||
<None Remove="Resources\Img\test_img\jump_long\top.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">
|
<Resource Include="Resources\Img\test_img\jump_long\head_top.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Resource>
|
</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">
|
<Resource Include="Resources\Img\test_img\jump_long\mat.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Resource>
|
</Resource>
|
||||||
<Resource Include="Resources\Img\test_img\jump_long\people.png">
|
<Resource Include="Resources\Img\test_img\jump_long\people.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Resource>
|
</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">
|
<Resource Include="Resources\Img\test_img\jump_long\tip.png">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Resource>
|
</Resource>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user