add altitude + camera spec component and calc tile size by this

also restrict detections to be no bigger than in classes.json
This commit is contained in:
Oleksandr Bezdieniezhnykh
2025-09-23 01:48:10 +03:00
parent b0e4b467c1
commit fde9a9f418
36 changed files with 715 additions and 222 deletions
+16 -5
View File
@@ -76,6 +76,7 @@
<RowDefinition Height="28"></RowDefinition>
<RowDefinition Height="28"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="80"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
@@ -191,10 +192,20 @@
</GridView>
</ListView.View>
</ListView>
<controls1:CameraConfigControl
x:Name="CameraConfigControl"
Grid.Column="0"
Grid.Row="4"
Camera="{Binding Camera, RelativeSource={RelativeSource AncestorType=Window}, Mode=OneWay}"
>
</controls1:CameraConfigControl>
<controls1:DetectionClasses
x:Name="LvClasses"
Grid.Column="0"
Grid.Row="4">
Grid.Row="5">
</controls1:DetectionClasses>
<GridSplitter
@@ -202,7 +213,7 @@
ResizeDirection="Columns"
Grid.Column="1"
Grid.Row="1"
Grid.RowSpan="4"
Grid.RowSpan="5"
ResizeBehavior="PreviousAndNext"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
@@ -211,7 +222,7 @@
<wpf:VideoView
Grid.Row="1"
Grid.Column="2"
Grid.RowSpan="4"
Grid.RowSpan="5"
x:Name="VideoView">
<controls1:CanvasEditor x:Name="Editor"
Background="#01000000"
@@ -224,7 +235,7 @@
ResizeDirection="Columns"
Grid.Column="3"
Grid.Row="1"
Grid.RowSpan="4"
Grid.RowSpan="5"
ResizeBehavior="PreviousAndNext"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
@@ -234,7 +245,7 @@
<DataGrid x:Name="DgAnnotations"
Grid.Column="4"
Grid.Row="1"
Grid.RowSpan="4"
Grid.RowSpan="5"
Background="Black"
Foreground="White"
RowHeaderWidth="0"
+41 -27
View File
@@ -29,7 +29,7 @@ namespace Azaion.Annotator;
public partial class Annotator
{
private readonly AppConfig _appConfig;
private readonly AppConfig? _appConfig;
private readonly LibVLC _libVlc;
private readonly MediaPlayer _mediaPlayer;
private readonly IMediator _mediator;
@@ -41,12 +41,12 @@ public partial class Annotator
private readonly IDbFactory _dbFactory;
private readonly IInferenceService _inferenceService;
private readonly IInferenceClient _inferenceClient;
private bool _suspendLayout;
private bool _gpsPanelVisible;
private readonly CancellationTokenSource _mainCancellationSource = new();
public CancellationTokenSource DetectionCancellationSource = new();
public CancellationTokenSource DetCancelSource = new();
private bool _isInferenceNow;
private readonly TimeSpan _thresholdBefore = TimeSpan.FromMilliseconds(50);
@@ -59,6 +59,8 @@ public partial class Annotator
public IntervalTree<TimeSpan, Annotation> TimedAnnotations { get; set; } = new();
public string MainTitle { get; set; }
public CameraConfig Camera => _appConfig?.CameraConfig ?? new CameraConfig();
public Annotator(
IConfigUpdater configUpdater,
IOptions<AppConfig> appConfig,
@@ -73,10 +75,7 @@ public partial class Annotator
IInferenceClient inferenceClient,
IGpsMatcherService gpsMatcherService)
{
InitializeComponent();
MainTitle = $"Azaion Annotator {Constants.GetLocalVersion()}";
Title = MainTitle;
// Initialize configuration and services BEFORE InitializeComponent so bindings can see real values
_appConfig = appConfig.Value;
_configUpdater = configUpdater;
_libVlc = libVlc;
@@ -89,6 +88,14 @@ public partial class Annotator
_inferenceService = inferenceService;
_inferenceClient = inferenceClient;
// Ensure bindings (e.g., Camera) resolve immediately
DataContext = this;
InitializeComponent();
MainTitle = $"Azaion Annotator {Constants.GetLocalVersion()}";
Title = MainTitle;
Loaded += OnLoaded;
Closed += OnFormClosed;
Activated += (_, _) => _formState.ActiveWindow = WindowEnum.Annotator;
@@ -100,7 +107,6 @@ public partial class Annotator
{
_appConfig.DirectoriesConfig.VideosDirectory = TbFolder.Text;
await ReloadFiles();
SaveUserSettings();
}
catch (Exception e)
{
@@ -109,6 +115,13 @@ public partial class Annotator
};
Editor.GetTimeFunc = () => TimeSpan.FromMilliseconds(_mediaPlayer.Time);
MapMatcherComponent.Init(_appConfig, gpsMatcherService);
// When camera settings change, persist config
CameraConfigControl.CameraChanged += (_, _) =>
{
if (_appConfig != null)
_configUpdater.Save(_appConfig);
};
}
private void OnLoaded(object sender, RoutedEventArgs e)
@@ -118,13 +131,13 @@ public partial class Annotator
_suspendLayout = true;
MainGrid.ColumnDefinitions.FirstOrDefault()!.Width = new GridLength(_appConfig.UIConfig.LeftPanelWidth);
MainGrid.ColumnDefinitions.LastOrDefault()!.Width = new GridLength(_appConfig.UIConfig.RightPanelWidth);
MainGrid.ColumnDefinitions.FirstOrDefault()!.Width = new GridLength(_appConfig?.UIConfig.LeftPanelWidth ?? Constants.DEFAULT_LEFT_PANEL_WIDTH);
MainGrid.ColumnDefinitions.LastOrDefault()!.Width = new GridLength(_appConfig?.UIConfig.RightPanelWidth ?? Constants.DEFAULT_RIGHT_PANEL_WIDTH);
_suspendLayout = false;
TbFolder.Text = _appConfig.DirectoriesConfig.VideosDirectory;
TbFolder.Text = _appConfig?.DirectoriesConfig.VideosDirectory ?? Constants.DEFAULT_VIDEO_DIR;
LvClasses.Init(_appConfig.AnnotationConfig.DetectionClasses);
LvClasses.Init(_appConfig?.AnnotationConfig.DetectionClasses ?? Constants.DefaultAnnotationClasses);
}
public void BlinkHelp(string helpText, int times = 2)
@@ -212,9 +225,9 @@ public partial class Annotator
private void OpenAnnotationResult(Annotation ann)
{
_mediaPlayer.SetPause(true);
if (!ann.IsSplit)
if (!ann.IsSplit)
Editor.RemoveAllAnns();
_mediaPlayer.Time = (long)ann.Time.TotalMilliseconds;
Dispatcher.Invoke(() =>
@@ -228,7 +241,7 @@ public partial class Annotator
}
private void SaveUserSettings()
{
if (_suspendLayout)
if (_suspendLayout || _appConfig is null)
return;
_appConfig.UIConfig.LeftPanelWidth = MainGrid.ColumnDefinitions.FirstOrDefault()!.Width.Value;
@@ -269,7 +282,7 @@ public partial class Annotator
Editor.ZoomTo(new Point(canvasTileLocation.CenterX, canvasTileLocation.CenterY));
}
else
Editor.CreateDetections(annotation, _appConfig.AnnotationConfig.DetectionClasses, _formState.CurrentMediaSize);
Editor.CreateDetections(annotation, _appConfig?.AnnotationConfig.DetectionClasses ?? [], _formState.CurrentMediaSize);
});
}
@@ -333,11 +346,12 @@ public partial class Annotator
private async Task ReloadFiles()
{
var dir = new DirectoryInfo(_appConfig.DirectoriesConfig.VideosDirectory);
var dir = new DirectoryInfo(_appConfig?.DirectoriesConfig.VideosDirectory ?? Constants.DEFAULT_VIDEO_DIR);
if (!dir.Exists)
return;
var videoFiles = dir.GetFiles(_appConfig.AnnotationConfig.VideoFormats.ToArray()).Select(x =>
var videoFiles = dir.GetFiles((_appConfig?.AnnotationConfig.VideoFormats ?? Constants.DefaultVideoFormats)
.ToArray()).Select(x =>
{
var media = new Media(_libVlc, x.FullName);
media.Parse();
@@ -351,7 +365,7 @@ public partial class Annotator
return fInfo;
}).ToList();
var imageFiles = dir.GetFiles(_appConfig.AnnotationConfig.ImageFormats.ToArray())
var imageFiles = dir.GetFiles((_appConfig?.AnnotationConfig.ImageFormats ?? Constants.DefaultImageFormats).ToArray())
.Select(x => new MediaFileInfo
{
Name = x.Name,
@@ -383,7 +397,7 @@ public partial class Annotator
{
_mainCancellationSource.Cancel();
_inferenceService.StopInference();
DetectionCancellationSource.Cancel();
DetCancelSource.Cancel();
_mediaPlayer.Stop();
_mediaPlayer.Dispose();
@@ -417,14 +431,16 @@ public partial class Annotator
{
Title = "Open Video folder",
IsFolderPicker = true,
InitialDirectory = Path.GetDirectoryName(_appConfig.DirectoriesConfig.VideosDirectory)
InitialDirectory = Path.GetDirectoryName(_appConfig?.DirectoriesConfig.VideosDirectory ?? Constants.DEFAULT_VIDEO_DIR)
};
var dialogResult = dlg.ShowDialog();
if (dialogResult != CommonFileDialogResult.Ok || string.IsNullOrEmpty(dlg.FileName))
return;
_appConfig.DirectoriesConfig.VideosDirectory = dlg.FileName;
if (_appConfig is not null)
_appConfig.DirectoriesConfig.VideosDirectory = dlg.FileName;
TbFolder.Text = dlg.FileName;
}
@@ -495,7 +511,7 @@ public partial class Annotator
_isInferenceNow = true;
AIDetectBtn.IsEnabled = false;
DetectionCancellationSource = new CancellationTokenSource();
DetCancelSource = new CancellationTokenSource();
var files = (FilteredMediaFiles.Count == 0 ? AllMediaFiles : FilteredMediaFiles)
.Skip(LvFiles.SelectedIndex)
@@ -504,9 +520,7 @@ public partial class Annotator
if (files.Count == 0)
return;
//TODO: Get Tile Size from UI based on height setup
var tileSize = 550;
await _inferenceService.RunInference(files, tileSize, DetectionCancellationSource.Token);
await _inferenceService.RunInference(files, _appConfig?.CameraConfig ?? Constants.DefaultCameraConfig, DetCancelSource.Token);
LvFiles.Items.Refresh();
_isInferenceNow = false;
@@ -607,7 +621,7 @@ public class GradientStyleSelector : StyleSelector
foreach (var gradientStop in gradients)
brush.GradientStops.Add(gradientStop);
style.Setters.Add(new Setter(DataGridRow.BackgroundProperty, brush));
style.Setters.Add(new Setter(Control.BackgroundProperty, brush));
return style;
}
}
+1 -1
View File
@@ -162,7 +162,7 @@ public class AnnotatorEventHandler(
break;
case PlaybackControlEnum.Stop:
inferenceService.StopInference();
await mainWindow.DetectionCancellationSource.CancelAsync();
await mainWindow.DetCancelSource.CancelAsync();
mediaPlayer.Stop();
break;
case PlaybackControlEnum.PreviousFrame: