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