From c314268d1e6faece57f7800e802c0d0842f06785 Mon Sep 17 00:00:00 2001 From: Alex Bezdieniezhnykh Date: Mon, 17 Feb 2025 18:41:18 +0200 Subject: [PATCH] added better logging to python add day / winter / night switcher --- Azaion.Annotator/Annotator.xaml.cs | 8 +- Azaion.Annotator/AnnotatorEventHandler.cs | 10 +- Azaion.Common/Controls/DetectionClasses.xaml | 151 ++++++++++++------ .../Controls/DetectionClasses.xaml.cs | 51 +++++- Azaion.Common/DTO/Config/AnnotationConfig.cs | 2 - Azaion.Common/DTO/DetectionClass.cs | 11 +- Azaion.Dataset/DatasetExplorer.xaml.cs | 38 ++--- Azaion.Dataset/DatasetExplorerEventHandler.cs | 8 +- Azaion.Inference/api_client.pyx | 3 +- Azaion.Inference/constants.pxd | 5 +- Azaion.Inference/constants.pyx | 7 + Azaion.Inference/main.pyx | 1 - Azaion.Inference/remote_command.pyx | 4 +- Azaion.Inference/remote_command_handler.pyx | 8 +- 14 files changed, 204 insertions(+), 103 deletions(-) diff --git a/Azaion.Annotator/Annotator.xaml.cs b/Azaion.Annotator/Annotator.xaml.cs index 3fcf801..a1b95b1 100644 --- a/Azaion.Annotator/Annotator.xaml.cs +++ b/Azaion.Annotator/Annotator.xaml.cs @@ -120,8 +120,8 @@ public partial class Annotator TbFolder.Text = _appConfig.DirectoriesConfig.VideosDirectory; AnnotationClasses = new ObservableCollection(_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)); }; diff --git a/Azaion.Annotator/AnnotatorEventHandler.cs b/Azaion.Annotator/AnnotatorEventHandler.cs index 4bfefce..3764872 100644 --- a/Azaion.Annotator/AnnotatorEventHandler.cs +++ b/Azaion.Annotator/AnnotatorEventHandler.cs @@ -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); diff --git a/Azaion.Common/Controls/DetectionClasses.xaml b/Azaion.Common/Controls/DetectionClasses.xaml index c823502..7a125ee 100644 --- a/Azaion.Common/Controls/DetectionClasses.xaml +++ b/Azaion.Common/Controls/DetectionClasses.xaml @@ -1,49 +1,106 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + - - \ No newline at end of file + + + + + + + + + + diff --git a/Azaion.Common/Controls/DetectionClasses.xaml.cs b/Azaion.Common/Controls/DetectionClasses.xaml.cs index c60a581..a52f8b4 100644 --- a/Azaion.Common/Controls/DetectionClasses.xaml.cs +++ b/Azaion.Common/Controls/DetectionClasses.xaml.cs @@ -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? 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; } } \ No newline at end of file diff --git a/Azaion.Common/DTO/Config/AnnotationConfig.cs b/Azaion.Common/DTO/Config/AnnotationConfig.cs index c46979a..736e33b 100644 --- a/Azaion.Common/DTO/Config/AnnotationConfig.cs +++ b/Azaion.Common/DTO/Config/AnnotationConfig.cs @@ -11,8 +11,6 @@ public class AnnotationConfig [JsonIgnore] public Dictionary DetectionClassesDict => _detectionClassesDict ??= AnnotationClasses.ToDictionary(x => x.Id); - public int? LastSelectedExplorerClass { get; set; } - public List VideoFormats { get; set; } = null!; public List ImageFormats { get; set; } = null!; diff --git a/Azaion.Common/DTO/DetectionClass.cs b/Azaion.Common/DTO/DetectionClass.cs index be07669..af60116 100644 --- a/Azaion.Common/DTO/DetectionClass.cs +++ b/Azaion.Common/DTO/DetectionClass.cs @@ -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 } \ No newline at end of file diff --git a/Azaion.Dataset/DatasetExplorer.xaml.cs b/Azaion.Dataset/DatasetExplorer.xaml.cs index 3f610ac..845538d 100644 --- a/Azaion.Dataset/DatasetExplorer.xaml.cs +++ b/Azaion.Dataset/DatasetExplorer.xaml.cs @@ -93,38 +93,20 @@ public partial class DatasetExplorer AllDetectionClasses = new ObservableCollection( new List { 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; } } diff --git a/Azaion.Dataset/DatasetExplorerEventHandler.cs b/Azaion.Dataset/DatasetExplorerEventHandler.cs index 10fa47f..3a7926b 100644 --- a/Azaion.Dataset/DatasetExplorerEventHandler.cs +++ b/Azaion.Dataset/DatasetExplorerEventHandler.cs @@ -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); diff --git a/Azaion.Inference/api_client.pyx b/Azaion.Inference/api_client.pyx index aef5732..76efcb5 100644 --- a/Azaion.Inference/api_client.pyx +++ b/Azaion.Inference/api_client.pyx @@ -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(f'Downloaded file: {filename}, {len(data)} bytes') return data cdef load_ai_model(self): diff --git a/Azaion.Inference/constants.pxd b/Azaion.Inference/constants.pxd index 926d517..6ed8f80 100644 --- a/Azaion.Inference/constants.pxd +++ b/Azaion.Inference/constants.pxd @@ -9,4 +9,7 @@ cdef str QUEUE_CONFIG_FILENAME # queue config filename to load from api cdef str AI_MODEL_FILE # AI Model file cdef bytes DONE_SIGNAL -cdef int MODEL_BATCH_SIZE \ No newline at end of file +cdef int MODEL_BATCH_SIZE + + +cdef log(str log_message, bytes client_id=*) \ No newline at end of file diff --git a/Azaion.Inference/constants.pyx b/Azaion.Inference/constants.pyx index 5748e9f..eff149d 100644 --- a/Azaion.Inference/constants.pyx +++ b/Azaion.Inference/constants.pyx @@ -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}') \ No newline at end of file diff --git a/Azaion.Inference/main.pyx b/Azaion.Inference/main.pyx index 96f06dc..297bbcb 100644 --- a/Azaion.Inference/main.pyx +++ b/Azaion.Inference/main.pyx @@ -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) diff --git a/Azaion.Inference/remote_command.pyx b/Azaion.Inference/remote_command.pyx index 9c70c55..5109387 100644 --- a/Azaion.Inference/remote_command.pyx +++ b/Azaion.Inference/remote_command.pyx @@ -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): diff --git a/Azaion.Inference/remote_command_handler.pyx b/Azaion.Inference/remote_command_handler.pyx index b44b051..42c64ce 100644 --- a/Azaion.Inference/remote_command_handler.pyx +++ b/Azaion.Inference/remote_command_handler.pyx @@ -14,7 +14,8 @@ cdef class RemoteCommandHandler: self._router.setsockopt(zmq.LINGER, 0) with open(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( message) cmd.client_id = client_id - print(f'Received [{cmd}] from the client {client_id}') + constants.log(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(f'Sent {len(data)} bytes.', client_id) cdef stop(self): self._shutdown_event.set()