using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using Hawkeye.VisionBuilder.Workflow; using Hawkeye.VisionBuilder.Workflow.Datatypes; using VisionBuilder.UI.Common.Commands; using VisionBuilder.UI.Common.RecipeProcessing; using VisionBuilder.UI.Common.ViewModel.Classes; namespace VisionBuilder.UI.Recipes.HawkeyeRecipe { public class HawkeyeRecognitionControl: IRecognitionControl { private readonly IImageSource _imageSource; private readonly HawkeyeRecognitionSettings _recognitionConfiguration; private readonly ILoadingService _loadingService; private CancellationTokenSource _cts; private Task _loopTask; public HawkeyeRecognitionControl(IImageSource imageSource, HawkeyeRecognitionSettings recognitionConfiguration, ILoadingService loadingService) { _imageSource = imageSource; _recognitionConfiguration = recognitionConfiguration; _loadingService = loadingService; } public List GetRecipesData() { _loadingService.StartLoading($"Loading recipes for {_recognitionConfiguration.CameraName}..."); try { var files = WorkflowRecipeHelper.ListRecipeFiles(_recognitionConfiguration.RecipeNameFilter); List recipes = new List(); foreach (var file in files) { var workFlow = WorkflowList.LoadJSONFromFile(file); var recipe = new RecipeData { RecipeName = Path.GetFileNameWithoutExtension(file), Image = workFlow.RecipeImage }; recipes.Add(recipe); } return recipes; } finally { _loadingService.StopLoading($"Loading recipes for {_recognitionConfiguration.CameraName}..."); } } RecipeData _currentRecipe; public void SetRecipe(RecipeData recipe) { // error if running if (IsRunning) { throw new InvalidOperationException("Cannot change recipe while recognition is running."); } _currentRecipe = recipe; } public bool IsRunning { get; set; } public bool IsPaused { get; set; } private DateTime _startTime; private WorkflowList _workflow; public void Start() { if (_currentRecipe == null) { throw new InvalidOperationException("No recipe set."); } if (IsRunning) { throw new InvalidOperationException("Recognition is already running."); } _loadingService.StartLoading($"Starting recipe {_currentRecipe.RecipeName} on {_recognitionConfiguration.CameraName}..."); _workflow = WorkflowList.LoadJSONFromFile("..\\Data\\Recipes\\" + _currentRecipe.RecipeName + ".jhrcp"); _startTime = DateTime.Now; IsRunning = true; _cts = new CancellationTokenSource(); _loopTask = Task.Run(() => Loop(_cts.Token), _cts.Token); SessionStarted?.Invoke(new SessionStartedEvent { RecipeName = _currentRecipe.RecipeName, SessionStarted = _startTime, }); _loadingService.StopLoading($"Starting recipe {_currentRecipe.RecipeName} on {_recognitionConfiguration.CameraName}..."); } public void Stop() { if (!IsRunning) return ; _loadingService.StartLoading($"Stopping {_recognitionConfiguration.CameraName}"); _cts?.Cancel(); try { _loopTask?.Wait(); } catch (AggregateException ex) when (ex.InnerExceptions.All(e => e is TaskCanceledException)) { // Ignore cancellation exceptions } finally { IsRunning = false; _cts?.Dispose(); _cts = null; _loopTask = null; } SessionEnded?.Invoke(new SessionEndedEvent { SessionEnded = DateTime.Now }); _loadingService.StopLoading($"Stopping {_recognitionConfiguration.CameraName}"); } public void Pause() { IsPaused= true; } public void Resume() { IsPaused = false; } private async Task Loop(CancellationToken token) { // Start the recognition process using the Hawkeye library while (!token.IsCancellationRequested) { if (IsPaused) { await Task.Delay(100, token); continue; } var sw = Stopwatch.StartNew(); _workflow.Context.CancellationToken= token; _workflow.ImageSource= _imageSource; try { _workflow.Execute(); } catch (Exception e) when(token.IsCancellationRequested) { sw.Stop(); return; } sw.Stop(); if (sw.ElapsedMilliseconds < _recognitionConfiguration.MinimumProcessingTime) { Thread.Sleep(_recognitionConfiguration.MinimumProcessingTime - (int)sw.ElapsedMilliseconds); } string[] errorNames = _workflow.Operations.Where(x => !x.Result).Select(x => x.Label).ToArray(); var annotated = _workflow.Context.ActiveImage.ImageData.Clone(); var canvas = new OpenCVCanvas(annotated); _workflow.Context.GraphicsElements.ForEach(x => x.Draw(canvas)); var processingResult = new ImageProcessedEvent() { SessionStart = _startTime, RecipeName = _currentRecipe.RecipeName, AnalysisTime = sw.Elapsed, ErrorNames = errorNames.ToList(), HasError = errorNames.Length > 0, ImageSource = _recognitionConfiguration.CameraName, ImageOriginal = _workflow.Context.LastCameraImage.ImageData, ImageAnalysis = annotated }; ImageProcessed(processingResult); } } public event Action ImageProcessed = delegate{}; public event Action? SessionStarted = delegate { }; public event Action? SessionEnded = delegate { }; } }