using Compunet.YoloV8; using Hawkeye.VisionBuilder.Features.ColorProgileGenerator; using Hawkeye.VisionBuilder.Features.ImagePreview; using Hawkeye.VisionBuilder.Features.ImagesStrip; using Hawkeye.VisionBuilder.Features.ToolEditor; using Hawkeye.VisionBuilder.Features.VisionSteps; using Hawkeye.VisionBuilder.Features.Yolo; using Hawkeye.VisionBuilder.Panels; using Hawkeye.VisionBuilder.Workflow; using Hawkeye.VisionBuilder.Workflow.ColorStudioClasses; using Hawkeye.VisionBuilder.Workflow.Configuration; using Hawkeye.VisionBuilder.Workflow.Datatypes; using Hawkeye.VisionBuilder.Workflow.Operations.AI; using Hawkeye.VisionBuilder.Workflow.Operations.Filters; using Hawkeye.VisionBuilder.Workflow.Operations.Memory; using Inspectron.Settings.WindowsWizard; using Inspectron.Settings.WindowsWizard.Controls; using Microsoft.WindowsAPICodePack.Dialogs; using OpenCvSharp; using OpenCvSharp.Extensions; using System.Windows.Forms; using Hawkeye.VisionBuilder.Features.ImageStatistics; using Size = OpenCvSharp.Size; namespace Hawkeye.VisionBuilder { public partial class MainWindow : Form { private readonly WorkflowList _workflowList; private readonly OperationDiscoveryService _discoveryService; private readonly ToolConfigurationPanel _toolConfigurationPanel; private readonly ImagePreviewPanel _previewPanel; private readonly VisionStepsPanel _visionStepsPanel; private ImageStripPanel _imagesStripPanel; public MainWindow(WorkflowList workflowList, OperationDiscoveryService discoveryService) { _workflowList = workflowList; _discoveryService = discoveryService; InitializeComponent(); { _previewPanel = new ImagePreviewPanel(); _previewPanel.MdiParent = this; _previewPanel.Show(); } { _visionStepsPanel = new VisionStepsPanel(workflowList, discoveryService, _previewPanel); _visionStepsPanel.MdiParent = this; _visionStepsPanel.Show(); } { _toolConfigurationPanel = new ToolConfigurationPanel(workflowList, _visionStepsPanel); _toolConfigurationPanel.MdiParent = this; _toolConfigurationPanel.Show(); } { ReinitCameraPanel(workflowList); } _visionStepsPanel.OperationSelected += operation => { _toolConfigurationPanel.SetOperation(operation); }; //var codeEditor = new ScriptEditorPanel(); //codeEditor.MdiParent = this; //codeEditor.Show(); } private void ReinitCameraPanel(WorkflowList workflowList) { if (_imagesStripPanel != null) { _imagesStripPanel.Close(); _imagesStripPanel.Dispose(); _imagesStripPanel = null; } _imagesStripPanel = new ImageStripPanel(); _workflowList.ImageSource= _imagesStripPanel; _imagesStripPanel.ImageSelected += data => { if (_imagesStripPanel is ImageStripPanel imagesStripPanel) { if (imagesStripPanel.IsExecutingWorkflow) { _visionStepsPanel.ExecuteWorkflow(); var result = _visionStepsPanel.WorkflowList.Operations.All(x => x.Result == true); ProcessResult(result); (_imagesStripPanel as ImageStripPanel).InformImageProcessed(result); return; } } _visionStepsPanel.ProcessRowSelection(); var selectedOperation = _visionStepsPanel.GetSelectedOperation(); if (selectedOperation != null) { ProcessResult(selectedOperation.Result); (_imagesStripPanel as ImageStripPanel).InformImageProcessed(selectedOperation.Result); } }; if(Directory.Exists(_workflowList.Configuration.EmulationPath)) _imagesStripPanel.LoadImages(_workflowList.Configuration.EmulationPath); _imagesStripPanel.MdiParent = this; _imagesStripPanel.Show(); } string _saveErrorDirectory = null; void ProcessResult(bool result) { if (_statisticsDialog != null) { if (_statisticsDialog.cbExpectedMode.Checked) { _statisticsDialog.AddExpected((_imagesStripPanel as ImageStripPanel).GetImagePath(), _visionStepsPanel.WorkflowList.Operations.Where(x => x.Result == false).Select(x => x.Label) .ToArray()); } else { if (result) { _statisticsDialog.AddGoodImage((_imagesStripPanel as ImageStripPanel).GetImagePath()); } else { _statisticsDialog.AddBadImage((_imagesStripPanel as ImageStripPanel).GetImagePath(), _visionStepsPanel.WorkflowList.Operations.Where(x => x.Result == false).Select(x => x.Label).ToArray()); } } } if (!copyOnStopToolStripMenuItem.Checked) return; var shouldSaveOnError = (_imagesStripPanel as ImageStripPanel).StopOnErrors; var shouldSaveOnNoError = (_imagesStripPanel as ImageStripPanel).StopOnNoErrors; if ((!result && shouldSaveOnError) || (result && shouldSaveOnNoError)) { var resultFile = Path.Combine(_saveErrorDirectory, Path.GetFileName((_imagesStripPanel as ImageStripPanel).GetImagePath())); if (!File.Exists(resultFile)) { File.Copy((_imagesStripPanel as ImageStripPanel).GetImagePath(), Path.Combine(_saveErrorDirectory, Path.GetFileName((_imagesStripPanel as ImageStripPanel).GetImagePath()))); } } } protected override void OnShown(EventArgs e) { base.OnShown(e); WindowState= FormWindowState.Maximized; Application.DoEvents(); OrganizeWindows(null, null); _previewPanel.Fit(); } private void OrganizeWindows(object sender, EventArgs e) { _previewPanel.Left = 0; _previewPanel.Top = 0; _previewPanel.Width = this.ClientSize.Width / 2; _previewPanel.Height = (this.ClientSize.Height - 40) - 30 - _imagesStripPanel.Height; _imagesStripPanel.Top = _previewPanel.Height; _imagesStripPanel.Left = 0; _imagesStripPanel.Width = _previewPanel.Width; _toolConfigurationPanel.Top = 0; _toolConfigurationPanel.Left = this.ClientSize.Width / 2; _toolConfigurationPanel.Width = this.ClientSize.Width / 2 - 10; _toolConfigurationPanel.Height = (this.ClientSize.Height - 40) / 2; _visionStepsPanel.Top = (this.ClientSize.Height - 40) / 2; _visionStepsPanel.Left = this.ClientSize.Width / 2; _visionStepsPanel.Width = this.ClientSize.Width / 2 - 10; _visionStepsPanel.Height = (this.ClientSize.Height - 40) / 2 - 30; } private void loadRecipeToolStripMenuItem_Click(object sender, EventArgs e) { OpenFileDialog dialog = new OpenFileDialog(); dialog.Filter = "Suported types|*.jhrcp;*.hrcp"; PrepareDialog(dialog); if (dialog.ShowDialog() == DialogResult.OK) { var path = dialog.FileName; var ext = Path.GetExtension(path); if (ext == ".jhrcp") { LoadRecipeJSON(path); } else if (ext == ".hrcp") { LoadRecipeBinary(path); } else { MessageBox.Show("Unsupported file format. Please use .hrcp or .jhrcp files."); return; } } } private void PrepareDialog(FileDialog dialog) { if (_loadedPath != null) { dialog.InitialDirectory = Path.GetDirectoryName(Path.GetFullPath(_loadedPath)); dialog.FileName = Path.GetFileNameWithoutExtension(_loadedPath); } else { Directory.CreateDirectory(Path.GetFullPath(@"..\Data\Recipes")); dialog.InitialDirectory = Path.GetFullPath(@"..\Data\Recipes"); } } private string _loadedPath = null; public void LoadRecipeBinary(string path) { _loadedPath = path; var bytes = File.ReadAllBytes(path); MemoryStream stream = new MemoryStream(bytes); BinaryReader reader = new BinaryReader(stream); _workflowList.Load(reader, _discoveryService); ReinitCameraPanel(_workflowList); OrganizeWindows(null, null); _visionStepsPanel.RefreshWorkflow(); } public void LoadRecipeJSON(string path) { _loadedPath = path; _workflowList.LoadJSON(path,_discoveryService); ReinitCameraPanel(_workflowList); OrganizeWindows(null, null); _visionStepsPanel.RefreshWorkflow(); } private void _workflowList_PythonMissing() { SetupConfig(); } private void saveRecipeToolStripMenuItem_Click(object sender, EventArgs e) { SaveFileDialog dialog = new SaveFileDialog(); dialog.Filter = "*.jhrcp|*.jhrcp|*.hrcp|*.hrcp"; PrepareDialog(dialog); if (dialog.ShowDialog() == DialogResult.OK) { var ext = Path.GetExtension(dialog.FileName); if (ext == ".jhrcp") { _workflowList.RecipeImage = _workflowList.Context.LastCameraImage?.ImageData; _workflowList.SaveJSON(dialog.FileName); } else { SaveBinary(dialog.FileName); } } } private void SaveBinary(string path) { MemoryStream ms = new MemoryStream(); BinaryWriter bw = new BinaryWriter(ms); _workflowList.RecipeImage = _workflowList.Context.LastCameraImage.ImageData; _workflowList.Save(bw); ms.Close(); File.WriteAllBytes(path, ms.ToArray()); } private void toolBtnConfiguration_Click(object sender, EventArgs e) { SetupConfig(); ReinitCameraPanel(_workflowList); OrganizeWindows(null, null); } private void SetupConfig() { SetupPage.Begin("Camera", "Configuration") .AddItem(_workflowList.Configuration, nameof(_workflowList.Configuration.RuntimeCameraType)) .AddItem(_workflowList.Configuration, nameof(_workflowList.Configuration.DevelopmentCameraType)) .AddItem(_workflowList.Configuration, nameof(_workflowList.Configuration.EmulationPath), editor => editor.FolderPick = true) .Next("Recipe selection") .AddItem(_workflowList.Configuration.RecipeSelectionConfig, nameof(RecipeSelectionConfig.SerialEnabled)) .AddItem(_workflowList.Configuration.RecipeSelectionConfig, nameof(RecipeSelectionConfig.ComPort)) .Next("Outputs") .AddItem(_workflowList.Configuration, nameof(_workflowList.Configuration.Outputs)) .AddItem(_workflowList.Configuration, nameof(_workflowList.Configuration.ResultPin)) .AddItem(_workflowList.Configuration, nameof(_workflowList.Configuration.SerialPort)) .AddItem(_workflowList.Configuration, nameof(_workflowList.Configuration.Delay), editor => editor.Max = 1000) .Next("Python") .AddItem(_workflowList.Configuration, nameof(_workflowList.Configuration.PythonPath), editor => editor.FolderPick = false) .Next("Bad tweak") .AddItem(_workflowList.Configuration.BadTweakLearning, nameof(BadTweakLearning.Enabled)) .AddItem(_workflowList.Configuration.BadTweakLearning, nameof(BadTweakLearning.ThresholdLevel), editor => { editor.Min = 0; editor.Max = 255; }) .Next("Statistics") .ShowSetupDialog(); } private void generateFromColorProfileToolStripMenuItem_Click(object sender, EventArgs e) { var tool = new ColorProfileSelection(_workflowList); tool.ShowDialog(); _visionStepsPanel.RefreshWorkflow(); } private void updateAllToolStripMenuItem_Click(object sender, EventArgs e) { var dialog = new OpenFileDialog(); dialog.Filter = "*.colorprofile|*.colorprofile"; if (dialog.ShowDialog() == DialogResult.OK) { var path = dialog.FileName; var operations = _workflowList.Operations; foreach (var operation in operations) { if (operation is ColorProfileOperation colorProfileOperation) { colorProfileOperation.ColorProfilePath.Path = path; } } } } private void copyPathToolStripMenuItem_Click(object sender, EventArgs e) { if (_imagesStripPanel is not ImageStripPanel panel) return; var imagePath = panel.GetImagePath(); if (imagePath == null) return; Clipboard.SetText(imagePath); } private void copyOnErrorToolStripMenuItem_Click(object sender, EventArgs e) { FolderBrowserDialog dialog = new FolderBrowserDialog(); if (dialog.ShowDialog() == DialogResult.OK) { _saveErrorDirectory = dialog.SelectedPath; return; } copyOnStopToolStripMenuItem.Checked = false; } private void generateFromYoloToolStripMenuItem_Click(object sender, EventArgs e) { // pick yolo file OpenFileDialog dialog = new OpenFileDialog(); dialog.Filter = "*.onnx|*.onnx"; dialog.InitialDirectory = Path.GetFullPath(@"..\Data\Models"); if (dialog.ShowDialog() == DialogResult.OK) { var path = dialog.FileName; var predictor = YoloV8Predictor.Create(path); var classes = predictor.Metadata.Names; foreach (var cls in classes) { { var operation = new YoloPickDetected(); operation.Label = cls.Name; operation.TypeId = cls.Id + 1; _workflowList.Operations.Add(operation); } } _visionStepsPanel.RefreshWorkflow(); } } private void massSetAttributeToolStripMenuItem_Click(object sender, EventArgs e) { AttributeSetter setter = new AttributeSetter(_workflowList); if (setter.ShowDialog() == DialogResult.OK) { _visionStepsPanel.RefreshWorkflow(); } } private string? _saveAsPath = null; private void saveAsToolStripMenuItem_Click(object sender, EventArgs e) { if (_imagesStripPanel is not ImageStripPanel panel) return; var path = GetSaveAsPath(); if (path == null) return; var imagePath = panel.GetImagePath(); if (imagePath == null) return; var bytes = File.ReadAllBytes(imagePath); File.WriteAllBytes(Path.Combine(path, Path.GetFileName(imagePath)), bytes); } string GetSaveAsPath() { if (_saveAsPath == null) { CommonOpenFileDialog dialog = new CommonOpenFileDialog(); dialog.IsFolderPicker = true; if (dialog.ShowDialog() == CommonFileDialogResult.Ok) { _saveAsPath = dialog.FileName; } } return _saveAsPath; } ImageStatisticsDialog _statisticsDialog = null; private void imageStatisticsToolStripMenuItem_Click(object sender, EventArgs e) { if (_statisticsDialog!=null) { return; } _statisticsDialog = new ImageStatisticsDialog(); _statisticsDialog.Show(this); _statisticsDialog.FormClosed += (s, args) => { _statisticsDialog = null; }; _statisticsDialog.FileSelected += _statisticsDialog_FileSelected; } private void _statisticsDialog_FileSelected(string file) { (_imagesStripPanel as ImageStripPanel).SelectImage(file); } } }