sort thumbnails by date in DatasetExplorer

This commit is contained in:
Alex Bezdieniezhnykh
2024-09-29 16:24:31 +03:00
parent 22d4493d86
commit d2186eb326
8 changed files with 182 additions and 108 deletions
+63 -26
View File
@@ -1,10 +1,12 @@
using System.Drawing;
using System.Collections.Concurrent;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using Azaion.Annotator.DTO;
using Azaion.Annotator.Extensions;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Color = System.Drawing.Color;
using ParallelOptions = Azaion.Annotator.Extensions.ParallelOptions;
using Size = System.Windows.Size;
@@ -13,15 +15,21 @@ namespace Azaion.Annotator;
public delegate void ThumbnailsUpdatedEventHandler(double thumbnailsPercentage);
public class GalleryManager(Config config, ILogger<GalleryManager> logger) : IGalleryManager
public class GalleryManager : IGalleryManager
{
private readonly ILogger<GalleryManager> _logger;
public event ThumbnailsUpdatedEventHandler ThumbnailsUpdate;
private readonly string _thumbnailsCacheFile;
private readonly SemaphoreSlim _updateLock = new(1);
public double ThumbnailsPercentage { get; set; }
public ConcurrentDictionary<string, LabelInfo> LabelsCache { get; set; } = new();
private DirectoryInfo? _thumbnailsDirectory;
private readonly Config _config;
private DirectoryInfo ThumbnailsDirectory
{
get
@@ -29,17 +37,24 @@ public class GalleryManager(Config config, ILogger<GalleryManager> logger) : IGa
if (_thumbnailsDirectory != null)
return _thumbnailsDirectory;
var dir = new DirectoryInfo(config.ThumbnailsDirectory);
var dir = new DirectoryInfo(_config.ThumbnailsDirectory);
if (!dir.Exists)
Directory.CreateDirectory(config.ThumbnailsDirectory);
_thumbnailsDirectory = new DirectoryInfo(config.ThumbnailsDirectory);
Directory.CreateDirectory(_config.ThumbnailsDirectory);
_thumbnailsDirectory = new DirectoryInfo(_config.ThumbnailsDirectory);
return _thumbnailsDirectory;
}
}
public GalleryManager(Config config, ILogger<GalleryManager> logger)
{
_config = config;
_logger = logger;
_thumbnailsCacheFile = Path.Combine(config.ThumbnailsDirectory, Config.ThumbnailsCacheFile);
}
public void ClearThumbnails()
{
foreach(var file in new DirectoryInfo(config.ThumbnailsDirectory).GetFiles())
foreach(var file in new DirectoryInfo(_config.ThumbnailsDirectory).GetFiles())
file.Delete();
}
@@ -56,7 +71,16 @@ public class GalleryManager(Config config, ILogger<GalleryManager> logger) : IGa
.Select(gr => gr.Key)
.ToHashSet();
var files = new DirectoryInfo(config.ImagesDirectory).GetFiles();
if (File.Exists(_thumbnailsCacheFile))
{
var cache = JsonConvert.DeserializeObject<ConcurrentDictionary<string, LabelInfo>>(
await File.ReadAllTextAsync(_thumbnailsCacheFile), new DenseDateTimeConverter());
LabelsCache = cache ?? new ConcurrentDictionary<string, LabelInfo>();
}
else
LabelsCache = new ConcurrentDictionary<string, LabelInfo>();
var files = new DirectoryInfo(_config.ImagesDirectory).GetFiles();
var imagesCount = files.Length;
await ParallelExt.ForEachAsync(files, async (file, cancellationToken) =>
@@ -70,7 +94,7 @@ public class GalleryManager(Config config, ILogger<GalleryManager> logger) : IGa
}
catch (Exception e)
{
logger.LogError(e, $"Failed to generate thumbnail for {file.Name}! Error: {e.Message}");
_logger.LogError(e, $"Failed to generate thumbnail for {file.Name}! Error: {e.Message}");
}
}, new ParallelOptions
{
@@ -87,29 +111,26 @@ public class GalleryManager(Config config, ILogger<GalleryManager> logger) : IGa
}
finally
{
await SaveLabelsCache();
_updateLock.Release();
}
}
public async Task CreateThumbnail(string imgPath, CancellationToken cancellationToken = default)
public async Task SaveLabelsCache()
{
var bitmap = await GenerateThumbnail(imgPath);
if (bitmap != null)
{
var thumbnailName = Path.Combine(ThumbnailsDirectory.FullName, $"{Path.GetFileNameWithoutExtension(imgPath)}{Config.ThumbnailPrefix}.jpg");
bitmap.Save(thumbnailName, ImageFormat.Jpeg);
}
var labelsCacheStr = JsonConvert.SerializeObject(LabelsCache, new DenseDateTimeConverter());
await File.WriteAllTextAsync(_thumbnailsCacheFile, labelsCacheStr);
}
private async Task<Bitmap?> GenerateThumbnail(string imgPath)
public async Task CreateThumbnail(string imgPath, CancellationToken cancellationToken = default)
{
var width = (int)config.ThumbnailConfig.Size.Width;
var height = (int)config.ThumbnailConfig.Size.Height;
var width = (int)_config.ThumbnailConfig.Size.Width;
var height = (int)_config.ThumbnailConfig.Size.Height;
var imgName = Path.GetFileName(imgPath);
var labelName = Path.Combine(config.LabelsDirectory, $"{Path.GetFileNameWithoutExtension(imgPath)}.txt");
var labelName = Path.Combine(_config.LabelsDirectory, $"{Path.GetFileNameWithoutExtension(imgPath)}.txt");
var originalImage = Image.FromStream(new MemoryStream(await File.ReadAllBytesAsync(imgPath)));
var originalImage = Image.FromStream(new MemoryStream(await File.ReadAllBytesAsync(imgPath, cancellationToken)));
var bitmap = new Bitmap(width, height);
@@ -121,16 +142,23 @@ public class GalleryManager(Config config, ILogger<GalleryManager> logger) : IGa
var size = new Size(originalImage.Width, originalImage.Height);
if (!File.Exists(labelName))
{
File.Move(imgPath, Path.Combine(config.UnknownImages, imgName));
logger.LogInformation($"No labels found for image {imgName}! Moved image to the {config.UnknownImages} folder.");
return null;
File.Move(imgPath, Path.Combine(_config.UnknownImages, imgName));
_logger.LogInformation($"No labels found for image {imgName}! Moved image to the {_config.UnknownImages} folder.");
return;
}
var labels = (await YoloLabel.ReadFromFile(labelName))
.Select(x => new CanvasLabel(x, size, size))
.ToList();
var thumbWhRatio = width / (float)height;
var border = config.ThumbnailConfig.Border;
var border = _config.ThumbnailConfig.Border;
var classes = labels.Select(x => x.ClassNumber).Distinct().ToList();
LabelsCache.TryAdd(imgName, new LabelInfo
{
Classes = classes,
ImageDateTime = File.GetCreationTimeUtc(imgPath)
});
var frameX = 0.0;
var frameY = 0.0;
@@ -169,13 +197,20 @@ public class GalleryManager(Config config, ILogger<GalleryManager> logger) : IGa
foreach (var label in labels)
{
var color = config.AnnotationClassesDict[label.ClassNumber].Color;
var color = _config.AnnotationClassesDict[label.ClassNumber].Color;
var brush = new SolidBrush(Color.FromArgb(color.A, color.R, color.G, color.B));
var rectangle = new RectangleF((float)((label.X - frameX) / scale), (float)((label.Y - frameY) / scale), (float)(label.Width / scale), (float)(label.Height / scale));
g.FillRectangle(brush, rectangle);
}
return bitmap;
if (bitmap != null)
{
var thumbnailName = Path.Combine(ThumbnailsDirectory.FullName, $"{Path.GetFileNameWithoutExtension(imgPath)}{Config.ThumbnailPrefix}.jpg");
bitmap.Save(thumbnailName, ImageFormat.Jpeg);
}
}
}
@@ -183,6 +218,8 @@ public interface IGalleryManager
{
event ThumbnailsUpdatedEventHandler ThumbnailsUpdate;
double ThumbnailsPercentage { get; set; }
Task SaveLabelsCache();
ConcurrentDictionary<string, LabelInfo> LabelsCache { get; set; }
Task CreateThumbnail(string imgPath, CancellationToken cancellationToken = default);
Task RefreshThumbnails();
void ClearThumbnails();