mirror of
https://github.com/azaion/annotations.git
synced 2026-04-23 04:36:31 +00:00
sort thumbnails by date in DatasetExplorer
This commit is contained in:
@@ -6,10 +6,10 @@ using System.Windows.Media;
|
||||
using Azaion.Annotator.DTO;
|
||||
using Azaion.Annotator.Extensions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using ScottPlot;
|
||||
using Color = ScottPlot.Color;
|
||||
using MessageBox = System.Windows.MessageBox;
|
||||
using Orientation = ScottPlot.Orientation;
|
||||
|
||||
namespace Azaion.Annotator;
|
||||
|
||||
@@ -22,10 +22,9 @@ public partial class DatasetExplorer
|
||||
private ObservableCollection<AnnotationClass> AllAnnotationClasses { get; set; } = new();
|
||||
|
||||
private int _tempSelectedClassIdx = 0;
|
||||
private readonly string _thumbnailsCacheFile;
|
||||
private readonly IConfigRepository _configRepository;
|
||||
private readonly FormState _formState;
|
||||
private static Dictionary<string, List<int>> LabelsCache { get; set; } = new();
|
||||
private readonly IGalleryManager _galleryManager;
|
||||
|
||||
public bool ThumbnailLoading { get; set; }
|
||||
|
||||
@@ -42,12 +41,7 @@ public partial class DatasetExplorer
|
||||
_logger = logger;
|
||||
_configRepository = configRepository;
|
||||
_formState = formState;
|
||||
_thumbnailsCacheFile = Path.Combine(config.ThumbnailsDirectory, Config.ThumbnailsCacheFile);
|
||||
if (File.Exists(_thumbnailsCacheFile))
|
||||
{
|
||||
var cache = JsonConvert.DeserializeObject<Dictionary<string, List<int>>>(File.ReadAllText(_thumbnailsCacheFile));
|
||||
LabelsCache = cache ?? new Dictionary<string, List<int>>();
|
||||
}
|
||||
_galleryManager = galleryManager;
|
||||
|
||||
InitializeComponent();
|
||||
Loaded += async (_, _) =>
|
||||
@@ -126,22 +120,6 @@ public partial class DatasetExplorer
|
||||
|
||||
Activated += (_, _) => { _formState.ActiveWindow = WindowsEnum.DatasetExplorer; };
|
||||
|
||||
Switcher.SelectionChanged += (sender, args) =>
|
||||
{
|
||||
switch (Switcher.SelectedIndex)
|
||||
{
|
||||
case 0: //ListView
|
||||
LvClasses.ItemsSource = AllAnnotationClasses;
|
||||
LvClasses.SelectedIndex = _tempSelectedClassIdx;
|
||||
ExplorerEditor.Background = null;
|
||||
break;
|
||||
case 1: //Editor
|
||||
_tempSelectedClassIdx = LvClasses.SelectedIndex;
|
||||
LvClasses.ItemsSource = _config.AnnotationClasses;
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
ExplorerEditor.GetTimeFunc = () => _formState.GetTime(CurrentThumbnail!.ImagePath);
|
||||
galleryManager.ThumbnailsUpdate += thumbnailsPercentage =>
|
||||
{
|
||||
@@ -152,7 +130,8 @@ public partial class DatasetExplorer
|
||||
|
||||
private void LoadClassDistribution()
|
||||
{
|
||||
var data = LabelsCache.SelectMany(x => x.Value)
|
||||
var data = _galleryManager.LabelsCache
|
||||
.SelectMany(x => x.Value.Classes)
|
||||
.GroupBy(x => x)
|
||||
.Select(x => new
|
||||
{
|
||||
@@ -163,7 +142,9 @@ public partial class DatasetExplorer
|
||||
})
|
||||
.ToList();
|
||||
|
||||
var foregroundColor = Color.FromColor(System.Drawing.Color.Black);
|
||||
var plot = ClassDistribution.Plot;
|
||||
|
||||
plot.Add.Bars(data.Select(x => new Bar
|
||||
{
|
||||
Orientation = Orientation.Horizontal,
|
||||
@@ -171,17 +152,21 @@ public partial class DatasetExplorer
|
||||
Label = x.ClassCount > 200 ? x.ClassCount.ToString() : "",
|
||||
FillColor = new Color(x.Color.R, x.Color.G, x.Color.B, x.Color.A),
|
||||
Value = x.ClassCount,
|
||||
CenterLabel = true
|
||||
CenterLabel = true,
|
||||
LabelOffset = 10
|
||||
}));
|
||||
|
||||
foreach (var x in data)
|
||||
{
|
||||
var label = plot.Add.Text(x.Name, 50, -1.5 * x.Key + 1.1);
|
||||
label.LabelFontSize = 16;
|
||||
label.LabelFontColor = foregroundColor;
|
||||
label.LabelFontSize = 18;
|
||||
}
|
||||
|
||||
plot.Axes.AutoScale();
|
||||
//plot.Axes.SetLimits(-200, data.Max(x => x.ClassCount + 3000), -2 * data.Count + 5, 5);
|
||||
ClassDistribution.Background = new SolidColorBrush(System.Windows.Media.Colors.Black);
|
||||
plot.HideAxesAndGrid();
|
||||
plot.FigureBackground.Color = new("#888888");
|
||||
|
||||
ClassDistribution.Refresh();
|
||||
}
|
||||
|
||||
@@ -200,9 +185,7 @@ public partial class DatasetExplorer
|
||||
{
|
||||
ImageSource = await dto.ImagePath.OpenImage()
|
||||
};
|
||||
|
||||
Switcher.SelectedIndex = 1;
|
||||
LvClasses.SelectedIndex = 1;
|
||||
SwitchTab(toEditor: true);
|
||||
|
||||
var time = _formState.GetTime(dto.ImagePath);
|
||||
ExplorerEditor.RemoveAllAnns();
|
||||
@@ -227,6 +210,28 @@ public partial class DatasetExplorer
|
||||
|
||||
}
|
||||
|
||||
public void SwitchTab(bool toEditor)
|
||||
{
|
||||
if (toEditor)
|
||||
{
|
||||
AnnotationsTab.Visibility = Visibility.Collapsed;
|
||||
EditorTab.Visibility = Visibility.Visible;
|
||||
_tempSelectedClassIdx = LvClasses.SelectedIndex;
|
||||
LvClasses.ItemsSource = _config.AnnotationClasses;
|
||||
|
||||
Switcher.SelectedIndex = 1;
|
||||
LvClasses.SelectedIndex = Math.Max(0, _tempSelectedClassIdx - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
AnnotationsTab.Visibility = Visibility.Visible;
|
||||
EditorTab.Visibility = Visibility.Collapsed;
|
||||
LvClasses.ItemsSource = AllAnnotationClasses;
|
||||
LvClasses.SelectedIndex = _tempSelectedClassIdx;
|
||||
Switcher.SelectedIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SaveUserSettings()
|
||||
{
|
||||
_config.DatasetExplorerConfig = this.GetConfig();
|
||||
@@ -264,81 +269,78 @@ public partial class DatasetExplorer
|
||||
if (!Directory.Exists(_config.ThumbnailsDirectory))
|
||||
return;
|
||||
|
||||
ThumbnailsDtos.Clear();
|
||||
var thumbnails = Directory.GetFiles(_config.ThumbnailsDirectory, "*.jpg");
|
||||
|
||||
var thumbNum = 0;
|
||||
foreach (var thumbnail in thumbnails)
|
||||
var thumbnailDtos = new List<ThumbnailDto>();
|
||||
for (int i = 0; i < thumbnails.Length; i++)
|
||||
{
|
||||
await AddThumbnail(thumbnail);
|
||||
var thumbnailDto = GetThumbnail(thumbnails[i]);
|
||||
if (thumbnailDto != null)
|
||||
thumbnailDtos.Add(thumbnailDto);
|
||||
|
||||
if (thumbNum % 1000 == 0)
|
||||
{
|
||||
await File.WriteAllTextAsync(_thumbnailsCacheFile, JsonConvert.SerializeObject(LabelsCache));
|
||||
LoadingAnnsBar.Value = thumbNum * 100.0 / thumbnails.Length;
|
||||
}
|
||||
thumbNum++;
|
||||
if (i % 1000 == 0)
|
||||
LoadingAnnsBar.Value = i * 100.0 / thumbnails.Length;
|
||||
}
|
||||
|
||||
ThumbnailsDtos.Clear();
|
||||
foreach (var th in thumbnailDtos.OrderByDescending(x => x.ImageDate))
|
||||
ThumbnailsDtos.Add(th);
|
||||
|
||||
LoadingAnnsCaption.Visibility = Visibility.Collapsed;
|
||||
LoadingAnnsBar.Visibility = Visibility.Collapsed;
|
||||
await File.WriteAllTextAsync(_thumbnailsCacheFile, JsonConvert.SerializeObject(LabelsCache));
|
||||
}
|
||||
|
||||
private async Task AddThumbnail(string thumbnail, CancellationToken cancellationToken = default)
|
||||
private ThumbnailDto? GetThumbnail(string thumbnail)
|
||||
{
|
||||
try
|
||||
{
|
||||
var name = Path.GetFileNameWithoutExtension(thumbnail)[..^Config.ThumbnailPrefix.Length];
|
||||
var imageName = Path.Combine(_config.ImagesDirectory, name);
|
||||
var imagePath = Path.Combine(_config.ImagesDirectory, name);
|
||||
foreach (var f in _config.ImageFormats)
|
||||
{
|
||||
var curName = $"{imageName}.{f}";
|
||||
var curName = $"{imagePath}.{f}";
|
||||
if (File.Exists(curName))
|
||||
{
|
||||
imageName = curName;
|
||||
imagePath = curName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var labelPath = Path.Combine(_config.LabelsDirectory, $"{name}.txt");
|
||||
|
||||
if (!LabelsCache.TryGetValue(name, out var classes))
|
||||
if (!_galleryManager.LabelsCache.TryGetValue(Path.GetFileName(imagePath), out var info))
|
||||
{
|
||||
if (!File.Exists(labelPath))
|
||||
if (File.Exists(labelPath))
|
||||
return null;
|
||||
|
||||
var imageExists = File.Exists(imagePath);
|
||||
if (!imageExists)
|
||||
{
|
||||
var imageExists = File.Exists(imageName);
|
||||
if (!imageExists)
|
||||
{
|
||||
_logger.LogError($"No label {labelPath} found ! Image {imageName} not found, removing thumbnail {thumbnail}");
|
||||
File.Delete(thumbnail);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogError($"No label {labelPath} found! But Image {imageName} exists! Image moved to {_config.UnknownImages} directory!");
|
||||
File.Move(imageName, Path.Combine(_config.UnknownImages, imageName));
|
||||
}
|
||||
return;
|
||||
File.Delete(thumbnail);
|
||||
_logger.LogError($"No label {labelPath} found ! Image {imagePath} not found, thumbnail {thumbnail} was removed");
|
||||
}
|
||||
|
||||
var labels = await YoloLabel.ReadFromFile(labelPath, cancellationToken);
|
||||
classes = labels.Select(x => x.ClassNumber).Distinct().ToList();
|
||||
LabelsCache.Add(name, classes);
|
||||
}
|
||||
|
||||
if (classes.Contains(ExplorerEditor.CurrentAnnClass.Id) || ExplorerEditor.CurrentAnnClass.Id == -1)
|
||||
{
|
||||
ThumbnailsDtos.Add(new ThumbnailDto
|
||||
else
|
||||
{
|
||||
ThumbnailPath = thumbnail,
|
||||
ImagePath = imageName,
|
||||
LabelPath = labelPath
|
||||
});
|
||||
File.Move(imagePath, Path.Combine(_config.UnknownImages, imagePath));
|
||||
_logger.LogError($"No label {labelPath} found! But Image {imagePath} exists! Image moved to {_config.UnknownImages} directory!");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!info.Classes.Contains(ExplorerEditor.CurrentAnnClass.Id) && ExplorerEditor.CurrentAnnClass.Id != -1)
|
||||
return null;
|
||||
|
||||
return new ThumbnailDto
|
||||
{
|
||||
ThumbnailPath = thumbnail,
|
||||
ImagePath = imagePath,
|
||||
LabelPath = labelPath,
|
||||
ImageDate = info.ImageDateTime
|
||||
};
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, e.Message);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user