add results pane

differentiate already processed videos
This commit is contained in:
Oleksandr Bezdieniezhnykh
2024-07-18 21:40:15 +03:00
parent 71006a2462
commit 288a34e992
6 changed files with 63 additions and 45 deletions
+4
View File
@@ -6,9 +6,13 @@ public class AnnotationResult
{ {
[JsonProperty(PropertyName = "f")] [JsonProperty(PropertyName = "f")]
public string Image { get; set; } = null!; public string Image { get; set; } = null!;
[JsonProperty(PropertyName = "t")] [JsonProperty(PropertyName = "t")]
public TimeSpan Time { get; set; } public TimeSpan Time { get; set; }
[JsonIgnore]
public string TimeStr => $"{Time:h\\:mm\\:ss}";
[JsonProperty(PropertyName = "p")] [JsonProperty(PropertyName = "p")]
public double Percentage { get; set; } public double Percentage { get; set; }
+4 -3
View File
@@ -2,7 +2,8 @@
public class VideoFileInfo public class VideoFileInfo
{ {
public string Name { get; set; } = null!; public string Name { get; set; } = null!;
public string Path { get; set; } = null!; public string Path { get; set; } = null!;
public TimeSpan Duration { get; set; } public TimeSpan Duration { get; set; }
public bool HasAnnotations { get; set; }
} }
+18 -13
View File
@@ -105,9 +105,18 @@
<ListView Grid.Row="2" <ListView Grid.Row="2"
Grid.Column="0" Grid.Column="0"
Name="LvFiles" Name="LvFiles"
Background="Black" Background="Black"
SelectedItem="{Binding Path=SelectedVideo}" Foreground="#FFA4AFCC" SelectedItem="{Binding Path=SelectedVideo}" Foreground="#FFA4AFCC"
> >
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding HasAnnotations}" Value="true">
<Setter Property="Background" Value="Gray"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.Resources>
<ListView.View> <ListView.View>
<GridView> <GridView>
<GridViewColumn Width="Auto" <GridViewColumn Width="Auto"
@@ -197,24 +206,20 @@
CanUserResizeRows="False" CanUserResizeRows="False"
CanUserResizeColumns="False"> CanUserResizeColumns="False">
<DataGrid.Columns> <DataGrid.Columns>
<DataGridTemplateColumn <DataGridTextColumn
Width="120" Width="120"
Header="Кадр" Header="Кадр"
CanUserSort="False"> CanUserSort="False"
<DataGridTemplateColumn.HeaderStyle> Binding="{Binding Path=TimeStr}">
<DataGridTextColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader"> <Style TargetType="DataGridColumnHeader">
<Setter Property="Background" Value="#252525"></Setter> <Setter Property="Background" Value="#252525"></Setter>
</Style> </Style>
</DataGridTemplateColumn.HeaderStyle> </DataGridTextColumn.HeaderStyle>
<DataGridTemplateColumn.CellTemplate> </DataGridTextColumn>
<DataTemplate>
<TextBlock Text="{Binding Path=ClassNumber}"></TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn <DataGridTextColumn
Width="*" Width="*"
Header="Клас" Header="Клас"
Binding="{Binding Path=Name}" Binding="{Binding Path=Name}"
CanUserSort="False"> CanUserSort="False">
<DataGridTextColumn.HeaderStyle> <DataGridTextColumn.HeaderStyle>
+10 -2
View File
@@ -153,6 +153,7 @@ public partial class MainWindow
{ {
Annotations = LoadAnnotations(); Annotations = LoadAnnotations();
_formState.AnnotationResults = LoadAnnotationResults(); _formState.AnnotationResults = LoadAnnotationResults();
DgAnnotations.ItemsSource = _formState.AnnotationResults;
} }
private Dictionary<TimeSpan, List<YoloLabel>> LoadAnnotations() private Dictionary<TimeSpan, List<YoloLabel>> LoadAnnotations()
@@ -205,16 +206,23 @@ public partial class MainWindow
var dir = new DirectoryInfo(_config.VideosDirectory); var dir = new DirectoryInfo(_config.VideosDirectory);
if (!dir.Exists) if (!dir.Exists)
return; return;
var labelNames = new DirectoryInfo(_config.LabelsDirectory).GetFiles()
.Select(x => x.Name[..^11])
.GroupBy(x => x)
.Select(gr => gr.Key)
.ToDictionary(x => x);
var files = dir.GetFiles("mp4", "mov").Select(x => var files = dir.GetFiles("mp4", "mov").Select(x =>
{ {
_mediaPlayer.Media = new Media(_libVLC, x.FullName); _mediaPlayer.Media = new Media(_libVLC, x.FullName);
return new VideoFileInfo return new VideoFileInfo
{ {
Name = x.Name, Name = x.Name,
Path = x.FullName, Path = x.FullName,
Duration = TimeSpan.FromMilliseconds(_mediaPlayer.Media.Duration) Duration = TimeSpan.FromMilliseconds(_mediaPlayer.Media.Duration),
HasAnnotations = labelNames.ContainsKey(Path.GetFileNameWithoutExtension(x.Name).Replace(" ", ""))
}; };
}).ToList(); }).ToList();
+26 -26
View File
@@ -9,21 +9,21 @@ using Newtonsoft.Json;
namespace Azaion.Annotator; namespace Azaion.Annotator;
public class PlayerControlHandler(LibVLC libVLC, MediaPlayer mediaPlayer, MainWindow mainWindow, FormState formState, Config config) : public class PlayerControlHandler(LibVLC libVLC, MediaPlayer mediaPlayer, MainWindow mainWindow, FormState formState, Config config) :
INotificationHandler<KeyEvent>, INotificationHandler<KeyEvent>,
INotificationHandler<AnnClassSelectedEvent>, INotificationHandler<AnnClassSelectedEvent>,
INotificationHandler<PlaybackControlEvent>, INotificationHandler<PlaybackControlEvent>,
INotificationHandler<VolumeChangedEvent> INotificationHandler<VolumeChangedEvent>
{ {
private const int STEP = 20; private const int STEP = 20;
private const int LARGE_STEP = 5000; private const int LARGE_STEP = 5000;
private const int RESULT_WIDTH = 1280; private const int RESULT_WIDTH = 1280;
private static readonly string[] CatchSenders = ["ForegroundWindow", "ScrollViewer", "VideoView"]; private static readonly string[] CatchSenders = ["ForegroundWindow", "ScrollViewer", "VideoView"];
private readonly Dictionary<Key, PlaybackControlEnum> KeysControlEnumDict = new() private readonly Dictionary<Key, PlaybackControlEnum> KeysControlEnumDict = new()
{ {
{ Key.Space, PlaybackControlEnum.Pause }, { Key.Space, PlaybackControlEnum.Pause },
{ Key.Left, PlaybackControlEnum.PreviousFrame }, { Key.Left, PlaybackControlEnum.PreviousFrame },
{ Key.Right, PlaybackControlEnum.NextFrame }, { Key.Right, PlaybackControlEnum.NextFrame },
{ Key.Enter, PlaybackControlEnum.SaveAnnotations }, { Key.Enter, PlaybackControlEnum.SaveAnnotations },
{ Key.Delete, PlaybackControlEnum.RemoveSelectedAnns }, { Key.Delete, PlaybackControlEnum.RemoveSelectedAnns },
@@ -34,13 +34,13 @@ public class PlayerControlHandler(LibVLC libVLC, MediaPlayer mediaPlayer, MainWi
{ {
SelectClass(notification.AnnotationClass); SelectClass(notification.AnnotationClass);
await Task.CompletedTask; await Task.CompletedTask;
} }
private void SelectClass(AnnotationClass annClass) private void SelectClass(AnnotationClass annClass)
{ {
mainWindow.Editor.CurrentAnnClass = annClass; mainWindow.Editor.CurrentAnnClass = annClass;
foreach (var ann in mainWindow.Editor.CurrentAnns.Where(x => x.IsSelected)) foreach (var ann in mainWindow.Editor.CurrentAnns.Where(x => x.IsSelected))
ann.AnnotationClass = annClass; ann.AnnotationClass = annClass;
mainWindow.LvClasses.SelectedIndex = annClass.Id; mainWindow.LvClasses.SelectedIndex = annClass.Id;
} }
@@ -49,18 +49,18 @@ public class PlayerControlHandler(LibVLC libVLC, MediaPlayer mediaPlayer, MainWi
{ {
if (!CatchSenders.Contains(notification.Sender.GetType().Name)) if (!CatchSenders.Contains(notification.Sender.GetType().Name))
return; return;
var key = notification.Args.Key; var key = notification.Args.Key;
var keyNumber = (int?)null; var keyNumber = (int?)null;
if ((int)key >= (int)Key.D1 && (int)key <= (int)Key.D9) if ((int)key >= (int)Key.D1 && (int)key <= (int)Key.D9)
keyNumber = key - Key.D1; keyNumber = key - Key.D1;
if ((int)key >= (int)Key.NumPad1 && (int)key <= (int)Key.NumPad9) if ((int)key >= (int)Key.NumPad1 && (int)key <= (int)Key.NumPad9)
keyNumber = key - Key.NumPad1; keyNumber = key - Key.NumPad1;
if (keyNumber.HasValue) if (keyNumber.HasValue)
SelectClass(mainWindow.AnnotationClasses[keyNumber.Value]); SelectClass(mainWindow.AnnotationClasses[keyNumber.Value]);
if (KeysControlEnumDict.TryGetValue(key, out var value)) if (KeysControlEnumDict.TryGetValue(key, out var value))
await ControlPlayback(value); await ControlPlayback(value);
await VolumeControl(key); await VolumeControl(key);
@@ -80,7 +80,7 @@ public class PlayerControlHandler(LibVLC libVLC, MediaPlayer mediaPlayer, MainWi
case Key.VolumeUp: case Key.VolumeUp:
var vUp = Math.Min(100, mediaPlayer.Volume + 5); var vUp = Math.Min(100, mediaPlayer.Volume + 5);
ChangeVolume(vUp); ChangeVolume(vUp);
mainWindow.Volume.Value = vUp; mainWindow.Volume.Value = vUp;
break; break;
case Key.Down: case Key.Down:
case Key.VolumeDown: case Key.VolumeDown:
@@ -111,7 +111,7 @@ public class PlayerControlHandler(LibVLC libVLC, MediaPlayer mediaPlayer, MainWi
break; break;
case PlaybackControlEnum.Pause: case PlaybackControlEnum.Pause:
mediaPlayer.Pause(); mediaPlayer.Pause();
if (!mediaPlayer.IsPlaying) if (!mediaPlayer.IsPlaying)
mainWindow.BlinkHelp(HelpTexts.HelpTextsDict[HelpTextEnum.AnnotationHelp]); mainWindow.BlinkHelp(HelpTexts.HelpTextsDict[HelpTextEnum.AnnotationHelp]);
break; break;
case PlaybackControlEnum.Stop: case PlaybackControlEnum.Stop:
@@ -171,7 +171,7 @@ public class PlayerControlHandler(LibVLC libVLC, MediaPlayer mediaPlayer, MainWi
formState.CurrentVolume = volume; formState.CurrentVolume = volume;
mediaPlayer.Volume = volume; mediaPlayer.Volume = volume;
} }
private void Play() private void Play()
{ {
if (mainWindow.LvFiles.SelectedItem == null) if (mainWindow.LvFiles.SelectedItem == null)
@@ -180,12 +180,12 @@ public class PlayerControlHandler(LibVLC libVLC, MediaPlayer mediaPlayer, MainWi
formState.CurrentFile = fileInfo.Name; formState.CurrentFile = fileInfo.Name;
mainWindow.LoadExistingAnnotations(); mainWindow.LoadExistingAnnotations();
mediaPlayer.Stop(); mediaPlayer.Stop();
mediaPlayer.Play(new Media(libVLC, fileInfo.Path)); mediaPlayer.Play(new Media(libVLC, fileInfo.Path));
mainWindow.BlinkHelp(HelpTexts.HelpTextsDict[HelpTextEnum.PauseForAnnotations]); mainWindow.BlinkHelp(HelpTexts.HelpTextsDict[HelpTextEnum.PauseForAnnotations]);
} }
private async Task SaveAnnotations() private async Task SaveAnnotations()
{ {
if (string.IsNullOrEmpty(formState.CurrentFile)) if (string.IsNullOrEmpty(formState.CurrentFile))
@@ -204,18 +204,18 @@ public class PlayerControlHandler(LibVLC libVLC, MediaPlayer mediaPlayer, MainWi
Directory.CreateDirectory(config.ImagesDirectory); Directory.CreateDirectory(config.ImagesDirectory);
if (!Directory.Exists(config.ResultsDirectory)) if (!Directory.Exists(config.ResultsDirectory))
Directory.CreateDirectory(config.ResultsDirectory); Directory.CreateDirectory(config.ResultsDirectory);
await File.WriteAllTextAsync($"{config.LabelsDirectory}/{fName}.txt", labels); await File.WriteAllTextAsync($"{config.LabelsDirectory}/{fName}.txt", labels);
formState.AnnotationResults.Add(new AnnotationResult(time, fName, currentAnns)); formState.AnnotationResults.Add(new AnnotationResult(time, fName, currentAnns));
await File.WriteAllTextAsync($"{config.ResultsDirectory}/{fName}.json", JsonConvert.SerializeObject(formState.AnnotationResults)); await File.WriteAllTextAsync($"{config.ResultsDirectory}/{fName}.json", JsonConvert.SerializeObject(formState.AnnotationResults));
var resultHeight = (uint)Math.Round(RESULT_WIDTH / formState.CurrentVideoSize.Width * formState.CurrentVideoSize.Height); var resultHeight = (uint)Math.Round(RESULT_WIDTH / formState.CurrentVideoSize.Width * formState.CurrentVideoSize.Height);
mediaPlayer.TakeSnapshot(0, $"{config.ImagesDirectory}/{fName}.jpg", RESULT_WIDTH, resultHeight); mediaPlayer.TakeSnapshot(0, $"{config.ImagesDirectory}/{fName}.jpg", RESULT_WIDTH, resultHeight);
mainWindow.Annotations[time] = currentAnns; mainWindow.Annotations[time] = currentAnns;
mainWindow.Editor.RemoveAllAnns(); mainWindow.Editor.RemoveAllAnns();
mediaPlayer.Play(); mediaPlayer.Play();
} }
} }
+1 -1
View File
@@ -1,5 +1,5 @@
{ {
"VideosDirectory": "E:\\Azaion3\\Videos", "VideosDirectory": "E:\\Azaion3\\VideosDone",
"LabelsDirectory": "E:\\labels", "LabelsDirectory": "E:\\labels",
"ImagesDirectory": "E:\\images", "ImagesDirectory": "E:\\images",
"ResultsDirectory": "E:\\results", "ResultsDirectory": "E:\\results",