233 lines
8.1 KiB
C#
233 lines
8.1 KiB
C#
using System.CodeDom;
|
|
using System.Diagnostics;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Hawkeye.VisionBuilder.Workflow;
|
|
using Hawkeye.VisionBuilder.Workflow.Datatypes;
|
|
using Hawkeye.VisionBuilder.Workflow.Operations;
|
|
using Serilog;
|
|
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<RecipeData> GetRecipesData()
|
|
{
|
|
_loadingService.StartLoading($"Loading recipes for {_recognitionConfiguration.CameraName}...");
|
|
try
|
|
{
|
|
var files = WorkflowRecipeHelper.ListRecipeFiles(_recognitionConfiguration.RecipeNameFilter);
|
|
List<RecipeData> recipes = new List<RecipeData>();
|
|
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();
|
|
|
|
|
|
Log.Information($"Warming up");
|
|
try
|
|
{
|
|
var swWarmup = Stopwatch.StartNew();
|
|
// warmup run
|
|
_workflow.ImageSource = new EmptyImageSource();
|
|
_workflow.Context = new Context();
|
|
_workflow.Context.CancellationToken = CancellationToken.None;
|
|
_workflow.Execute(); // Warmup run
|
|
swWarmup.Stop();
|
|
Log.Information($"Warmup run took {swWarmup.ElapsedMilliseconds} ms");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log.Error(ex, "Error during warmup run");
|
|
}
|
|
|
|
_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));
|
|
|
|
TimeSpan cameraTime = TimeSpan.FromMilliseconds(0);
|
|
var cameraOperation = _workflow.Operations.FirstOrDefault(x => x is GetImageOperation);
|
|
if (cameraOperation != null)
|
|
{
|
|
cameraTime=cameraOperation.ExecutionTime;
|
|
}
|
|
|
|
var processingResult = new ImageProcessedEvent()
|
|
{
|
|
SessionStart = _startTime,
|
|
RecipeName = _currentRecipe.RecipeName,
|
|
AnalysisTime = sw.Elapsed- cameraTime,
|
|
ErrorNames = errorNames.ToList(),
|
|
HasError = errorNames.Length > 0,
|
|
ImageSource = _recognitionConfiguration.CameraName,
|
|
ImageOriginal = _workflow.Context.LastCameraImage.ImageData,
|
|
ImageAnalysis = annotated
|
|
};
|
|
|
|
var swProcessed = Stopwatch.StartNew();
|
|
ImageProcessed(processingResult);
|
|
swProcessed.Stop();
|
|
Log.Information($"ImageProcessed event handled in {swProcessed.ElapsedMilliseconds} ms");
|
|
|
|
|
|
}
|
|
}
|
|
|
|
public event Action<ImageProcessedEvent> ImageProcessed = delegate{};
|
|
public event Action<SessionStartedEvent>? SessionStarted = delegate { };
|
|
public event Action<SessionEndedEvent>? SessionEnded = delegate { };
|
|
}
|
|
}
|