587 lines
22 KiB
C#
587 lines
22 KiB
C#
using AiSportsMicrospaceDB.DBContext;
|
|
using AiSportsMicrospaceDB.Entities;
|
|
using Common;
|
|
using Dto;
|
|
using Enum;
|
|
using HandyControl.Controls;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text;
|
|
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.Animation;
|
|
using System.Windows.Media.Imaging;
|
|
using System.Windows.Navigation;
|
|
using System.Windows.Shapes;
|
|
using Wpf_AiSportsMicrospace;
|
|
using Wpf_AiSportsMicrospace.Common;
|
|
using Wpf_AiSportsMicrospace.Enum;
|
|
using Wpf_AiSportsMicrospace.MyUserControl;
|
|
using Wpf_AiSportsMicrospace.Views;
|
|
using WpfAnimatedGif;
|
|
using Yztob.AiSports.Inferences.Abstractions;
|
|
using Yztob.AiSports.Inferences.Implement;
|
|
using Yztob.AiSports.Inferences.Things;
|
|
using Yztob.AiSports.Postures.Sports;
|
|
using Yztob.AiSports.Postures.Things;
|
|
using Yztob.AiSports.Sensors.Abstractions;
|
|
using Yztob.AiSports.Sensors.Things;
|
|
|
|
namespace Views.JumpLong
|
|
{
|
|
/// <summary>
|
|
/// StandingLeap.xaml 的交互逻辑
|
|
/// </summary>
|
|
public partial class StandingLeap : UserControl
|
|
{
|
|
#region 私有成员
|
|
private Main _mainWin => Application.Current.MainWindow as Main;
|
|
private IHumanPredictor _humanPredictor;
|
|
private IObjectDetector _objectDetector;
|
|
private HumanGraphicsRenderer _humanGraphicsRenderer;
|
|
private SportBase _sport;
|
|
private ApparatusLongJumpDelineation _measureApparatus;
|
|
private MediaPlayer _mediaPlayer = new MediaPlayer();
|
|
private readonly SportDetectionQueue _detectQueue;
|
|
|
|
private JumpLongPoints _Points;
|
|
|
|
private int _sportType = 0; // 0:未开始 1:运动中 2:运动结束展示排行榜
|
|
|
|
#endregion
|
|
|
|
public StandingLeap()
|
|
{
|
|
InitializeComponent();
|
|
Loaded += UserControl_Loaded;
|
|
Unloaded += UserControl_Unloaded;
|
|
_humanPredictor = HumanPredictorFactory.Create(HumanPredictorType.SingleHigh);
|
|
_humanGraphicsRenderer = new HumanGraphicsRenderer();
|
|
_humanGraphicsRenderer.DrawLabel = false;
|
|
_objectDetector = ObjectDetectorFactory.CreateSportGoodsDetector();
|
|
_detectQueue = new SportDetectionQueue();
|
|
_detectQueue.Start();
|
|
_measureApparatus = new ApparatusLongJumpDelineation();
|
|
_measureApparatus.MeasureLength = 300;
|
|
}
|
|
|
|
private async void UserControl_Loaded(object sender, RoutedEventArgs e)
|
|
{
|
|
// 播放音乐
|
|
PlayMusic("jumphand.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;
|
|
_sport = SportBase.Create("standing-long-jump");
|
|
_sport.OnTicked += this.OnSportTick;
|
|
_sport.Start();
|
|
// 开始跳远抽帧线程
|
|
_mainWin.FacialRecognitionEvent += this.HumanPredicting;
|
|
var _isCalibrated = this.ReactangleCalibrating(1920, 1080);
|
|
_sport.MeasureApparatus = _measureApparatus;
|
|
_detectQueue.Sport = _sport;
|
|
}
|
|
|
|
|
|
//举手检测
|
|
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) //举手完成 开始跳远检测
|
|
{
|
|
TipBox.Opacity = 0;
|
|
_sportType = 1;
|
|
StartSport();
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine("OnFrameExtracted error: " + ex.Message);
|
|
}
|
|
}
|
|
|
|
|
|
private void UserControl_Unloaded(object sender, RoutedEventArgs e)
|
|
{
|
|
_sport.Stop();
|
|
_humanPredictor?.Dispose();
|
|
_objectDetector?.Dispose();
|
|
}
|
|
|
|
private async void HumanPredicting(VideoFrame frame)
|
|
{
|
|
try
|
|
{
|
|
var buffer = frame.GetImageBuffer(ImageFormat.Jpeg).ToArray();
|
|
var humanResult = await Task.Run<HumanInferenceResult>(() => _humanPredictor.Predicting(buffer, frame.Number));
|
|
var objects = _sport.Equipment ? await Task.Run<List<BoundingBox>>(() => _objectDetector.Detecting(buffer)) : new List<BoundingBox>();
|
|
if (_sport.MeasureApparatus != null)
|
|
objects.AddRange(_sport.MeasureApparatus.Apparatuses);
|
|
|
|
//运动需要保证时序
|
|
var human = humanResult?.Humans?.FirstOrDefault();
|
|
_detectQueue.Enqueue(frame.Number, human, objects);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine("ProcessFrame error: " + ex.Message);
|
|
}
|
|
}
|
|
|
|
//播放音乐
|
|
private void PlayMusic(string musicFileName)
|
|
{
|
|
// 获取项目根目录
|
|
string projectRoot = System.IO.Path.Combine(AppContext.BaseDirectory, @"..\..\..");
|
|
string musicPath = System.IO.Path.Combine(projectRoot, "Resources", "Music", musicFileName);
|
|
|
|
if (!File.Exists(musicPath))
|
|
{
|
|
Console.WriteLine($"音乐文件不存在: {musicPath}");
|
|
return;
|
|
}
|
|
|
|
_mediaPlayer.Open(new Uri(musicPath, UriKind.Absolute));
|
|
|
|
ShowCenterTip(TimeSpan.FromSeconds(3));
|
|
|
|
// 监听播放完成事件
|
|
_mediaPlayer.MediaEnded += MediaPlayer_MediaEnded;
|
|
//_mainWin.WebcamClient.StartExtract();
|
|
_mediaPlayer.Play();
|
|
}
|
|
private void ShowCenterTip(TimeSpan duration)
|
|
{
|
|
// 渐变出现动画
|
|
var fadeInAnimation = new DoubleAnimation
|
|
{
|
|
From = 0,
|
|
To = 1,
|
|
Duration = TimeSpan.FromSeconds(1.5)
|
|
};
|
|
TipBox.BeginAnimation(UIElement.OpacityProperty, fadeInAnimation);
|
|
|
|
//// 定时移除,并且渐变消失
|
|
//Task.Delay(duration).ContinueWith(_ =>
|
|
//{
|
|
// Dispatcher.Invoke(() =>
|
|
// {
|
|
// // 渐变消失动画
|
|
// var fadeOutAnimation = new DoubleAnimation
|
|
// {
|
|
// From = 1,
|
|
// To = 0,
|
|
// Duration = TimeSpan.FromSeconds(1.5)
|
|
// };
|
|
// TipBox.BeginAnimation(UIElement.OpacityProperty, fadeOutAnimation);
|
|
|
|
// });;
|
|
//});
|
|
|
|
}
|
|
private void MediaPlayer_MediaEnded(object sender, EventArgs e)
|
|
{
|
|
// 音乐播放完成后的逻辑
|
|
Console.WriteLine("音乐播放完成!");
|
|
}
|
|
|
|
private void OnSportTick(int counts, int times)
|
|
{
|
|
var ts = TimeSpan.FromSeconds(times);
|
|
_ = Dispatcher.BeginInvoke(async () =>
|
|
{
|
|
//sportCounts.Content = _sport.GetFormatCounts(); //counts.ToString();
|
|
//sportTimes.Content = _sport.GetFormatTimes();//ts.ToString(@"mm\'ss\""");
|
|
var counts = _sport.GetFormatCounts();
|
|
if (double.Parse(counts[..^1]) > 0 && _sportType == 1) //正向跳远时候&&处于测试阶段时候触发更新
|
|
{
|
|
ImageBehavior.SetRepeatBehavior(centerImg4, new RepeatBehavior(2));
|
|
ImageBehavior.SetRepeatBehavior(centerImg4, new RepeatBehavior(1));
|
|
ImageBehavior.GetAnimationController(centerImg4).Play();
|
|
await Task.Delay(2100);
|
|
_sport.Stop();//关闭运动
|
|
//_mainWin.FacialRecognitionEvent -= this.HumanPredicting;
|
|
count.Text = counts;
|
|
time.Text = _sport.GetFormatTimes();
|
|
ShowRope();
|
|
if (!_sport.IsCounting)
|
|
{
|
|
_sport.Stop();
|
|
_sport.Start();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
//展示成绩
|
|
private async void ShowRope()
|
|
{
|
|
// 渐变出现动画
|
|
var fadeInAnimation = new DoubleAnimation
|
|
{
|
|
From = 0,
|
|
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);
|
|
ImageBehavior.GetAnimationController(centerImg4).Pause();
|
|
|
|
//_mainWin.WebcamClient.OnExtractFrame -= this.OnFrameExtracted;
|
|
for (int i = 12; i >= 0; i--)
|
|
{
|
|
countDown.Text = i.ToString() + "s";
|
|
|
|
if (i == 8)
|
|
{
|
|
centerImg4.Visibility = Visibility.Hidden;
|
|
centerImg3.Visibility = Visibility.Visible;
|
|
}
|
|
if (i == 1)
|
|
{
|
|
RankingGrid.BeginAnimation(UIElement.OpacityProperty, fadeInAnimation1);
|
|
_sportType = 0;
|
|
PlayMusic("raisehand.mp3");
|
|
}
|
|
await Task.Delay(1000);
|
|
}
|
|
// 关闭跳远抽帧线程
|
|
}
|
|
|
|
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(x => x.Code == AppSettings.Code);
|
|
var boxes = new List<BoundingBox>()
|
|
{
|
|
new(){
|
|
ImageWidth = frameWidth,
|
|
ImageHeight = frameHeight,
|
|
Label = new PredictionLabel(){
|
|
Key = "begin"
|
|
},
|
|
MaskLayer = new MaskLayer(){
|
|
Contours = [
|
|
new ((float)points.BottomPoint3.X, (float)points.BottomPoint3.Y),
|
|
new ((float)points.TopPoint3.X, (float)points.TopPoint3.Y),
|
|
]
|
|
}
|
|
},
|
|
new(){
|
|
ImageWidth = frameWidth,
|
|
ImageHeight = frameHeight,
|
|
Label = new PredictionLabel{
|
|
Key = "end"
|
|
},
|
|
MaskLayer = new MaskLayer(){
|
|
Contours = [
|
|
new((float)points.BottomPoint2.X, (float)points.BottomPoint2.Y),
|
|
new((float)points.TopPoint2.X, (float)points.TopPoint2.Y),
|
|
]
|
|
}
|
|
}
|
|
};
|
|
|
|
boxes[1].Label.Key = "take-off";
|
|
boxes.Add(new BoundingBox()
|
|
{
|
|
ImageWidth = frameWidth,
|
|
ImageHeight = frameHeight,
|
|
Label = new PredictionLabel
|
|
{
|
|
Key = "end"
|
|
},
|
|
MaskLayer = new MaskLayer()
|
|
{
|
|
Contours = [
|
|
new ((float)points.BottomPoint1.X, (float)points.BottomPoint1.Y),
|
|
new ((float)points.TopPoint1.X, (float)points.TopPoint1.Y),
|
|
]
|
|
}
|
|
});
|
|
|
|
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(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)
|
|
{
|
|
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;
|
|
|
|
|
|
|
|
// 检测起跳区域的人
|
|
|
|
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()
|
|
{
|
|
|
|
Utils.PlayBackgroundMusic("countdown_3.mp3", false);
|
|
_mainWin.ShowCountDownAnimation();
|
|
centerImg3.Visibility = Visibility.Hidden;
|
|
centerImg4.Visibility = Visibility.Visible;
|
|
//if (_sport?.IsCounting == true)
|
|
//_mainWin.WebcamClient.OnExtractFrame += this.OnFrameExtracted;
|
|
}
|
|
|
|
|
|
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;
|
|
});
|
|
}
|
|
}
|
|
}
|