From 1aecb79ade9479bb54e500213e64e60a74603c4f Mon Sep 17 00:00:00 2001 From: meelstorm <8780022+TesAnti@users.noreply.github.com> Date: Mon, 29 Sep 2025 09:31:57 +0200 Subject: [PATCH] 1.0.5 --- Plugins/CandyboxPlugin/Recipe/HistoRecipe.cs | 4 +++- .../Commands/ErrorsInSequenceEvent.cs | 6 +++++ .../Processing/BaseRecognitionControl.cs | 23 +++++++++++++++---- .../BaseRecognitionControlSettings.cs | 2 ++ .../Processing/IRecognitionControl.cs | 1 + .../ViewModel/SingleCameraVM.cs | 20 ++++++++++++---- .../EProcessingEvent.cs | 1 + .../Modules/IOCommanderCameraModule.cs | 10 ++++++-- .../Settings/IOCommanderCameraSettings.cs | 1 + .../Form1.Designer.cs | 3 +++ VisionBuilder.UI.Windows.Test/Form1.cs | 23 ++++++++++++++++++- .../VisionBuilder.UI.Windows.Uno.csproj | 2 +- VisionBuilder.UI.Windows/Components/Stats.cs | 10 ++++++-- VisionBuilder.UI.Windows/ModuleExtensions.cs | 2 ++ VisionBuilder.UI.Windows/WindowsUISettings.cs | 14 +++++++++++ VisionBuilder.UI.sln | 4 ++++ 16 files changed, 110 insertions(+), 16 deletions(-) create mode 100644 VisionBuilder.UI.Common/Commands/ErrorsInSequenceEvent.cs create mode 100644 VisionBuilder.UI.Windows/WindowsUISettings.cs diff --git a/Plugins/CandyboxPlugin/Recipe/HistoRecipe.cs b/Plugins/CandyboxPlugin/Recipe/HistoRecipe.cs index ecccb03..f1fa630 100644 --- a/Plugins/CandyboxPlugin/Recipe/HistoRecipe.cs +++ b/Plugins/CandyboxPlugin/Recipe/HistoRecipe.cs @@ -119,7 +119,9 @@ namespace CandyboxPlugin.Recipe } File.WriteAllText(_configurationPath, JsonSerializer.Serialize(_learnedParameters, new JsonSerializerOptions() { WriteIndented = true })); - image.Resize(ThumbnailSize).SaveImage(Path.Combine("..\\Data\\Samples", Path.GetFileNameWithoutExtension(_recipeName) + ".bmp")); + var fullSamplePath = Path.GetFullPath(Path.Combine("..\\Data\\Samples", _recipeName + ".bmp")); + Directory.CreateDirectory(Path.GetDirectoryName(fullSamplePath)); + image.Resize(ThumbnailSize).SaveImage(fullSamplePath); } } diff --git a/VisionBuilder.UI.Common/Commands/ErrorsInSequenceEvent.cs b/VisionBuilder.UI.Common/Commands/ErrorsInSequenceEvent.cs new file mode 100644 index 0000000..7dbbf69 --- /dev/null +++ b/VisionBuilder.UI.Common/Commands/ErrorsInSequenceEvent.cs @@ -0,0 +1,6 @@ +namespace VisionBuilder.UI.Common.Commands; + +public class ErrorsInSequenceEvent +{ + public int Errors { get; set; } +} \ No newline at end of file diff --git a/VisionBuilder.UI.Common/Processing/BaseRecognitionControl.cs b/VisionBuilder.UI.Common/Processing/BaseRecognitionControl.cs index 97b4138..0cf21f5 100644 --- a/VisionBuilder.UI.Common/Processing/BaseRecognitionControl.cs +++ b/VisionBuilder.UI.Common/Processing/BaseRecognitionControl.cs @@ -128,7 +128,7 @@ public abstract class BaseRecognitionControl: IRecognitionControl SessionEnded = DateTime.Now }); _loadingService.StopLoading($"Stopping {_settings.CameraName}"); - + IsPaused=false; // ensure paused is reset } public void Pause() @@ -141,6 +141,8 @@ public abstract class BaseRecognitionControl: IRecognitionControl IsPaused = false; } + int _errorsInSequence = 0; + private async Task Loop(CancellationToken token) { @@ -149,7 +151,7 @@ public abstract class BaseRecognitionControl: IRecognitionControl { if (IsPaused) { - await Task.Delay(100, token); + await Task.Delay(100, token).ConfigureAwait(false); continue; } @@ -165,6 +167,18 @@ public abstract class BaseRecognitionControl: IRecognitionControl Thread.Sleep(_settings.MinimumProcessingTime - (int)processed.Value.processingTime.Milliseconds); } + if (processed.Value.errorNames.Length > 0) + { + _errorsInSequence++; + if (_errorsInSequence >= _settings.ErrorsInSequenceAlarm) + { + ErrorsInSequenceAlarm(new ErrorsInSequenceEvent(){Errors = _errorsInSequence}); + } + } + else + { + _errorsInSequence = 0; + } var processingResult = new ImageProcessedEvent() { @@ -188,6 +202,7 @@ public abstract class BaseRecognitionControl: IRecognitionControl } public event Action ImageProcessed = delegate { }; - public event Action? SessionStarted = delegate { }; - public event Action? SessionEnded = delegate { }; + public event Action SessionStarted = delegate { }; + public event Action SessionEnded = delegate { }; + public event Action ErrorsInSequenceAlarm = delegate { }; } \ No newline at end of file diff --git a/VisionBuilder.UI.Common/Processing/BaseRecognitionControlSettings.cs b/VisionBuilder.UI.Common/Processing/BaseRecognitionControlSettings.cs index f4bedd1..6487b41 100644 --- a/VisionBuilder.UI.Common/Processing/BaseRecognitionControlSettings.cs +++ b/VisionBuilder.UI.Common/Processing/BaseRecognitionControlSettings.cs @@ -8,10 +8,12 @@ public abstract class BaseRecognitionControlSettings(string cameraName) : ISetti public int MinimumProcessingTime { get; set; } public string RecipeNameFilter { get; set; } = "*"; + public int ErrorsInSequenceAlarm { get; set; } = 5; public virtual void RegisterSettings(InspectronSettings settings) { settings.RegisterSimple(this, () => this.MinimumProcessingTime, CameraName + "/Hawkeye recognition", "Minimum processing time (ms)"); settings.RegisterSimple(this, () => this.RecipeNameFilter, CameraName + "/Hawkeye recognition", nameof(RecipeNameFilter)); + settings.RegisterSimple(this, () => this.ErrorsInSequenceAlarm, CameraName + "/Hawkeye recognition", nameof(ErrorsInSequenceAlarm)); } } \ No newline at end of file diff --git a/VisionBuilder.UI.Common/Processing/IRecognitionControl.cs b/VisionBuilder.UI.Common/Processing/IRecognitionControl.cs index 734afcf..2dca183 100644 --- a/VisionBuilder.UI.Common/Processing/IRecognitionControl.cs +++ b/VisionBuilder.UI.Common/Processing/IRecognitionControl.cs @@ -15,5 +15,6 @@ public interface IRecognitionControl event Action ImageProcessed; event Action SessionStarted; event Action SessionEnded; + event Action ErrorsInSequenceAlarm; } \ No newline at end of file diff --git a/VisionBuilder.UI.Common/ViewModel/SingleCameraVM.cs b/VisionBuilder.UI.Common/ViewModel/SingleCameraVM.cs index 5996a4e..1f92ac6 100644 --- a/VisionBuilder.UI.Common/ViewModel/SingleCameraVM.cs +++ b/VisionBuilder.UI.Common/ViewModel/SingleCameraVM.cs @@ -123,19 +123,29 @@ namespace VisionBuilder.UI.Common } [RelayCommand(CanExecute = nameof(CanStart))] - public void Start() + public async Task Start() { - _handlingEnabled = true; - _recognitionControl.Start(); + IsRunning = true; + await Task.Run(() => + { + _recognitionControl.Start(); + }); + _handlingEnabled = true; + } [RelayCommand(CanExecute = nameof(CanStop))] - public void Stop() + public async Task Stop() { _handlingEnabled = false; - _recognitionControl.Stop(); + await Task.Run(() => + { + _recognitionControl.Stop(); + }); + IsPaused = false; IsRunning = false; + } [RelayCommand(CanExecute = nameof(IsResumed))] diff --git a/VisionBuilder.UI.IOCommander/EProcessingEvent.cs b/VisionBuilder.UI.IOCommander/EProcessingEvent.cs index 73ac9cf..985f5fb 100644 --- a/VisionBuilder.UI.IOCommander/EProcessingEvent.cs +++ b/VisionBuilder.UI.IOCommander/EProcessingEvent.cs @@ -8,5 +8,6 @@ public enum EProcessingEvent SessionEnded, ErrorOccurred, GoodOccured, + ErrorsInSequenceAlarm, TestMode } \ No newline at end of file diff --git a/VisionBuilder.UI.IOCommander/Modules/IOCommanderCameraModule.cs b/VisionBuilder.UI.IOCommander/Modules/IOCommanderCameraModule.cs index 200f564..825944f 100644 --- a/VisionBuilder.UI.IOCommander/Modules/IOCommanderCameraModule.cs +++ b/VisionBuilder.UI.IOCommander/Modules/IOCommanderCameraModule.cs @@ -28,10 +28,16 @@ public class IOCommanderCameraModule: IVisionBuilderModule _recognitionControl.ImageProcessed += _recognitionControl_ImageProcessed; _recognitionControl.SessionStarted += _recognitionControl_SessionStarted; _recognitionControl.SessionEnded += _recognitionControl_SessionEnded; - - + _recognitionControl.ErrorsInSequenceAlarm += _recognitionControl_ErrorsInSequenceAlarm; + + + } + private void _recognitionControl_ErrorsInSequenceAlarm(ErrorsInSequenceEvent obj) + { + EmitEvent(EProcessingEvent.ErrorsInSequenceAlarm); + } private void ProcessCommand(EGPIOCommand command) { diff --git a/VisionBuilder.UI.IOCommander/Settings/IOCommanderCameraSettings.cs b/VisionBuilder.UI.IOCommander/Settings/IOCommanderCameraSettings.cs index 7bf7c2f..1263a8c 100644 --- a/VisionBuilder.UI.IOCommander/Settings/IOCommanderCameraSettings.cs +++ b/VisionBuilder.UI.IOCommander/Settings/IOCommanderCameraSettings.cs @@ -17,6 +17,7 @@ namespace VisionBuilder.UI.IOCommander.Settings new (EProcessingEvent.SessionEnded), new (EProcessingEvent.ErrorOccurred), new (EProcessingEvent.GoodOccured), + new (EProcessingEvent.ErrorsInSequenceAlarm), ]; [SettingDescription(@" diff --git a/VisionBuilder.UI.Windows.Test/Form1.Designer.cs b/VisionBuilder.UI.Windows.Test/Form1.Designer.cs index 958fb21..3391538 100644 --- a/VisionBuilder.UI.Windows.Test/Form1.Designer.cs +++ b/VisionBuilder.UI.Windows.Test/Form1.Designer.cs @@ -95,6 +95,7 @@ // // materialDivider1 // + materialDivider1.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; materialDivider1.BackColor = Color.FromArgb(55, 71, 79); materialDivider1.Depth = 0; materialDivider1.Location = new Point(8, 984); @@ -106,6 +107,7 @@ // // singleCameraControl1 // + singleCameraControl1.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; singleCameraControl1.BackColor = Color.White; singleCameraControl1.Location = new Point(8, 32); singleCameraControl1.Name = "singleCameraControl1"; @@ -132,6 +134,7 @@ // // flowLayoutPanel1 // + flowLayoutPanel1.Anchor = AnchorStyles.Bottom | AnchorStyles.Left; flowLayoutPanel1.BackColor = Color.Transparent; flowLayoutPanel1.Controls.Add(btnTestMode); flowLayoutPanel1.Controls.Add(btnSettings); diff --git a/VisionBuilder.UI.Windows.Test/Form1.cs b/VisionBuilder.UI.Windows.Test/Form1.cs index b0ff42e..1c215c7 100644 --- a/VisionBuilder.UI.Windows.Test/Form1.cs +++ b/VisionBuilder.UI.Windows.Test/Form1.cs @@ -14,13 +14,15 @@ namespace VisionBuilder.UI.Windows.Test private readonly MainWindowVM _mainWindowVm; private readonly IPasswordInputService _passwordInputService; private readonly UIConfiguration _uiConfiguration; + private readonly WindowsUISettings _windowsUiSettings; - public Form1(MainWindowVM mainWindowVm, IPasswordInputService passwordInputService, UIConfiguration uiConfiguration) + public Form1(MainWindowVM mainWindowVm, IPasswordInputService passwordInputService, UIConfiguration uiConfiguration, WindowsUISettings windowsUiSettings) { _mainWindowVm = mainWindowVm; _passwordInputService = passwordInputService; _uiConfiguration = uiConfiguration; + _windowsUiSettings = windowsUiSettings; MaterialSkin.MaterialSkinManager.ConfigureForInspectron(); InitializeComponent(); singleCameraControl1.SetViewModel(mainWindowVm.SingleCameraVms[0]); @@ -51,6 +53,18 @@ namespace VisionBuilder.UI.Windows.Test { _mainWindowVm.OnProgramStarted(); BringToFront(); + if (_windowsUiSettings.FullScreen) + { + WindowState = FormWindowState.Maximized; + } + } + + protected override void OnShown(EventArgs e) + { + base.OnShown(e); + flowLayoutPanel1.Left = (ClientSize.Width - flowLayoutPanel1.Width) / 2; + + } private void btnExit_Click(object sender, EventArgs e) @@ -59,6 +73,13 @@ namespace VisionBuilder.UI.Windows.Test Environment.Exit(0); } + protected override void OnClosed(EventArgs e) + { + base.OnClosed(e); + _mainWindowVm.OnProgramClosed(); + Environment.Exit(0); + } + private void btnMinimize_Click(object sender, EventArgs e) { WindowState = FormWindowState.Minimized; diff --git a/VisionBuilder.UI.Windows.Test/VisionBuilder.UI.Windows.Uno.csproj b/VisionBuilder.UI.Windows.Test/VisionBuilder.UI.Windows.Uno.csproj index 747a63d..31eef46 100644 --- a/VisionBuilder.UI.Windows.Test/VisionBuilder.UI.Windows.Uno.csproj +++ b/VisionBuilder.UI.Windows.Test/VisionBuilder.UI.Windows.Uno.csproj @@ -8,7 +8,7 @@ enable Inspectron icon-512.ico false - 1.0.4 + 1.0.5 diff --git a/VisionBuilder.UI.Windows/Components/Stats.cs b/VisionBuilder.UI.Windows/Components/Stats.cs index e8c9626..920dd20 100644 --- a/VisionBuilder.UI.Windows/Components/Stats.cs +++ b/VisionBuilder.UI.Windows/Components/Stats.cs @@ -26,7 +26,14 @@ namespace VisionBuilder.UI.Windows.Components private void _statisticsVm_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e) { - switch (e.PropertyName) + if (InvokeRequired) Invoke(() => HandleStatisticsPropertyChange(e.PropertyName!)); + else + HandleStatisticsPropertyChange(e.PropertyName!); + } + + private void HandleStatisticsPropertyChange(string propertyName) + { + switch (propertyName) { case nameof(StatisticsVM.SessionStarted): Clear(); @@ -58,7 +65,6 @@ namespace VisionBuilder.UI.Windows.Components break; } } - void InitializeFields() { UpdateMeta(StartedAtLabel,""); diff --git a/VisionBuilder.UI.Windows/ModuleExtensions.cs b/VisionBuilder.UI.Windows/ModuleExtensions.cs index 7639261..5a0d646 100644 --- a/VisionBuilder.UI.Windows/ModuleExtensions.cs +++ b/VisionBuilder.UI.Windows/ModuleExtensions.cs @@ -1,4 +1,5 @@ using Ninject; +using VisionBuilder.UI.Common; using VisionBuilder.UI.Common.Processing; using VisionBuilder.UI.Common.Services; using VisionBuilder.UI.Common.ViewModel.Interfaces.UI; @@ -15,6 +16,7 @@ public static class ModuleExtensions self.Bind().To().InSingletonScope(); self.Bind().To().InSingletonScope(); self.Bind().To().InSingletonScope(); + self.Bind().To().InSingletonScope(); return self; } } \ No newline at end of file diff --git a/VisionBuilder.UI.Windows/WindowsUISettings.cs b/VisionBuilder.UI.Windows/WindowsUISettings.cs new file mode 100644 index 0000000..072f302 --- /dev/null +++ b/VisionBuilder.UI.Windows/WindowsUISettings.cs @@ -0,0 +1,14 @@ +using Inspectron.Settings; +using VisionBuilder.UI.Common; + +namespace VisionBuilder.UI.Windows; + +public class WindowsUISettings: ISettings +{ + public bool FullScreen { get; set; }=false; + + public void RegisterSettings(InspectronSettings settings) + { + settings.RegisterSimple(this, () => this.FullScreen,"System",nameof(FullScreen)); + } +} \ No newline at end of file diff --git a/VisionBuilder.UI.sln b/VisionBuilder.UI.sln index c7df656..9f6299f 100644 --- a/VisionBuilder.UI.sln +++ b/VisionBuilder.UI.sln @@ -13,7 +13,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MaterialSkin.Core", "framew EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisionBuilder.UI.Windows.Uno", "VisionBuilder.UI.Windows.Test\VisionBuilder.UI.Windows.Uno.csproj", "{7697A266-A721-4D74-9C5C-0D4F2F6BBF68}" ProjectSection(ProjectDependencies) = postProject + {19E9B1A2-FBC6-2668-EDDF-1B3A6828184A} = {19E9B1A2-FBC6-2668-EDDF-1B3A6828184A} {31C47198-DEC2-4073-A0C2-220549502CD1} = {31C47198-DEC2-4073-A0C2-220549502CD1} + {52D6A9AE-D0F1-4C52-B688-E0219169E179} = {52D6A9AE-D0F1-4C52-B688-E0219169E179} + {B20D7E75-1C19-632D-21D2-2663B0329C5E} = {B20D7E75-1C19-632D-21D2-2663B0329C5E} + {DB20082B-60E8-D623-3F3A-04612A929CD6} = {DB20082B-60E8-D623-3F3A-04612A929CD6} EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Inspectron.Settings", "framework\Inspectron.Settings\Inspectron.Settings.csproj", "{E286CE4C-B68A-94B6-F477-0DBF42358009}"