added better logging to python

add day / winter / night switcher
This commit is contained in:
Alex Bezdieniezhnykh
2025-02-17 18:41:18 +02:00
parent 2ecbc9bfd4
commit c314268d1e
14 changed files with 204 additions and 103 deletions
+4 -4
View File
@@ -120,8 +120,8 @@ public partial class Annotator
TbFolder.Text = _appConfig.DirectoriesConfig.VideosDirectory;
AnnotationClasses = new ObservableCollection<DetectionClass>(_appConfig.AnnotationConfig.AnnotationClasses);
LvClasses.ItemsSource = AnnotationClasses;
LvClasses.SelectedIndex = 0;
LvClasses.DetectionDataGrid.ItemsSource = AnnotationClasses;
LvClasses.SelectNum(0);
if (LvFiles.Items.IsEmpty)
BlinkHelp(HelpTexts.HelpTextsDict[HelpTextEnum.Initial]);
@@ -176,9 +176,9 @@ public partial class Annotator
await _mediator.Publish(new AnnotatorControlEvent(PlaybackControlEnum.Play));
};
LvClasses.SelectionChanged += (_, _) =>
LvClasses.DetectionClassChanged += (_, args) =>
{
var selectedClass = (DetectionClass)LvClasses.SelectedItem;
var selectedClass = args.DetectionClass;
Editor.CurrentAnnClass = selectedClass;
_mediator.Publish(new AnnClassSelectedEvent(selectedClass));
};
+5 -5
View File
@@ -53,12 +53,12 @@ public class AnnotatorEventHandler(
await Task.CompletedTask;
}
private void SelectClass(DetectionClass annClass)
private void SelectClass(DetectionClass detClass)
{
mainWindow.Editor.CurrentAnnClass = annClass;
mainWindow.Editor.CurrentAnnClass = detClass;
foreach (var ann in mainWindow.Editor.CurrentDetections.Where(x => x.IsSelected))
ann.DetectionClass = annClass;
mainWindow.LvClasses.SelectedIndex = annClass.Id;
ann.DetectionClass = detClass;
mainWindow.LvClasses.SelectNum(detClass.Id);
}
public async Task Handle(KeyEvent keyEvent, CancellationToken cancellationToken = default)
@@ -74,7 +74,7 @@ public class AnnotatorEventHandler(
if ((int)key >= (int)Key.NumPad1 && (int)key <= (int)Key.NumPad9)
keyNumber = key - Key.NumPad1;
if (keyNumber.HasValue)
SelectClass((DetectionClass)mainWindow.LvClasses.Items[keyNumber.Value]!);
SelectClass((DetectionClass)mainWindow.LvClasses.DetectionDataGrid.Items[keyNumber.Value]!);
if (_keysControlEnumDict.TryGetValue(key, out var value))
await ControlPlayback(value, cancellationToken);
+73 -16
View File
@@ -1,10 +1,44 @@
<DataGrid x:Class="Azaion.Common.Controls.DetectionClasses"
<UserControl x:Class="Azaion.Common.Controls.DetectionClasses"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<Style x:Key="ButtonRadioButtonStyle" TargetType="RadioButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RadioButton">
<Border x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}" BorderThickness="1"
Padding="10,5" CornerRadius="2">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="Border" Property="Background" Value="Gray"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Border" Property="Background" Value="DarkGray"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="White"/>
<Setter Property="Foreground" Value="White"/>
</Style>
</UserControl.Resources>
<Grid Background="Black">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- Your DataGrid with detection classes -->
<DataGrid x:Name="DetectionDataGrid"
Grid.Row="0"
Background="Black"
RowBackground="#252525"
Foreground="White"
@@ -15,35 +49,58 @@
CellStyle="{DynamicResource DataGridCellStyle1}"
IsReadOnly="True"
CanUserResizeRows="False"
CanUserResizeColumns="False">
CanUserResizeColumns="False"
SelectionChanged="DetectionDataGrid_SelectionChanged"
x:FieldModifier="public">
<DataGrid.Columns>
<DataGridTemplateColumn
Width="50"
Header="Клавіша"
CanUserSort="False">
<DataGridTemplateColumn Width="50" Header="Клавіша" CanUserSort="False">
<DataGridTemplateColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="Background" Value="#252525"></Setter>
<Setter Property="Background" Value="#252525"/>
</Style>
</DataGridTemplateColumn.HeaderStyle>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border Background="{Binding Path=ColorBrush}">
<TextBlock Text="{Binding Path=ClassNumber}"></TextBlock>
<TextBlock Text="{Binding Path=ClassNumber}"/>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn
Width="*"
Header="Назва"
Binding="{Binding Path=Name}"
CanUserSort="False">
<DataGridTextColumn Width="*" Header="Назва" Binding="{Binding Path=Name}" CanUserSort="False">
<DataGridTextColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="Background" Value="#252525"></Setter>
<Setter Property="Background" Value="#252525"/>
</Style>
</DataGridTextColumn.HeaderStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</DataGrid>
<!-- StackPanel with mode switcher RadioButtons -->
<StackPanel x:Name="ModeSwitcherPanel"
Grid.Row="1"
Orientation="Horizontal"
HorizontalAlignment="Center"
Margin="0,5,0,5">
<RadioButton x:Name="NormalModeRadioButton"
Tag="0"
Content="Звичайний"
GroupName="Mode"
Checked="ModeRadioButton_Checked"
IsChecked="True"
Style="{StaticResource ButtonRadioButtonStyle}"/>
<RadioButton x:Name="EveningModeRadioButton"
Tag="1"
Content="Зима"
GroupName="Mode"
Checked="ModeRadioButton_Checked" Margin="10,0,0,0"
Style="{StaticResource ButtonRadioButtonStyle}"/>
<RadioButton x:Name="NightModeRadioButton"
Tag="2"
Content="Ніч"
GroupName="Mode"
Checked="ModeRadioButton_Checked" Margin="10,0,0,0"
Style="{StaticResource ButtonRadioButtonStyle}"/>
</StackPanel>
</Grid>
</UserControl>
@@ -1,9 +1,54 @@
namespace Azaion.Common.Controls;
using System.Windows;
using System.Windows.Controls;
using Azaion.Common.DTO;
namespace Azaion.Common.Controls;
public class DetectionClassChangedEventArgs(DetectionClass? detectionClass, int classNumber) : EventArgs
{
public DetectionClass? DetectionClass { get; } = detectionClass;
public int ClassNumber { get; } = classNumber;
}
public partial class DetectionClasses
{
public DetectionClasses()
public event EventHandler<DetectionClassChangedEventArgs>? DetectionClassChanged;
public DetectionClasses() => InitializeComponent();
public int CurrentClassNumber { get; private set; } = 0;
public DetectionClass? CurrentDetectionClass { get; set; }
private void DetectionDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e) =>
RaiseDetectionClassChanged();
private void ModeRadioButton_Checked(object sender, RoutedEventArgs e) =>
RaiseDetectionClassChanged();
private void RaiseDetectionClassChanged()
{
InitializeComponent();
var detClass = (DetectionClass)DetectionDataGrid.SelectedItem;
var baseClassNumber = detClass?.Id ?? 0;
var modeAmplifier = 0;
foreach (var child in ModeSwitcherPanel.Children)
if (child is RadioButton { IsChecked: true } rb)
if (int.TryParse(rb.Tag?.ToString(), out int modeIndex))
{
if (detClass != null)
detClass.PhotoMode = (PhotoMode)modeIndex;
modeAmplifier += modeIndex * 20;
}
CurrentDetectionClass = detClass;
CurrentClassNumber = baseClassNumber + modeAmplifier;
DetectionClassChanged?.Invoke(this, new DetectionClassChangedEventArgs(detClass, CurrentClassNumber));
}
public void SelectNum(int keyNumber)
{
DetectionDataGrid.SelectedIndex = keyNumber;
}
}
@@ -11,8 +11,6 @@ public class AnnotationConfig
[JsonIgnore]
public Dictionary<int, DetectionClass> DetectionClassesDict => _detectionClassesDict ??= AnnotationClasses.ToDictionary(x => x.Id);
public int? LastSelectedExplorerClass { get; set; }
public List<string> VideoFormats { get; set; } = null!;
public List<string> ImageFormats { get; set; } = null!;
+10 -1
View File
@@ -11,12 +11,21 @@ public class DetectionClass
public string Name { get; set; } = null!;
public string ShortName { get; set; } = null!;
public PhotoMode PhotoMode { get; set; }
[JsonIgnore]
public Color Color => Id.ToColor();
[JsonIgnore]
[JsonIgnore] //For UI
public int ClassNumber => Id + 1;
[JsonIgnore]
public SolidColorBrush ColorBrush => new(Color);
}
public enum PhotoMode
{
Regular = 0,
Winter = 20,
Night = 40
}
+10 -28
View File
@@ -93,38 +93,20 @@ public partial class DatasetExplorer
AllDetectionClasses = new ObservableCollection<DetectionClass>(
new List<DetectionClass> { new() {Id = -1, Name = "All", ShortName = "All"}}
.Concat(_annotationConfig.AnnotationClasses));
LvClasses.ItemsSource = AllDetectionClasses;
LvClasses.DetectionDataGrid.ItemsSource = AllDetectionClasses;
LvClasses.MouseUp += async (_, _) =>
LvClasses.DetectionClassChanged += async (_, args) =>
{
var selectedClass = (DetectionClass)LvClasses.SelectedItem;
ExplorerEditor.CurrentAnnClass = selectedClass;
_annotationConfig.LastSelectedExplorerClass = selectedClass.Id;
ExplorerEditor.CurrentAnnClass = args.DetectionClass;
if (Switcher.SelectedIndex == 0)
await ReloadThumbnails();
else
foreach (var ann in ExplorerEditor.CurrentDetections.Where(x => x.IsSelected))
ann.DetectionClass = selectedClass;
ann.DetectionClass = args.DetectionClass;
};
LvClasses.SelectionChanged += (_, _) =>
{
if (Switcher.SelectedIndex != 1)
return;
var selectedClass = (DetectionClass)LvClasses.SelectedItem;
if (selectedClass == null)
return;
ExplorerEditor.CurrentAnnClass = selectedClass;
foreach (var ann in ExplorerEditor.CurrentDetections.Where(x => x.IsSelected))
ann.DetectionClass = selectedClass;
};
LvClasses.SelectedIndex = _annotationConfig.LastSelectedExplorerClass ?? 0;
ExplorerEditor.CurrentAnnClass = (DetectionClass)LvClasses.SelectedItem;
ExplorerEditor.CurrentAnnClass = (DetectionClass)LvClasses.CurrentDetectionClass;
await _dbFactory.Run(async db =>
{
@@ -256,18 +238,18 @@ public partial class DatasetExplorer
{
AnnotationsTab.Visibility = Visibility.Collapsed;
EditorTab.Visibility = Visibility.Visible;
_tempSelectedClassIdx = LvClasses.SelectedIndex;
LvClasses.ItemsSource = _annotationConfig.AnnotationClasses;
_tempSelectedClassIdx = LvClasses.CurrentClassNumber;
LvClasses.DetectionDataGrid.ItemsSource = _annotationConfig.AnnotationClasses;
Switcher.SelectedIndex = 1;
LvClasses.SelectedIndex = Math.Max(0, _tempSelectedClassIdx - 1);
LvClasses.SelectNum(Math.Max(0, _tempSelectedClassIdx - 1));
}
else
{
AnnotationsTab.Visibility = Visibility.Visible;
EditorTab.Visibility = Visibility.Collapsed;
LvClasses.ItemsSource = AllDetectionClasses;
LvClasses.SelectedIndex = _tempSelectedClassIdx;
LvClasses.DetectionDataGrid.ItemsSource = AllDetectionClasses;
LvClasses.SelectNum(_tempSelectedClassIdx);
Switcher.SelectedIndex = 0;
}
}
@@ -42,7 +42,7 @@ public class DatasetExplorerEventHandler(
if ((int)key >= (int)Key.NumPad1 && (int)key <= (int)Key.NumPad9) keyNumber = key - Key.NumPad1;
if (keyNumber.HasValue)
datasetExplorer.LvClasses.SelectedIndex = keyNumber.Value;
datasetExplorer.LvClasses.SelectNum(keyNumber.Value);
else
{
if (datasetExplorer.Switcher.SelectedIndex == 1 && _keysControlEnumDict.TryGetValue(key, out var value))
@@ -88,13 +88,11 @@ public class DatasetExplorerEventHandler(
public async Task Handle(AnnotationCreatedEvent notification, CancellationToken cancellationToken)
{
var annotation = notification.Annotation;
var selectedClass = ((DetectionClass?)datasetExplorer.LvClasses.SelectedItem)?.Id;
if (selectedClass == null)
return;
var selectedClass = datasetExplorer.LvClasses.CurrentClassNumber;
//TODO: For editing existing need to handle updates
datasetExplorer.AddAnnotationToDict(annotation);
if (annotation.Classes.Contains(selectedClass.Value))
if (annotation.Classes.Contains(selectedClass))
{
var annThumb = new AnnotationThumbnail(annotation);
datasetExplorer.SelectedAnnotations.Add(annThumb);
+2 -1
View File
@@ -1,5 +1,6 @@
import json
import os
import time
from http import HTTPStatus
from uuid import UUID
import jwt
@@ -97,7 +98,7 @@ cdef class ApiClient:
stream = BytesIO(response.raw.read())
data = Security.decrypt_to(stream, key)
print(f'loaded file: {filename}, {len(data)} bytes')
constants.log(<str>f'Downloaded file: {filename}, {len(data)} bytes')
return data
cdef load_ai_model(self):
+3
View File
@@ -10,3 +10,6 @@ cdef str AI_MODEL_FILE # AI Model file
cdef bytes DONE_SIGNAL
cdef int MODEL_BATCH_SIZE
cdef log(str log_message, bytes client_id=*)
+7
View File
@@ -1,3 +1,5 @@
import time
cdef str CONFIG_FILE = "config.yaml" # Port for the zmq
cdef int QUEUE_MAXSIZE = 1000 # Maximum size of the command queue
@@ -10,3 +12,8 @@ cdef str AI_MODEL_FILE = "azaion.onnx"
cdef bytes DONE_SIGNAL = b"DONE"
cdef int MODEL_BATCH_SIZE = 4
cdef log(str log_message, bytes client_id=None):
local_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
client_str = '' if client_id is None else f' {client_id}'
print(f'[{local_time}{client_str}]: {log_message}')
-1
View File
@@ -29,7 +29,6 @@ cdef class CommandProcessor:
self.inference = Inference(self.api_client, self.on_annotation)
def start(self):
print('Started!')
while self.running:
try:
command = self.inference_queue.get(timeout=0.5)
+2 -2
View File
@@ -13,8 +13,8 @@ cdef class RemoteCommand:
40: "STOP_INFERENCE",
100: "EXIT"
}
data_str = f'. Data: {len(self.data)} bytes' if self.data else ''
return f'{command_type_names[self.command_type]}: {data_str}'
data_str = f'{len(self.data)} bytes' if self.data else ''
return f'{command_type_names[self.command_type]} ({data_str})'
@staticmethod
cdef from_msgpack(bytes data):
+5 -3
View File
@@ -14,7 +14,8 @@ cdef class RemoteCommandHandler:
self._router.setsockopt(zmq.LINGER, 0)
with open(<str>constants.CONFIG_FILE, "r") as f:
config = yaml.safe_load(f)
self._router.bind(f'tcp://*:{config["zmq_port"]}')
port = config["zmq_port"]
self._router.bind(f'tcp://*:{port}')
self._dealer = self._context.socket(zmq.DEALER)
self._dealer.setsockopt(zmq.LINGER, 0)
@@ -30,6 +31,7 @@ cdef class RemoteCommandHandler:
for _ in range(4): # 4 worker threads
worker = Thread(target=self._worker_loop, daemon=True)
self._workers.append(worker)
print(f'Listening to commands on port {port}...')
cdef start(self):
self._proxy_thread.start()
@@ -60,7 +62,7 @@ cdef class RemoteCommandHandler:
client_id, message = worker_socket.recv_multipart()
cmd = RemoteCommand.from_msgpack(<bytes> message)
cmd.client_id = client_id
print(f'Received [{cmd}] from the client {client_id}')
constants.log(<str>f'{cmd}', client_id)
self._on_command(cmd)
except Exception as e:
if not self._shutdown_event.is_set():
@@ -74,7 +76,7 @@ cdef class RemoteCommandHandler:
with self._context.socket(zmq.DEALER) as socket:
socket.connect("inproc://backend")
socket.send_multipart([client_id, data])
print(f'{len(data)} bytes was sent to client {client_id}')
constants.log(<str>f'Sent {len(data)} bytes.', client_id)
cdef stop(self):
self._shutdown_event.set()