fix image save, ui small fixes

This commit is contained in:
Alex Bezdieniezhnykh
2025-03-12 01:07:52 +02:00
parent 06f527e6c3
commit 33070b90bf
9 changed files with 63 additions and 49 deletions
+9 -1
View File
@@ -148,7 +148,8 @@
Grid.Column="0"
Name="LvFiles"
Background="Black"
SelectedItem="{Binding Path=SelectedVideo}" Foreground="#FFEEEEEE"
SelectedItem="{Binding Path=SelectedVideo}"
Foreground="#FFDDDDDD"
>
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}">
@@ -156,6 +157,13 @@
<DataTrigger Binding="{Binding HasAnnotations}" Value="true">
<Setter Property="Background" Value="#FF505050"/>
</DataTrigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value=" DimGray" />
<Setter Property="Background" Value="#FFCCCCCC"></Setter>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="DimGray"></Setter>
</Trigger>
</Style.Triggers>
<EventSetter Event="ContextMenuOpening" Handler="LvFilesContextOpening"></EventSetter>
</Style>
+26 -26
View File
@@ -1,7 +1,9 @@
using System.IO;
using System.Reflection.Metadata;
using System.Windows;
using System.Windows.Input;
using Azaion.Annotator.DTO;
using Azaion.Common;
using Azaion.Common.DTO;
using Azaion.Common.DTO.Config;
using Azaion.Common.DTO.Queue;
@@ -224,7 +226,8 @@ public class AnnotatorEventHandler(
mediaPlayer.Stop();
mainWindow.Title = $"Azaion Annotator - {mediaInfo.Name}";
mainWindow.BlinkHelp(HelpTexts.HelpTextsDict[HelpTextEnum.PauseForAnnotations]);
mediaPlayer.Play(new Media(libVLC, mediaInfo.Path));
if (formState.CurrentMedia.MediaType == MediaTypes.Video)
mediaPlayer.Play(new Media(libVLC, mediaInfo.Path));
}
//SAVE: MANUAL
@@ -234,47 +237,44 @@ public class AnnotatorEventHandler(
return;
var time = formState.BackgroundTime ?? TimeSpan.FromMilliseconds(mediaPlayer.Time);
var fName = formState.VideoName.ToTimeName(time);
var originalMediaName = formState.VideoName;
var fName = originalMediaName.ToTimeName(time);
var currentDetections = mainWindow.Editor.CurrentDetections
.Select(x => new Detection(fName, x.GetLabel(mainWindow.Editor.RenderSize, formState.BackgroundTime.HasValue ? mainWindow.Editor.RenderSize : formState.CurrentVideoSize)))
.ToList();
formState.CurrentMedia.HasAnnotations = mainWindow.TimedAnnotations.Count != 0;
formState.CurrentMedia.HasAnnotations = currentDetections.Count != 0;
mainWindow.LvFiles.Items.Refresh();
mainWindow.Editor.RemoveAllAnns();
var isVideo = formState.CurrentMedia.MediaType == MediaTypes.Video;
var imageExtension = isVideo ? ".jpg" : Path.GetExtension(formState.CurrentMedia.Path);
var imgPath = Path.Combine(dirConfig.Value.ImagesDirectory, $"{fName}{imageExtension}");
var imgPath = Path.Combine(dirConfig.Value.ImagesDirectory, $"{fName}{Constants.JPG_EXT}");
if (isVideo)
if (formState.BackgroundTime.HasValue)
{
if (formState.BackgroundTime.HasValue)
{
//no need to save image, it's already there, just remove background
mainWindow.Editor.ResetBackground();
formState.BackgroundTime = null;
//no need to save image, it's already there, just remove background
mainWindow.Editor.ResetBackground();
formState.BackgroundTime = null;
//next item
var annGrid = mainWindow.DgAnnotations;
annGrid.SelectedIndex = Math.Min(annGrid.Items.Count, annGrid.SelectedIndex + 1);
mainWindow.OpenAnnotationResult((AnnotationResult)annGrid.SelectedItem);
}
else
{
var resultHeight = (uint)Math.Round(RESULT_WIDTH / formState.CurrentVideoSize.Width * formState.CurrentVideoSize.Height);
mediaPlayer.TakeSnapshot(0, imgPath, RESULT_WIDTH, resultHeight);
mediaPlayer.Play();
}
//next item
var annGrid = mainWindow.DgAnnotations;
annGrid.SelectedIndex = Math.Min(annGrid.Items.Count, annGrid.SelectedIndex + 1);
mainWindow.OpenAnnotationResult((AnnotationResult)annGrid.SelectedItem);
}
else
{
File.Copy(formState.CurrentMedia.Path, imgPath, overwrite: true);
await NextMedia(ct: cancellationToken);
var resultHeight = (uint)Math.Round(RESULT_WIDTH / formState.CurrentVideoSize.Width * formState.CurrentVideoSize.Height);
mediaPlayer.TakeSnapshot(0, imgPath, RESULT_WIDTH, resultHeight);
if (isVideo)
mediaPlayer.Play();
else
await NextMedia(ct: cancellationToken);
}
var annotation = await annotationService.SaveAnnotation(formState.VideoName, time, imageExtension, currentDetections, SourceEnum.Manual, token: cancellationToken);
mainWindow.AddAnnotation(annotation);
var annotation = await annotationService.SaveAnnotation(originalMediaName, time, currentDetections, SourceEnum.Manual, token: cancellationToken);
if (isVideo)
mainWindow.AddAnnotation(annotation);
}
public async Task Handle(AnnotationsDeletedEvent notification, CancellationToken cancellationToken)
+1 -1
View File
@@ -5,7 +5,7 @@ namespace Azaion.Common;
public class Constants
{
public const string SECURE_RESOURCE_CACHE = "SecureResourceCache";
public const string JPG_EXT = ".jpg";
#region DirectoriesConfig
+1
View File
@@ -11,6 +11,7 @@ public class DetectionClass
public string Name { get; set; } = null!;
public string ShortName { get; set; } = null!;
[JsonIgnore]
public string UIName
{
get
+7 -8
View File
@@ -68,7 +68,7 @@ public class AnnotationService : INotificationHandler<AnnotationsDeletedEvent>
{
Reference = _hardwareService.GetHardware().Hash,
OffsetSpec = new OffsetTypeOffset(offset + 1),
MessageHandler = async (stream, consumer, context, message) =>
MessageHandler = async (_, _, context, message) =>
{
var msg = MessagePackSerializer.Deserialize<AnnotationCreatedMessage>(message.Data.Contents);
await _dbFactory.Run(async db => await db.QueueOffsets
@@ -89,7 +89,6 @@ public class AnnotationService : INotificationHandler<AnnotationsDeletedEvent>
msg.CreatedDate,
msg.OriginalMediaName,
msg.Time,
msg.ImageExtension,
JsonConvert.DeserializeObject<List<Detection>>(msg.Detections) ?? [],
msg.Source,
new MemoryStream(msg.Image),
@@ -105,23 +104,23 @@ public class AnnotationService : INotificationHandler<AnnotationsDeletedEvent>
public async Task<Annotation> SaveAnnotation(AnnotationImage a, CancellationToken cancellationToken = default)
{
a.Time = TimeSpan.FromMilliseconds(a.Milliseconds);
return await SaveAnnotationInner(DateTime.Now, a.OriginalMediaName, a.Time, ".jpg", a.Detections.ToList(),
return await SaveAnnotationInner(DateTime.Now, a.OriginalMediaName, a.Time, a.Detections.ToList(),
a.Source, new MemoryStream(a.Image), _authProvider.CurrentUser.Role, _authProvider.CurrentUser.Email, generateThumbnail: true, cancellationToken);
}
//Manual
public async Task<Annotation> SaveAnnotation(string originalMediaName, TimeSpan time, string imageExtension, List<Detection> detections, SourceEnum source, Stream? stream = null, CancellationToken token = default) =>
await SaveAnnotationInner(DateTime.UtcNow, originalMediaName, time, imageExtension, detections, source, stream,
public async Task<Annotation> SaveAnnotation(string originalMediaName, TimeSpan time, List<Detection> detections, SourceEnum source, Stream? stream = null, CancellationToken token = default) =>
await SaveAnnotationInner(DateTime.UtcNow, originalMediaName, time, detections, source, stream,
_authProvider.CurrentUser.Role, _authProvider.CurrentUser.Email, generateThumbnail: true, token);
//Manual Validate existing
public async Task ValidateAnnotation(Annotation annotation, CancellationToken token = default) =>
await SaveAnnotationInner(DateTime.UtcNow, annotation.OriginalMediaName, annotation.Time, annotation.ImageExtension, annotation.Detections.ToList(), SourceEnum.Manual, null,
await SaveAnnotationInner(DateTime.UtcNow, annotation.OriginalMediaName, annotation.Time, annotation.Detections.ToList(), SourceEnum.Manual, null,
_authProvider.CurrentUser.Role, _authProvider.CurrentUser.Email, generateThumbnail: false, token);
// Manual save from Validators -> Validated -> stream: azaion-annotations-confirm
// AI, Manual save from Operators -> Created -> stream: azaion-annotations
private async Task<Annotation> SaveAnnotationInner(DateTime createdDate, string originalMediaName, TimeSpan time, string imageExtension, List<Detection> detections, SourceEnum source, Stream? stream,
private async Task<Annotation> SaveAnnotationInner(DateTime createdDate, string originalMediaName, TimeSpan time, List<Detection> detections, SourceEnum source, Stream? stream,
RoleEnum userRole,
string createdEmail,
bool generateThumbnail = false,
@@ -156,7 +155,7 @@ public class AnnotationService : INotificationHandler<AnnotationsDeletedEvent>
Name = fName,
OriginalMediaName = originalMediaName,
Time = time,
ImageExtension = imageExtension,
ImageExtension = Constants.JPG_EXT,
CreatedEmail = createdEmail,
CreatedRole = userRole,
AnnotationStatus = status,
@@ -63,7 +63,7 @@ public class DatasetExplorerEventHandler(
var detections = datasetExplorer.ExplorerEditor.CurrentDetections
.Select(x => new Detection(a.Name, x.GetLabel(datasetExplorer.ExplorerEditor.RenderSize)))
.ToList();
await annotationService.SaveAnnotation(a.OriginalMediaName, a.Time, a.ImageExtension, detections, SourceEnum.Manual, token: cancellationToken);
await annotationService.SaveAnnotation(a.OriginalMediaName, a.Time, detections, SourceEnum.Manual, token: cancellationToken);
datasetExplorer.SwitchTab(toEditor: false);
break;
case PlaybackControlEnum.RemoveSelectedAnns:
+10 -8
View File
@@ -31,8 +31,8 @@
<ItemGroup>
<ProjectReference Include="..\Azaion.Common\Azaion.Common.csproj" />
<ProjectReference Include="..\Dummy\Azaion.Annotator\Azaion.Annotator.csproj" />
<ProjectReference Include="..\Dummy\Azaion.Dataset\Azaion.Dataset.csproj" />
<ProjectReference Include="..\Azaion.Annotator\Azaion.Annotator.csproj" />
<ProjectReference Include="..\Azaion.Dataset\Azaion.Dataset.csproj" />
</ItemGroup>
<ItemGroup>
@@ -40,12 +40,14 @@
<Content Include="logo.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<None Update="config.json">
<None Remove="config.json" />
<Content Include="config.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="config.production.json">
</Content>
<None Remove="config.production.json" />
<Content Include="config.production.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</Content>
</ItemGroup>
<ItemGroup>
@@ -58,8 +60,8 @@
<Target Name="PostBuild" AfterTargets="Build">
<MakeDir Directories="$(TargetDir)dummy" />
<Move SourceFiles="$(TargetDir)Azaion.Annotator.dll" DestinationFolder="$(TargetDir)dummy" />
<Move SourceFiles="$(TargetDir)Azaion.Dataset.dll" DestinationFolder="$(TargetDir)dummy" />
<Copy SourceFiles="$(TargetDir)Azaion.Annotator.dll" DestinationFolder="$(TargetDir)dummy" />
<Copy SourceFiles="$(TargetDir)Azaion.Dataset.dll" DestinationFolder="$(TargetDir)dummy" />
<Exec Command="upload.cmd $(ConfigurationName) stage" />
</Target>
+3 -1
View File
@@ -26,7 +26,9 @@
{ "Id": 8, "Name": "Танк з захистом", "ShortName": "Танк.захист" },
{ "Id": 9, "Name": "Дим", "ShortName": "Дим" },
{ "Id": 10, "Name": "Літак", "ShortName": "Літак" },
{ "Id": 11, "Name": "Мотоцикл", "ShortName": "Мото" }
{ "Id": 11, "Name": "Мотоцикл", "ShortName": "Мото" },
{ "Id": 12, "Name": "Маскування сіткою", "ShortName": "Сітка" },
{ "Id": 13, "Name": "Маскування гілками", "ShortName": "Гілки" }
],
"LastSelectedExplorerClass": null,
"VideoFormats": [ "mp4", "mov", "avi" ],
+3 -1
View File
@@ -25,7 +25,9 @@
{ "Id": 8, "Name": "Танк з захистом", "ShortName": "Танк.захист" },
{ "Id": 9, "Name": "Дим", "ShortName": "Дим" },
{ "Id": 10, "Name": "Літак", "ShortName": "Літак" },
{ "Id": 11, "Name": "Мотоцикл", "ShortName": "Мото" }
{ "Id": 11, "Name": "Мотоцикл", "ShortName": "Мото" },
{ "Id": 12, "Name": "Маскування сіткою", "ShortName": "Сітка" },
{ "Id": 13, "Name": "Маскування гілками", "ShortName": "Гілки" }
],
"LastSelectedExplorerClass": null,
"VideoFormats": [ "mp4", "mov", "avi" ],