mirror of
https://github.com/azaion/annotations.git
synced 2026-04-23 01:16:31 +00:00
fix image save, ui small fixes
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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" ],
|
||||||
|
|||||||
@@ -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" ],
|
||||||
|
|||||||
Reference in New Issue
Block a user