mirror of
https://github.com/azaion/annotations.git
synced 2026-04-22 12:46:30 +00:00
rework to Azaion.Suite
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Windows.Media;
|
||||
using Azaion.Common.Extensions;
|
||||
|
||||
namespace Azaion.Common.DTO;
|
||||
|
||||
public class AnnotationClass
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; } = null!;
|
||||
public string ShortName { get; set; } = null!;
|
||||
|
||||
[JsonIgnore]
|
||||
public Color Color => Id.ToColor();
|
||||
|
||||
[JsonIgnore]
|
||||
public int ClassNumber => Id + 1;
|
||||
|
||||
[JsonIgnore]
|
||||
public SolidColorBrush ColorBrush => new(Color);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Azaion.Annotator.DTO;
|
||||
|
||||
public class AIRecognitionConfig
|
||||
{
|
||||
public string AIModelPath { get; set; } = null!;
|
||||
public double FrameRecognitionSeconds { get; set; }
|
||||
public double TrackingDistanceConfidence { get; set; }
|
||||
public double TrackingProbabilityIncrease { get; set; }
|
||||
public double TrackingIntersectionThreshold { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Azaion.Common.DTO.Config;
|
||||
|
||||
public class AnnotationConfig
|
||||
{
|
||||
public List<AnnotationClass> AnnotationClasses { get; set; } = null!;
|
||||
|
||||
[JsonIgnore]
|
||||
private Dictionary<int, AnnotationClass>? _annotationClassesDict;
|
||||
[JsonIgnore]
|
||||
public Dictionary<int, AnnotationClass> AnnotationClassesDict => _annotationClassesDict ??= AnnotationClasses.ToDictionary(x => x.Id);
|
||||
|
||||
public int? LastSelectedExplorerClass { get; set; }
|
||||
|
||||
public List<string> VideoFormats { get; set; } = null!;
|
||||
public List<string> ImageFormats { get; set; } = null!;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace Azaion.Suite.Services.DTO;
|
||||
|
||||
public class ApiConfig
|
||||
{
|
||||
public string Url { get; set; } = null!;
|
||||
public int RetryCount {get;set;}
|
||||
public double TimeoutSeconds { get; set; }
|
||||
}
|
||||
|
||||
public class LocalFilesConfig
|
||||
{
|
||||
public string DllPath { get; set; } = null!;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Azaion.Annotator.DTO;
|
||||
using Azaion.Suite.Services.DTO;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Azaion.Common.DTO.Config;
|
||||
|
||||
public class AppConfig
|
||||
{
|
||||
public ApiConfig ApiConfig { get; set; } = null!;
|
||||
|
||||
public AnnotationConfig AnnotationConfig { get; set; } = null!;
|
||||
|
||||
public WindowConfig WindowConfig { get; set; } = null!;
|
||||
|
||||
public AIRecognitionConfig AIRecognitionConfig { get; set; } = null!;
|
||||
|
||||
public DirectoriesConfig DirectoriesConfig { get; set; } = null!;
|
||||
|
||||
public ThumbnailConfig ThumbnailConfig { get; set; } = null!;
|
||||
}
|
||||
|
||||
public interface IConfigUpdater
|
||||
{
|
||||
void CheckConfig();
|
||||
void Save(AppConfig config);
|
||||
}
|
||||
|
||||
public class ConfigUpdater : IConfigUpdater
|
||||
{
|
||||
public void CheckConfig()
|
||||
{
|
||||
var exePath = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory)!;
|
||||
var configFilePath = Path.Combine(exePath, Constants.CONFIG_PATH);
|
||||
|
||||
if (File.Exists(configFilePath))
|
||||
return;
|
||||
|
||||
var appConfig = new AppConfig
|
||||
{
|
||||
AnnotationConfig = new AnnotationConfig
|
||||
{
|
||||
AnnotationClasses = Constants.DefaultAnnotationClasses,
|
||||
VideoFormats = Constants.DefaultVideoFormats,
|
||||
ImageFormats = Constants.DefaultImageFormats,
|
||||
},
|
||||
|
||||
WindowConfig = new WindowConfig
|
||||
{
|
||||
WindowSize = Constants.DefaultWindowSize,
|
||||
WindowLocation = Constants.DefaultWindowLocation,
|
||||
ShowHelpOnStart = true,
|
||||
FullScreen = true,
|
||||
LeftPanelWidth = 250,
|
||||
RightPanelWidth = 250,
|
||||
},
|
||||
|
||||
DirectoriesConfig = new DirectoriesConfig
|
||||
{
|
||||
VideosDirectory = Constants.DEFAULT_VIDEO_DIR,
|
||||
ImagesDirectory = Constants.DEFAULT_IMAGES_DIR,
|
||||
LabelsDirectory = Constants.DEFAULT_LABELS_DIR,
|
||||
ResultsDirectory = Constants.DEFAULT_RESULTS_DIR,
|
||||
ThumbnailsDirectory = Constants.DEFAULT_THUMBNAILS_DIR
|
||||
},
|
||||
|
||||
ThumbnailConfig = new ThumbnailConfig
|
||||
{
|
||||
Size = Constants.DefaultThumbnailSize,
|
||||
Border = Constants.DEFAULT_THUMBNAIL_BORDER
|
||||
},
|
||||
|
||||
AIRecognitionConfig = new AIRecognitionConfig
|
||||
{
|
||||
AIModelPath = "azaion.onnx",
|
||||
FrameRecognitionSeconds = Constants.DEFAULT_FRAME_RECOGNITION_SECONDS,
|
||||
TrackingDistanceConfidence = Constants.TRACKING_DISTANCE_CONFIDENCE,
|
||||
TrackingProbabilityIncrease = Constants.TRACKING_PROBABILITY_INCREASE,
|
||||
TrackingIntersectionThreshold = Constants.TRACKING_INTERSECTION_THRESHOLD
|
||||
}
|
||||
};
|
||||
Save(appConfig);
|
||||
}
|
||||
|
||||
public void Save(AppConfig config)
|
||||
{
|
||||
File.WriteAllText(Constants.CONFIG_PATH, JsonConvert.SerializeObject(config, Formatting.Indented), Encoding.UTF8);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Azaion.Common.DTO;
|
||||
|
||||
public class DirectoriesConfig
|
||||
{
|
||||
public string VideosDirectory { get; set; } = null!;
|
||||
public string LabelsDirectory { get; set; } = null!;
|
||||
public string ImagesDirectory { get; set; } = null!;
|
||||
public string ResultsDirectory { get; set; } = null!;
|
||||
public string ThumbnailsDirectory { get; set; } = null!;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace Azaion.Common.DTO.Config;
|
||||
|
||||
public class ThumbnailConfig
|
||||
{
|
||||
public Size Size { get; set; }
|
||||
public int Border { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace Azaion.Common.DTO.Config;
|
||||
|
||||
public class WindowConfig
|
||||
{
|
||||
public Size WindowSize { get; set; }
|
||||
public Point WindowLocation { get; set; }
|
||||
public bool FullScreen { get; set; }
|
||||
|
||||
public double LeftPanelWidth { get; set; }
|
||||
public double RightPanelWidth { get; set; }
|
||||
public bool ShowHelpOnStart { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using MediatR;
|
||||
|
||||
namespace Azaion.Common.DTO;
|
||||
|
||||
public class ImageCreatedEvent(string imagePath) : INotification
|
||||
{
|
||||
public string ImagePath { get; } = imagePath;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Windows.Input;
|
||||
using MediatR;
|
||||
|
||||
namespace Azaion.Common.DTO;
|
||||
|
||||
public class KeyEvent(object sender, KeyEventArgs args, WindowEnum windowEnum) : INotification
|
||||
{
|
||||
public object Sender { get; set; } = sender;
|
||||
public KeyEventArgs Args { get; set; } = args;
|
||||
public WindowEnum WindowEnum { get; } = windowEnum;
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
using Size = System.Windows.Size;
|
||||
|
||||
namespace Azaion.Common.DTO;
|
||||
|
||||
public abstract class Label
|
||||
{
|
||||
[JsonProperty(PropertyName = "cl")] public int ClassNumber { get; set; }
|
||||
|
||||
protected Label()
|
||||
{
|
||||
}
|
||||
|
||||
protected Label(int classNumber)
|
||||
{
|
||||
ClassNumber = classNumber;
|
||||
}
|
||||
}
|
||||
|
||||
public class CanvasLabel : Label
|
||||
{
|
||||
public double X { get; set; }
|
||||
public double Y { get; set; }
|
||||
public double Width { get; set; }
|
||||
public double Height { get; set; }
|
||||
public double? Probability { get; }
|
||||
|
||||
public CanvasLabel()
|
||||
{
|
||||
}
|
||||
|
||||
public CanvasLabel(int classNumber, double x, double y, double width, double height, double? probability = null) : base(classNumber)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Width = width;
|
||||
Height = height;
|
||||
Probability = probability;
|
||||
}
|
||||
|
||||
public CanvasLabel(YoloLabel label, Size canvasSize, Size videoSize, double? probability = null)
|
||||
{
|
||||
var cw = canvasSize.Width;
|
||||
var ch = canvasSize.Height;
|
||||
var canvasAr = cw / ch;
|
||||
var videoAr = videoSize.Width / videoSize.Height;
|
||||
|
||||
ClassNumber = label.ClassNumber;
|
||||
|
||||
var left = label.CenterX - label.Width / 2;
|
||||
var top = label.CenterY - label.Height / 2;
|
||||
|
||||
if (videoAr > canvasAr) //100% width
|
||||
{
|
||||
var realHeight = cw / videoAr; //real video height in pixels on canvas
|
||||
var blackStripHeight = (ch - realHeight) / 2.0; //height of black strips at the top and bottom
|
||||
|
||||
X = left * cw;
|
||||
Y = top * realHeight + blackStripHeight;
|
||||
Width = label.Width * cw;
|
||||
Height = label.Height * realHeight;
|
||||
}
|
||||
else //100% height
|
||||
{
|
||||
var realWidth = ch * videoAr; //real video width in pixels on canvas
|
||||
var blackStripWidth = (cw - realWidth) / 2.0; //height of black strips at the top and bottom
|
||||
|
||||
X = left * realWidth + blackStripWidth;
|
||||
Y = top * ch;
|
||||
Width = label.Width * realWidth;
|
||||
Height = label.Height * ch;
|
||||
}
|
||||
Probability = probability;
|
||||
}
|
||||
}
|
||||
|
||||
public class YoloLabel : Label
|
||||
{
|
||||
[JsonProperty(PropertyName = "x")] public double CenterX { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "y")] public double CenterY { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "w")] public double Width { get; set; }
|
||||
|
||||
[JsonProperty(PropertyName = "h")] public double Height { get; set; }
|
||||
|
||||
public YoloLabel()
|
||||
{
|
||||
}
|
||||
|
||||
public YoloLabel(int classNumber, double centerX, double centerY, double width, double height) : base(classNumber)
|
||||
{
|
||||
CenterX = centerX;
|
||||
CenterY = centerY;
|
||||
Width = width;
|
||||
Height = height;
|
||||
}
|
||||
|
||||
public RectangleF ToRectangle() =>
|
||||
new((float)(CenterX - Width / 2.0), (float)(CenterY - Height / 2.0), (float)Width, (float)Height);
|
||||
|
||||
public YoloLabel(CanvasLabel canvasLabel, Size canvasSize, Size videoSize)
|
||||
{
|
||||
var cw = canvasSize.Width;
|
||||
var ch = canvasSize.Height;
|
||||
var canvasAr = cw / ch;
|
||||
var videoAr = videoSize.Width / videoSize.Height;
|
||||
|
||||
ClassNumber = canvasLabel.ClassNumber;
|
||||
|
||||
double left, top;
|
||||
if (videoAr > canvasAr) //100% width
|
||||
{
|
||||
left = canvasLabel.X / cw;
|
||||
Width = canvasLabel.Width / cw;
|
||||
var realHeight = cw / videoAr; //real video height in pixels on canvas
|
||||
var blackStripHeight = (ch - realHeight) / 2.0; //height of black strips at the top and bottom
|
||||
top = (canvasLabel.Y - blackStripHeight) / realHeight;
|
||||
Height = canvasLabel.Height / realHeight;
|
||||
}
|
||||
else //100% height
|
||||
{
|
||||
top = canvasLabel.Y / ch;
|
||||
Height = canvasLabel.Height / ch;
|
||||
var realWidth = ch * videoAr; //real video width in pixels on canvas
|
||||
var blackStripWidth = (cw - realWidth) / 2.0; //height of black strips at the top and bottom
|
||||
left = (canvasLabel.X - blackStripWidth) / realWidth;
|
||||
Width = canvasLabel.Width / realWidth;
|
||||
}
|
||||
|
||||
CenterX = left + Width / 2.0;
|
||||
CenterY = top + Height / 2.0;
|
||||
}
|
||||
|
||||
public static YoloLabel? Parse(string s)
|
||||
{
|
||||
if (string.IsNullOrEmpty(s))
|
||||
return null;
|
||||
|
||||
var strings = s.Replace(',', '.').Split(' ');
|
||||
if (strings.Length != 5)
|
||||
throw new Exception("Wrong labels format!");
|
||||
|
||||
var res = new YoloLabel
|
||||
{
|
||||
ClassNumber = int.Parse(strings[0], CultureInfo.InvariantCulture),
|
||||
CenterX = double.Parse(strings[1], CultureInfo.InvariantCulture),
|
||||
CenterY = double.Parse(strings[2], CultureInfo.InvariantCulture),
|
||||
Width = double.Parse(strings[3], CultureInfo.InvariantCulture),
|
||||
Height = double.Parse(strings[4], CultureInfo.InvariantCulture)
|
||||
};
|
||||
return res;
|
||||
}
|
||||
|
||||
public static async Task<List<YoloLabel>> ReadFromFile(string filename, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var str = await File.ReadAllTextAsync(filename, cancellationToken);
|
||||
|
||||
return str.Split('\n')
|
||||
.Select(Parse)
|
||||
.Where(ann => ann != null)
|
||||
.ToList()!;
|
||||
}
|
||||
|
||||
public static async Task WriteToFile(IEnumerable<YoloLabel> labels, string filename, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var labelsStr = string.Join(Environment.NewLine, labels.Select(x => x.ToString()));
|
||||
await File.WriteAllTextAsync(filename, labelsStr, cancellationToken);
|
||||
}
|
||||
|
||||
public override string ToString() => $"{ClassNumber} {CenterX:F5} {CenterY:F5} {Width:F5} {Height:F5}".Replace(',', '.');
|
||||
}
|
||||
|
||||
public class Detection : YoloLabel
|
||||
{
|
||||
public Detection(YoloLabel label, double? probability = null)
|
||||
{
|
||||
ClassNumber = label.ClassNumber;
|
||||
CenterX = label.CenterX;
|
||||
CenterY = label.CenterY;
|
||||
Height = label.Height;
|
||||
Width = label.Width;
|
||||
Probability = probability;
|
||||
}
|
||||
public double? Probability { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Azaion.Common.DTO;
|
||||
|
||||
public class LabelInfo
|
||||
{
|
||||
[JsonProperty("c")] public List<int> Classes { get; set; } = null!;
|
||||
|
||||
[JsonProperty("d")] public DateTime ImageDateTime { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace Azaion.Common.DTO;
|
||||
|
||||
public enum PlaybackControlEnum
|
||||
{
|
||||
None = 0,
|
||||
Play = 1,
|
||||
Pause = 2,
|
||||
Stop = 3,
|
||||
PreviousFrame = 4,
|
||||
NextFrame = 5,
|
||||
SaveAnnotations = 6,
|
||||
RemoveSelectedAnns = 7,
|
||||
RemoveAllAnns = 8,
|
||||
TurnOffVolume = 9,
|
||||
TurnOnVolume = 10,
|
||||
Previous = 11,
|
||||
Next = 12,
|
||||
Close = 13
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Azaion.Annotator.DTO;
|
||||
|
||||
public enum SelectionState
|
||||
{
|
||||
None = 0,
|
||||
NewAnnCreating = 1,
|
||||
AnnResizing = 2,
|
||||
AnnMoving = 3
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Azaion.Common.DTO;
|
||||
|
||||
public enum WindowEnum
|
||||
{
|
||||
None = 0,
|
||||
Annotator = 10,
|
||||
DatasetExplorer = 20
|
||||
}
|
||||
Reference in New Issue
Block a user