mirror of
https://github.com/azaion/annotations.git
synced 2026-04-22 12:56:30 +00:00
big refactoring. get rid of static properties and coupled architecture. prepare system for integration tests
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
<Window x:Class="Azaion.Annotator.Annotator"
|
||||
<Window x:Class="Azaion.Annotator.Annotator"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
@@ -256,7 +256,8 @@
|
||||
IsReadOnly="True"
|
||||
CanUserResizeRows="False"
|
||||
CanUserResizeColumns="False"
|
||||
RowStyleSelector="{StaticResource GradientStyleSelector}">
|
||||
RowStyleSelector="{StaticResource GradientStyleSelector}"
|
||||
local:GradientStyleSelector.ClassProvider="{Binding ClassProvider, RelativeSource={RelativeSource AncestorType=local:Annotator}}">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn
|
||||
Width="60"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
@@ -63,6 +63,11 @@ public partial class Annotator
|
||||
public CameraConfig Camera => _appConfig?.CameraConfig ?? new CameraConfig();
|
||||
private static readonly Guid ReloadTaskId = Guid.NewGuid();
|
||||
|
||||
private readonly IAnnotationPathResolver _pathResolver;
|
||||
private readonly IDetectionClassProvider _classProvider;
|
||||
|
||||
public IDetectionClassProvider ClassProvider => _classProvider;
|
||||
|
||||
public Annotator(
|
||||
IConfigUpdater configUpdater,
|
||||
IOptions<AppConfig> appConfig,
|
||||
@@ -75,8 +80,12 @@ public partial class Annotator
|
||||
IDbFactory dbFactory,
|
||||
IInferenceService inferenceService,
|
||||
IInferenceClient inferenceClient,
|
||||
IGpsMatcherService gpsMatcherService)
|
||||
IGpsMatcherService gpsMatcherService,
|
||||
IAnnotationPathResolver pathResolver,
|
||||
IDetectionClassProvider classProvider)
|
||||
{
|
||||
_pathResolver = pathResolver;
|
||||
_classProvider = classProvider;
|
||||
// Initialize configuration and services BEFORE InitializeComponent so bindings can see real values
|
||||
_appConfig = appConfig.Value;
|
||||
_configUpdater = configUpdater;
|
||||
@@ -270,9 +279,10 @@ public partial class Annotator
|
||||
{
|
||||
Dispatcher.Invoke(async () =>
|
||||
{
|
||||
if (showImage && !annotation.IsSplit && File.Exists(annotation.ImagePath))
|
||||
var imagePath = _pathResolver.GetImagePath(annotation);
|
||||
if (showImage && !annotation.IsSplit && File.Exists(imagePath))
|
||||
{
|
||||
Editor.SetBackground(await annotation.ImagePath.OpenImage());
|
||||
Editor.SetBackground(await imagePath.OpenImage());
|
||||
_formState.BackgroundTime = annotation.Time;
|
||||
}
|
||||
|
||||
@@ -648,11 +658,30 @@ public partial class Annotator
|
||||
|
||||
public class GradientStyleSelector : StyleSelector
|
||||
{
|
||||
public static readonly DependencyProperty ClassProviderProperty = DependencyProperty.RegisterAttached(
|
||||
"ClassProvider",
|
||||
typeof(IDetectionClassProvider),
|
||||
typeof(GradientStyleSelector),
|
||||
new PropertyMetadata(null));
|
||||
|
||||
public static void SetClassProvider(DependencyObject element, IDetectionClassProvider value)
|
||||
{
|
||||
element.SetValue(ClassProviderProperty, value);
|
||||
}
|
||||
|
||||
public static IDetectionClassProvider GetClassProvider(DependencyObject element)
|
||||
{
|
||||
return (IDetectionClassProvider)element.GetValue(ClassProviderProperty);
|
||||
}
|
||||
|
||||
public override Style? SelectStyle(object item, DependencyObject container)
|
||||
{
|
||||
if (container is not DataGridRow row || row.DataContext is not Annotation result)
|
||||
return null;
|
||||
|
||||
var dataGrid = FindParent<DataGrid>(row);
|
||||
var classProvider = dataGrid != null ? GetClassProvider(dataGrid) : null;
|
||||
|
||||
var style = new Style(typeof(DataGridRow));
|
||||
var brush = new LinearGradientBrush
|
||||
{
|
||||
@@ -661,16 +690,17 @@ public class GradientStyleSelector : StyleSelector
|
||||
};
|
||||
|
||||
var gradients = new List<GradientStop>();
|
||||
if (result.Colors.Count == 0)
|
||||
var colors = classProvider?.GetColors(result) ?? [];
|
||||
if (colors.Count == 0)
|
||||
{
|
||||
var color = (Color)ColorConverter.ConvertFromString("#40DDDDDD");
|
||||
gradients = [new GradientStop(color, 0.99)];
|
||||
}
|
||||
else
|
||||
{
|
||||
var increment = 1.0 / result.Colors.Count;
|
||||
var increment = 1.0 / colors.Count;
|
||||
var currentStop = increment;
|
||||
foreach (var c in result.Colors)
|
||||
foreach (var c in colors)
|
||||
{
|
||||
var resultColor = c.Color.ToConfidenceColor(c.Confidence);
|
||||
brush.GradientStops.Add(new GradientStop(resultColor, currentStop));
|
||||
@@ -683,4 +713,16 @@ public class GradientStyleSelector : StyleSelector
|
||||
style.Setters.Add(new Setter(Control.BackgroundProperty, brush));
|
||||
return style;
|
||||
}
|
||||
|
||||
private static T? FindParent<T>(DependencyObject child) where T : DependencyObject
|
||||
{
|
||||
var parent = VisualTreeHelper.GetParent(child);
|
||||
while (parent != null)
|
||||
{
|
||||
if (parent is T typedParent)
|
||||
return typedParent;
|
||||
parent = VisualTreeHelper.GetParent(parent);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,10 @@ public class AnnotatorEventHandler(
|
||||
IInferenceService inferenceService,
|
||||
IDbFactory dbFactory,
|
||||
IAzaionApi api,
|
||||
FailsafeAnnotationsProducer producer)
|
||||
FailsafeAnnotationsProducer producer,
|
||||
IAnnotationPathResolver pathResolver,
|
||||
IFileSystem fileSystem,
|
||||
IUICommandDispatcher uiDispatcher)
|
||||
:
|
||||
INotificationHandler<KeyEvent>,
|
||||
INotificationHandler<AnnClassSelectedEvent>,
|
||||
@@ -318,7 +321,7 @@ public class AnnotatorEventHandler(
|
||||
var annotationsResult = new List<Annotation>();
|
||||
var time = formState.BackgroundTime ?? TimeSpan.FromMilliseconds(mediaPlayer.Time);
|
||||
|
||||
if (!File.Exists(imgPath))
|
||||
if (!fileSystem.FileExists(imgPath))
|
||||
{
|
||||
if (mediaSize.FitSizeForAI())
|
||||
await source.SaveImage(imgPath, ct);
|
||||
@@ -339,7 +342,8 @@ public class AnnotatorEventHandler(
|
||||
{
|
||||
var annotationName = $"{formState.CurrentMedia?.Name ?? ""}{Constants.SPLIT_SUFFIX}{res.Tile.Width}_{res.Tile.Left:0000}_{res.Tile.Top:0000}!".ToTimeName(time);
|
||||
|
||||
var tileImgPath = Path.Combine(dirConfig.Value.ImagesDirectory, $"{annotationName}{Constants.JPG_EXT}");
|
||||
var tempAnnotation = new Annotation { Name = annotationName, ImageExtension = Constants.JPG_EXT };
|
||||
var tileImgPath = pathResolver.GetImagePath(tempAnnotation);
|
||||
var bitmap = new CroppedBitmap(source, new Int32Rect((int)res.Tile.Left, (int)res.Tile.Top, (int)res.Tile.Width, (int)res.Tile.Height));
|
||||
await bitmap.SaveImage(tileImgPath, ct);
|
||||
|
||||
@@ -367,7 +371,7 @@ public class AnnotatorEventHandler(
|
||||
{
|
||||
try
|
||||
{
|
||||
mainWindow.Dispatcher.Invoke(() =>
|
||||
uiDispatcher.Execute(() =>
|
||||
{
|
||||
var namesSet = notification.AnnotationNames.ToHashSet();
|
||||
|
||||
@@ -391,10 +395,11 @@ public class AnnotatorEventHandler(
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(Path.Combine(dirConfig.Value.ImagesDirectory, $"{name}{Constants.JPG_EXT}"));
|
||||
File.Delete(Path.Combine(dirConfig.Value.LabelsDirectory, $"{name}{Constants.TXT_EXT}"));
|
||||
File.Delete(Path.Combine(dirConfig.Value.ThumbnailsDirectory, $"{name}{Constants.THUMBNAIL_PREFIX}{Constants.JPG_EXT}"));
|
||||
File.Delete(Path.Combine(dirConfig.Value.ResultsDirectory, $"{name}{Constants.RESULT_PREFIX}{Constants.JPG_EXT}"));
|
||||
var tempAnnotation = new Annotation { Name = name, ImageExtension = Constants.JPG_EXT };
|
||||
fileSystem.DeleteFile(pathResolver.GetImagePath(tempAnnotation));
|
||||
fileSystem.DeleteFile(pathResolver.GetLabelPath(tempAnnotation));
|
||||
fileSystem.DeleteFile(pathResolver.GetThumbPath(tempAnnotation));
|
||||
fileSystem.DeleteFile(Path.Combine(dirConfig.Value.ResultsDirectory, $"{name}{Constants.RESULT_PREFIX}{Constants.JPG_EXT}"));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -416,7 +421,7 @@ public class AnnotatorEventHandler(
|
||||
|
||||
public Task Handle(AnnotationAddedEvent e, CancellationToken ct)
|
||||
{
|
||||
mainWindow.Dispatcher.Invoke(() =>
|
||||
uiDispatcher.Execute(() =>
|
||||
{
|
||||
var mediaInfo = (MediaFile)mainWindow.LvFiles.SelectedItem;
|
||||
if ((mediaInfo?.Name ?? "") == e.Annotation.OriginalMediaName)
|
||||
@@ -442,7 +447,7 @@ public class AnnotatorEventHandler(
|
||||
|
||||
public Task Handle(SetStatusTextEvent e, CancellationToken cancellationToken)
|
||||
{
|
||||
mainWindow.Dispatcher.Invoke(() =>
|
||||
uiDispatcher.Execute(() =>
|
||||
{
|
||||
mainWindow.StatusHelp.Text = e.Text;
|
||||
mainWindow.StatusHelp.Foreground = e.IsError ? Brushes.Red : Brushes.White;
|
||||
@@ -452,7 +457,7 @@ public class AnnotatorEventHandler(
|
||||
|
||||
public Task Handle(GPSMatcherResultProcessedEvent e, CancellationToken cancellationToken)
|
||||
{
|
||||
mainWindow.Dispatcher.Invoke(() =>
|
||||
uiDispatcher.Execute(() =>
|
||||
{
|
||||
var ann = mainWindow.MapMatcherComponent.Annotations[e.Index];
|
||||
AddMarker(e.GeoPoint, e.Image, Brushes.Blue);
|
||||
@@ -478,7 +483,7 @@ public class AnnotatorEventHandler(
|
||||
|
||||
public async Task Handle(AIAvailabilityStatusEvent e, CancellationToken cancellationToken)
|
||||
{
|
||||
mainWindow.Dispatcher.Invoke(() =>
|
||||
uiDispatcher.Execute(() =>
|
||||
{
|
||||
logger.LogInformation(e.ToString());
|
||||
mainWindow.AIDetectBtn.IsEnabled = e.Status == AIAvailabilityEnum.Enabled;
|
||||
|
||||
Reference in New Issue
Block a user