check point

This commit is contained in:
meelstorm
2025-07-14 12:03:59 +02:00
commit d3cb790bd9
431 changed files with 44078 additions and 0 deletions

View File

@@ -0,0 +1,125 @@
namespace Hawkeye.VisionBuilder
{
partial class ActionSelector
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.button1 = new System.Windows.Forms.Button();
this.pictureBox2 = new System.Windows.Forms.PictureBox();
this.button2 = new System.Windows.Forms.Button();
this.pictureBox3 = new System.Windows.Forms.PictureBox();
this.button3 = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBox3)).BeginInit();
this.SuspendLayout();
//
// pictureBox1
//
this.pictureBox1.Location = new System.Drawing.Point(24, 24);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(176, 176);
this.pictureBox1.TabIndex = 3;
this.pictureBox1.TabStop = false;
//
// button1
//
this.button1.Location = new System.Drawing.Point(56, 208);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(112, 23);
this.button1.TabIndex = 0;
this.button1.Text = "Select image set";
this.button1.UseVisualStyleBackColor = true;
//
// pictureBox2
//
this.pictureBox2.Location = new System.Drawing.Point(224, 24);
this.pictureBox2.Name = "pictureBox2";
this.pictureBox2.Size = new System.Drawing.Size(176, 176);
this.pictureBox2.TabIndex = 5;
this.pictureBox2.TabStop = false;
//
// button2
//
this.button2.Location = new System.Drawing.Point(256, 208);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(112, 23);
this.button2.TabIndex = 4;
this.button2.Text = "Build recipe";
this.button2.UseVisualStyleBackColor = true;
//
// pictureBox3
//
this.pictureBox3.Location = new System.Drawing.Point(424, 24);
this.pictureBox3.Name = "pictureBox3";
this.pictureBox3.Size = new System.Drawing.Size(176, 176);
this.pictureBox3.TabIndex = 7;
this.pictureBox3.TabStop = false;
//
// button3
//
this.button3.Location = new System.Drawing.Point(456, 208);
this.button3.Name = "button3";
this.button3.Size = new System.Drawing.Size(112, 23);
this.button3.TabIndex = 6;
this.button3.Text = "Specify outputs";
this.button3.UseVisualStyleBackColor = true;
//
// Form2
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(626, 258);
this.Controls.Add(this.pictureBox3);
this.Controls.Add(this.button3);
this.Controls.Add(this.pictureBox2);
this.Controls.Add(this.button2);
this.Controls.Add(this.pictureBox1);
this.Controls.Add(this.button1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "Form2";
this.Text = "Form2";
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBox3)).EndInit();
this.ResumeLayout(false);
}
#endregion
private PictureBox pictureBox1;
private Button button1;
private PictureBox pictureBox2;
private Button button2;
private PictureBox pictureBox3;
private Button button3;
}
}

View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Hawkeye.VisionBuilder
{
public partial class ActionSelector : Form
{
public ActionSelector()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,60 @@
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,86 @@
namespace Hawkeye.VisionBuilder.Features.ColorProgileGenerator
{
partial class ColorProfileSelection
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
listView1 = new ListView();
btnProfilePath = new Button();
button1 = new Button();
SuspendLayout();
//
// listView1
//
listView1.CheckBoxes = true;
listView1.Location = new Point(16, 48);
listView1.Name = "listView1";
listView1.Size = new Size(312, 368);
listView1.TabIndex = 0;
listView1.UseCompatibleStateImageBehavior = false;
listView1.View = View.List;
//
// btnProfilePath
//
btnProfilePath.Location = new Point(16, 8);
btnProfilePath.Name = "btnProfilePath";
btnProfilePath.Size = new Size(312, 23);
btnProfilePath.TabIndex = 1;
btnProfilePath.Text = "Select profile file";
btnProfilePath.UseVisualStyleBackColor = true;
btnProfilePath.Click += btnProfilePath_Click;
//
// button1
//
button1.Location = new Point(248, 424);
button1.Name = "button1";
button1.Size = new Size(75, 23);
button1.TabIndex = 2;
button1.Text = "Generate";
button1.UseVisualStyleBackColor = true;
button1.Click += button1_Click;
//
// ColorProfileSelection
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(348, 463);
Controls.Add(button1);
Controls.Add(btnProfilePath);
Controls.Add(listView1);
FormBorderStyle = FormBorderStyle.FixedToolWindow;
Name = "ColorProfileSelection";
Text = "ColorProfileSelection";
ResumeLayout(false);
}
#endregion
private ListView listView1;
private Button btnProfilePath;
private Button button1;
}
}

View File

@@ -0,0 +1,78 @@
using Hawkeye.VisionBuilder.Workflow.ColorStudioClasses;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Hawkeye.VisionBuilder.Workflow;
using Hawkeye.VisionBuilder.Workflow.Datatypes.Elements.Rectangle;
using Hawkeye.VisionBuilder.Workflow.Operations;
using Hawkeye.VisionBuilder.Workflow.Operations.Filters;
using Hawkeye.VisionBuilder.Workflow.Operations.Memory;
namespace Hawkeye.VisionBuilder.Features.ColorProgileGenerator
{
public partial class ColorProfileSelection : Form
{
private readonly WorkflowList _workflowList;
public ColorProfileSelection(WorkflowList workflowList)
{
_workflowList = workflowList;
InitializeComponent();
}
private void btnProfilePath_Click(object sender, EventArgs e)
{
var dialog = new OpenFileDialog();
dialog.Filter = "Color Profile File (*.colorprofile)|*.colorprofile";
if (dialog.ShowDialog() == DialogResult.OK)
{
btnProfilePath.Text = dialog.FileName;
LoadProfile(dialog.FileName);
}
}
private void LoadProfile(string dialogFileName)
{
var categoryTree = CategoryTree.LoadFromFile(dialogFileName);
var categories = categoryTree.CategoryItems.Select(c => c.Name).ToList();
listView1.Items.Clear();
foreach (var category in categories)
{
listView1.Items.Add(category);
}
}
private void button1_Click(object sender, EventArgs e)
{
var checkedItems= listView1.CheckedItems;
foreach (ListViewItem item in checkedItems)
{
var name = item.Text;
var operation = new ColorProfileOperation();
operation.Category.Value = name;
operation.ColorProfilePath.Path = btnProfilePath.Text;
_workflowList.Operations.Add(operation);
var blobFilter = new FindManyBlobsOperation(_workflowList);
blobFilter.SearchArea = null;
blobFilter.Label = name;
_workflowList.Operations.Add(blobFilter);
var imageFromMemory = new ImageFromMemoryOperation();
_workflowList.Operations.Add(imageFromMemory);
}
Close();
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,7 @@
namespace Hawkeye.VisionBuilder.Features.ImagePreview;
public enum EControlMode
{
Preview,
Creation
}

View File

@@ -0,0 +1,37 @@
namespace Hawkeye.VisionBuilder.Features.ImagePreview
{
partial class ImagePreviewControl
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
}
#endregion
}
}

View File

@@ -0,0 +1,329 @@
using System.Drawing;
using System.Drawing.Drawing2D;
using Hawkeye.VisionBuilder.Workflow;
using Hawkeye.VisionBuilder.Workflow.Datatypes;
using Hawkeye.VisionBuilder.Workflow.Datatypes.Elements;
using Hawkeye.VisionBuilder.Workflow.Datatypes.Elements.Origin;
using Hawkeye.VisionBuilder.Workflow.Datatypes.Elements.Poly;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using Point = System.Drawing.Point;
using PointF = System.Drawing.PointF;
using Matrix = Hawkeye.VisionBuilder.Workflow.Matrix;
using Vector2 = Hawkeye.VisionBuilder.Workflow.Vector2;
namespace Hawkeye.VisionBuilder.Features.ImagePreview
{
public partial class ImagePreviewControl : UserControl,ICanvas
{
private Bitmap _backBuffer;
public List<IGraphicsElement> GraphicsElements { get; set; }=new List<IGraphicsElement>();
public EControlMode Mode { get; set; } = EControlMode.Preview;
public Hawkeye.VisionBuilder.Workflow.Datatypes.HawkeyeImage Image
{
get => _image;
set
{
var needsCentering = _image == null;
_image = value;
if(needsCentering) CenterImage();
}
}
public void CenterImage()
{
TransformationMatrix= Workflow.Matrix.Identity;
var hRatio = Width/ (float)_image.ImageData.Width;
var vRatio = Height / (float) _image.ImageData.Height;
TransformationMatrix*=Matrix.CreateScale(Math.Min(hRatio,vRatio));
var shift = new Vector2(Width,Height)- Vector2.Transform(new Vector2(_image.ImageData.Width, _image.ImageData.Height),
TransformationMatrix);
TransformationMatrix *= Matrix.CreateTranslation(shift.X / 2f, shift.Y / 2f, 0);
}
public ImagePreviewControl()
{
InitializeComponent();
_backBuffer = new Bitmap(Width, Height);
MouseWheel += ZoomPictureBoxWheel_MouseWheel;
DoubleClick += ZoomPictureBoxWheel_DoubleClick;
DoubleBuffered = true;
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
}
private void ZoomPictureBoxWheel_DoubleClick(object sender, EventArgs e)
{
Invalidate();
}
private float _zoom = 1;
private void ZoomPictureBoxWheel_MouseWheel(object sender, MouseEventArgs e)
{
_zoom *= (e.Delta > 0) ? 0.9f : (1f / 0.9f);
TransformationMatrix = TransformationMatrix
* Matrix.CreateTranslation(-_lastMousePosition.X, -_lastMousePosition.Y, 0)
* Matrix.CreateScale((e.Delta > 0) ? 0.9f : (1f / 0.9f))
* Matrix.CreateTranslation(_lastMousePosition.X, _lastMousePosition.Y, 0);
Invalidate();
}
public void FitToScreen()
{
if (Image == null) return;
var width = Image.ImageData.Width;
var height = Image.ImageData.Height;
var aspectRatio = (float)width / height;
var screenAspectRatio = (float)Width / Height;
if (aspectRatio > screenAspectRatio)
{
_zoom = Width / (float)width;
TransformationMatrix = Matrix.Identity;
TransformationMatrix *= Matrix.CreateScale(_zoom);
var shift = new Vector2(Width, Height) - Vector2.Transform(new Vector2(width, height),
TransformationMatrix);
TransformationMatrix *= Matrix.CreateTranslation(shift.X / 2f, shift.Y / 2f, 0);
}
else
{
_zoom = Height / (float)height;
TransformationMatrix = Matrix.Identity;
TransformationMatrix *= Matrix.CreateScale(_zoom);
var shift = new Vector2(Width, Height) - Vector2.Transform(new Vector2(width, height),
TransformationMatrix);
TransformationMatrix *= Matrix.CreateTranslation(shift.X / 2f, shift.Y / 2f, 0);
}
Invalidate();
}
private MouseButtons _mouseButton = MouseButtons.None;
public Matrix TransformationMatrix { get; set; }=Matrix.Identity;
private Vector2 _lastMousePosition;
private const float NODE_SIZE = 10;
protected override void OnMouseDown(MouseEventArgs e)
{
_mouseButton = e.Button;
_lastMousePosition = new Vector2(e.X, e.Y);
var threshold = NODE_SIZE / _zoom ;
var inverted = Matrix.Invert(TransformationMatrix);
var imageCoords = Vector2.Transform(new Vector2(e.X, e.Y), inverted);
_selectedNode=GraphicsElements.Where(x=>x.Editable).Select(x => x.GetNode(imageCoords, threshold)).FirstOrDefault(x => x != null);
}
protected override void OnMouseUp(MouseEventArgs e)
{
_mouseButton = MouseButtons.None;
}
ToolTip _toolTip = new ToolTip();
static bool RectangleContainsPoint(int x, int y, int width, int height, int px, int py)
{
return px >= x && px <= x + width && py >= y && py <= y + height;
}
protected override void OnMouseLeave(EventArgs e)
{
_toolTip.Hide(this);
}
string GetContourInfo(Mat image, int x, int y)
{
var contours = image.FindContoursAsArray(RetrievalModes.List, ContourApproximationModes.ApproxSimple);
var contour = contours.FirstOrDefault(c => Cv2.PointPolygonTest(c, new Point2f(x, y), false) >= 0);
if (contour == null) return "No contour";
var area = Cv2.ContourArea(contour);
var rect = Cv2.BoundingRect(contour);
var width = rect.Width;
var height = rect.Height;
return $"Area: {area}, Width: {width}, Height: {height}";
}
protected override void OnMouseMove(MouseEventArgs e)
{
// if Ctrl is pressed
if ((ModifierKeys & Keys.Control) != 0&&_mouseButton == MouseButtons.None)
{
if(Image==null||Image.ImageData==null) return;
var inverted = Matrix.Invert(TransformationMatrix);
var imageCoords = Vector2.Transform(new Vector2(e.X, e.Y), inverted);
if(!RectangleContainsPoint(0,0,Image.ImageData.Width,Image.ImageData.Height,(int)imageCoords.X,(int)imageCoords.Y)) return;
if (Image.ImageData.Type() == MatType.CV_8UC3)
{
var pixel = Image.ImageData.Get<Vec3b>((int)imageCoords.Y,(int)imageCoords.X);
_toolTip.Show($"R:{pixel.Item0} G:{pixel.Item1} B:{pixel.Item2}", this, e.X + 15, e.Y + 15, 5000);
return;
}
if (Image.ImageData.Type() == MatType.CV_8UC1)
{
var pixel = Image.ImageData.Get<byte>((int)imageCoords.Y,(int)imageCoords.X);
var info= GetContourInfo(Image.ImageData, (int)imageCoords.X, (int)imageCoords.Y);
_toolTip.Show($"Gray:{pixel}\n"+info, this, e.X+15, e.Y+15,5000);
return;
}
return;
}
if (Mode == EControlMode.Preview)
{
if (_mouseButton == MouseButtons.Middle)
{
TransformationMatrix *=
Matrix.CreateTranslation(e.X - _lastMousePosition.X, e.Y - _lastMousePosition.Y, 0);
}
}
_mouseShift = new Vector2(e.X, e.Y) - _lastMousePosition;
if (_mouseButton == MouseButtons.Left&& _selectedNode != null)
{
var inverted = Matrix.Invert(TransformationMatrix);
var transformed = Vector2.Transform(new Vector2(e.X, e.Y), inverted);
_selectedNode.SetPosition(transformed);
}
_lastMousePosition = new Vector2(e.X, e.Y);
Invalidate();
}
private Graphics _currentGraphics;
private Workflow.Datatypes.HawkeyeImage? _image;
private Vector2 _mouseShift;
private INode _selectedNode;
protected override void OnPaint(PaintEventArgs pe)
{
if (Image == null)
{
pe.Graphics.Clear(Color.Black);
return;
}
try
{
using (Graphics g = Graphics.FromImage(_backBuffer))
{
_currentGraphics = g;
g.Clear(Color.Black);
var img = Image.ImageData.ToBitmap();
var pos = Vector2.Transform(new Vector2(0, 0), TransformationMatrix);
var size = Vector2.Transform(new Vector2(img.Width, img.Height), TransformationMatrix);
g.DrawImage(img, pos.X, pos.Y, size.X - pos.X, size.Y - pos.Y);
foreach (IGraphicsElement element in GraphicsElements)
{
element.Draw(this);
}
}
pe.Graphics.DrawImage(_backBuffer, 0, 0);
}
catch
{
}
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
//base.OnPaintBackground(pevent);
}
protected override void OnResize(EventArgs e)
{
if (Width == 0) return;
_backBuffer = new Bitmap(Width, Height);
}
public void DrawNode(Vector2 location)
{
var imageCoordSpace = Vector2.Transform(location, TransformationMatrix);
var start = imageCoordSpace - new Vector2(NODE_SIZE/2, NODE_SIZE / 2);
var end = (imageCoordSpace + new Vector2(NODE_SIZE / 2, NODE_SIZE / 2))-start;
_currentGraphics.FillRectangle(Brushes.White,start.X,start.Y,end.X,end.Y);
_currentGraphics.DrawRectangle(Pens.Black,start.X,start.Y,end.X,end.Y);
}
public void DrawArrow(Vector2 location, Vector2 direction)
{
var imageCoordSpaceLocation = Vector2.Transform(location, TransformationMatrix);
var imageCoordSpaceSize = Vector2.Transform(location + direction, TransformationMatrix);
var arrowPen = new Pen(Color.Aqua, 2);
arrowPen.EndCap = LineCap.Custom;
arrowPen.CustomEndCap = new AdjustableArrowCap(5,5,true);
_currentGraphics.DrawLine(arrowPen, imageCoordSpaceLocation.X, imageCoordSpaceLocation.Y, imageCoordSpaceSize.X, imageCoordSpaceSize.Y);
}
public void DrawRectangle(Vector2 start, Vector2 size, bool isGood)
{
var imageCoordSpaceLocation = Vector2.Transform(start, TransformationMatrix);
var imageCoordSpaceSize = Vector2.Transform(start+size, TransformationMatrix)-imageCoordSpaceLocation;
var pen = new Pen(isGood ? Color.Green : Color.Red, 2);
_currentGraphics.DrawRectangle(pen, imageCoordSpaceLocation.X, imageCoordSpaceLocation.Y, imageCoordSpaceSize.X, imageCoordSpaceSize.Y);
}
public void DrawLine(Vector2 start, Vector2 end,LineType type)
{
var coordStart = Vector2.Transform(start, TransformationMatrix);
var coordEnd = Vector2.Transform(end, TransformationMatrix);
var pen = new Pen(type ==LineType.Good? Color.Green:(type==LineType.Bad? Color.Red:Color.Aqua),2);
_currentGraphics.DrawLine(pen,coordStart.X,coordStart.Y,coordEnd.X,coordEnd.Y);
}
public void DrawPoly(Vector2[] points, bool isGood)
{
var pen = new Pen(isGood ? Color.Green : Color.Red, 3);
var coords = points.Select(x=> Vector2.Transform(x, TransformationMatrix)).Select(x => new PointF(x.X, x.Y)).ToArray();
_currentGraphics.DrawPolygon(pen, coords);
}
public void DrawCross(Vector2 location)
{
var startH=Vector2.Transform(location-new Vector2(10,0),TransformationMatrix);
var endH = Vector2.Transform(location+new Vector2(10,0), TransformationMatrix);
var startV =Vector2.Transform(location-new Vector2(0,20), TransformationMatrix);
var endV =Vector2.Transform(location+new Vector2(0,20), TransformationMatrix);
var pen = new Pen(Color.Aqua, 1);
_currentGraphics.DrawLine(pen, startH.X, startH.Y, endH.X, endH.Y);
_currentGraphics.DrawLine(pen, startV.X, startV.Y, endV.X, endV.Y);
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,77 @@
namespace Hawkeye.VisionBuilder.Features.ImagePreview
{
partial class ImagePreviewPanel
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ImagePreviewPanel));
toolStrip1 = new ToolStrip();
btnFit = new ToolStripButton();
toolStrip1.SuspendLayout();
SuspendLayout();
//
// toolStrip1
//
toolStrip1.Items.AddRange(new ToolStripItem[] { btnFit });
toolStrip1.Location = new Point(0, 0);
toolStrip1.Name = "toolStrip1";
toolStrip1.Size = new Size(800, 25);
toolStrip1.TabIndex = 0;
toolStrip1.Text = "toolStrip1";
//
// btnFit
//
btnFit.DisplayStyle = ToolStripItemDisplayStyle.Text;
btnFit.Image = (Image)resources.GetObject("btnFit.Image");
btnFit.ImageTransparentColor = Color.Magenta;
btnFit.Name = "btnFit";
btnFit.Size = new Size(24, 22);
btnFit.Text = "Fit";
btnFit.Click += btnFit_Click;
//
// ImagePreviewPanel
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(800, 450);
Controls.Add(toolStrip1);
DoubleBuffered = true;
Name = "ImagePreviewPanel";
Text = "Image Preview";
toolStrip1.ResumeLayout(false);
toolStrip1.PerformLayout();
ResumeLayout(false);
PerformLayout();
}
#endregion
private ImagePreviewControl imagePreviewControl;
private ToolStrip toolStrip1;
private ToolStripButton btnFit;
}
}

View File

@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Hawkeye.VisionBuilder.Panels;
using Hawkeye.VisionBuilder.Workflow.Datatypes;
using Hawkeye.VisionBuilder.Workflow.Datatypes.Elements;
namespace Hawkeye.VisionBuilder.Features.ImagePreview
{
public partial class ImagePreviewPanel : BasePannel
{
public ImagePreviewPanel()
{
InitializeComponent();
imagePreviewControl = new ImagePreviewControl()
{
Dock = DockStyle.Fill
};
this.Controls.Add(imagePreviewControl);
imagePreviewControl.BringToFront();
}
public Workflow.Datatypes.HawkeyeImage CurrentImage { get; set; }
public void SetImage(Workflow.Datatypes.HawkeyeImage image)
{
if (image == null) return;
imagePreviewControl.Image = image;
CurrentImage = image;
imagePreviewControl.Invalidate();
}
public void ClearGraphics()
{
imagePreviewControl.GraphicsElements.Clear();
}
public void AddGraphics(IGraphicsElement element)
{
imagePreviewControl.GraphicsElements.Add(element);
}
private void btnFit_Click(object sender, EventArgs e)
{
imagePreviewControl.FitToScreen();
}
}
}

View File

@@ -0,0 +1,133 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="btnFit.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACRSURBVDhPY/j27dt/SjDYACcnJ7IwigEf3n8kCZNswPNb
J/+f6DYF0yA+yQac6Db5f6hWCmwIiE+mC0wIu2DS2Vf/F1x6DefjwlgNyNr34r/0wkdgTMgQDAOQNRNj
CIoBOg0rMTTDMLIhIHbriZeYBmDTiIxBGkEYxge5liQDsGGQqykyAISpZwAlmIEywMAAAAc1/Jwvt6sN
AAAAAElFTkSuQmCC
</value>
</data>
</root>

View File

@@ -0,0 +1,96 @@
namespace Hawkeye.VisionBuilder.Features.ImageStatistics
{
partial class ImageStatisticsDialog
{
private System.ComponentModel.IContainer components = null;
private System.Windows.Forms.TreeView treeView;
private System.Windows.Forms.Button btnReset;
private System.Windows.Forms.Button btnClose;
private System.Windows.Forms.Button btnBackward;
private System.Windows.Forms.Button btnForward;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
this.treeView = new System.Windows.Forms.TreeView();
this.btnReset = new System.Windows.Forms.Button();
this.btnClose = new System.Windows.Forms.Button();
this.btnBackward = new System.Windows.Forms.Button();
this.btnForward = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// treeView
//
this.treeView.Location = new System.Drawing.Point(12, 12);
this.treeView.Name = "treeView";
this.treeView.Size = new System.Drawing.Size(360, 300);
this.treeView.TabIndex = 0;
this.treeView.NodeMouseClick += new System.Windows.Forms.TreeNodeMouseClickEventHandler(this.treeView_NodeMouseClick);
//
// btnReset
//
this.btnReset.Location = new System.Drawing.Point(12, 320);
this.btnReset.Name = "btnReset";
this.btnReset.Size = new System.Drawing.Size(75, 30);
this.btnReset.TabIndex = 1;
this.btnReset.Text = "Reset";
this.btnReset.UseVisualStyleBackColor = true;
this.btnReset.Click += new System.EventHandler(this.btnReset_Click);
//
// btnClose
//
this.btnClose.Location = new System.Drawing.Point(297, 320);
this.btnClose.Name = "btnClose";
this.btnClose.Size = new System.Drawing.Size(75, 30);
this.btnClose.TabIndex = 2;
this.btnClose.Text = "Close";
this.btnClose.UseVisualStyleBackColor = true;
this.btnClose.Click += new System.EventHandler(this.btnClose_Click);
//
// btnBackward
//
this.btnBackward.Location = new System.Drawing.Point(100, 320);
this.btnBackward.Name = "btnBackward";
this.btnBackward.Size = new System.Drawing.Size(75, 30);
this.btnBackward.TabIndex = 3;
this.btnBackward.Text = "<";
this.btnBackward.UseVisualStyleBackColor = true;
this.btnBackward.Click += new System.EventHandler(this.btnBackward_Click);
//
// btnForward
//
this.btnForward.Location = new System.Drawing.Point(190, 320);
this.btnForward.Name = "btnForward";
this.btnForward.Size = new System.Drawing.Size(75, 30);
this.btnForward.TabIndex = 4;
this.btnForward.Text = ">";
this.btnForward.UseVisualStyleBackColor = true;
this.btnForward.Click += new System.EventHandler(this.btnForward_Click);
//
// ImageStatisticsDialog
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(384, 361);
this.Controls.Add(this.btnForward);
this.Controls.Add(this.btnBackward);
this.Controls.Add(this.btnClose);
this.Controls.Add(this.btnReset);
this.Controls.Add(this.treeView);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "ImageStatisticsDialog";
this.Text = "Image Statistics";
this.ResumeLayout(false);
}
}
}

View File

@@ -0,0 +1,194 @@
using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Linq;
namespace Hawkeye.VisionBuilder.Features.ImageStatistics
{
public partial class ImageStatisticsDialog : Form
{
private TreeNode _goodNode;
private TreeNode _badNode;
private HashSet<string> _allFiles = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
private TreeNode? _selectedLeafNode = null;
private Dictionary<string, int> _badDefectCounts = new(StringComparer.OrdinalIgnoreCase);
public event Action<string>? FileSelected;
public ImageStatisticsDialog()
{
InitializeComponent();
InitializeTree();
treeView.AfterSelect += treeView_AfterSelect;
UpdateNavigationButtons();
}
private void InitializeTree()
{
treeView.Nodes.Clear();
_goodNode = new TreeNode(GetBranchText("Good", 0));
_badNode = new TreeNode(GetBranchText("Bad", 0));
treeView.Nodes.Add(_goodNode);
treeView.Nodes.Add(_badNode);
treeView.ExpandAll();
_allFiles.Clear();
_badDefectCounts.Clear();
}
public void AddGoodImage(string filePath)
{
if (_allFiles.Contains(filePath))
return;
string nodeText = System.IO.Path.GetFileName(filePath);
_goodNode.Nodes.Add(new TreeNode(nodeText) { Tag = filePath });
_allFiles.Add(filePath);
UpdateBranchText(_goodNode, "Good");
treeView.ExpandAll();
}
public void AddBadImage(string filePath, string[]? defects = null)
{
if (_allFiles.Contains(filePath))
return;
string nodeText = System.IO.Path.GetFileName(filePath);
if (defects != null && defects.Length > 0)
{
nodeText += " (" + string.Join(", ", defects) + ")";
foreach (var defect in defects)
{
if (string.IsNullOrWhiteSpace(defect)) continue;
if (_badDefectCounts.ContainsKey(defect))
_badDefectCounts[defect]++;
else
_badDefectCounts[defect] = 1;
}
}
_badNode.Nodes.Add(new TreeNode(nodeText) { Tag = filePath });
_allFiles.Add(filePath);
UpdateBranchText(_badNode, "Bad");
treeView.ExpandAll();
}
private void UpdateBranchText(TreeNode node, string name)
{
if (node == _badNode)
{
node.Text = GetBranchText(name, node.Nodes.Count);
}
else
{
node.Text = GetBranchText(name, node.Nodes.Count);
}
}
private string GetBranchText(string name, int count)
{
if (name == "Bad")
{
if (_badDefectCounts.Count > 0)
{
var defectSummary = string.Join(", ",
_badDefectCounts
.OrderByDescending(kv => kv.Value)
.ThenBy(kv => kv.Key)
.Select(kv => $"{kv.Key} {kv.Value}")
);
return $"{name} ({defectSummary})";
}
}
return $"{name} ({count})";
}
private void btnReset_Click(object sender, EventArgs e)
{
InitializeTree();
_badDefectCounts.Clear();
}
private void btnClose_Click(object sender, EventArgs e)
{
this.Close();
}
private void treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
// Only fire event for leaf nodes (filenames)
if (e.Node.Parent != null && e.Node.Tag is string filePath)
{
_selectedLeafNode = e.Node;
FileSelected?.Invoke(filePath);
}
else
{
_selectedLeafNode = null;
}
UpdateNavigationButtons();
}
private void treeView_AfterSelect(object? sender, TreeViewEventArgs e)
{
// Only consider leaf nodes (filenames)
if (e.Node.Parent != null && e.Node.Tag is string)
{
_selectedLeafNode = e.Node;
}
else
{
_selectedLeafNode = null;
}
UpdateNavigationButtons();
}
private void UpdateNavigationButtons()
{
if (_selectedLeafNode == null)
{
btnBackward.Enabled = false;
btnForward.Enabled = false;
return;
}
var parent = _selectedLeafNode.Parent;
if (parent == null)
{
btnBackward.Enabled = false;
btnForward.Enabled = false;
return;
}
int idx = parent.Nodes.IndexOf(_selectedLeafNode);
btnBackward.Enabled = idx > 0;
btnForward.Enabled = idx < parent.Nodes.Count - 1;
}
private void btnBackward_Click(object sender, EventArgs e)
{
if (_selectedLeafNode == null) return;
var parent = _selectedLeafNode.Parent;
if (parent == null) return;
int idx = parent.Nodes.IndexOf(_selectedLeafNode);
if (idx > 0)
{
var prev = parent.Nodes[idx - 1];
treeView.SelectedNode = prev;
treeView.Focus();
if (prev.Tag is string filePath)
FileSelected?.Invoke(filePath);
}
}
private void btnForward_Click(object sender, EventArgs e)
{
if (_selectedLeafNode == null) return;
var parent = _selectedLeafNode.Parent;
if (parent == null) return;
int idx = parent.Nodes.IndexOf(_selectedLeafNode);
if (idx < parent.Nodes.Count - 1)
{
var next = parent.Nodes[idx + 1];
treeView.SelectedNode = next;
treeView.Focus();
if (next.Tag is string filePath)
FileSelected?.Invoke(filePath);
}
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,221 @@
namespace Hawkeye.VisionBuilder.Features.ImagesStrip
{
partial class ImageStripPanel
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ImageStripPanel));
toolStrip1 = new ToolStrip();
lblSelectedImage = new ToolStripLabel();
btnToStart = new ToolStripButton();
btnPrev = new ToolStripButton();
btnPlay = new ToolStripButton();
btnNext = new ToolStripButton();
btnToEnd = new ToolStripButton();
toolStripSeparator1 = new ToolStripSeparator();
cbRepeat = new ToolStripButton();
toolStripLabel1 = new ToolStripLabel();
ncInterval = new ToolStripNumberControl();
ckbExecuteWorkflow = new ToolStripButton();
ckbStopOnError = new ToolStripButton();
ckbStopOnNoError = new ToolStripButton();
listView1 = new ListView();
toolStrip1.SuspendLayout();
SuspendLayout();
//
// toolStrip1
//
toolStrip1.Items.AddRange(new ToolStripItem[] { lblSelectedImage, btnToStart, btnPrev, btnPlay, btnNext, btnToEnd, toolStripSeparator1, cbRepeat, toolStripLabel1, ncInterval, ckbExecuteWorkflow, ckbStopOnError, ckbStopOnNoError });
toolStrip1.Location = new Point(0, 0);
toolStrip1.Name = "toolStrip1";
toolStrip1.Size = new Size(876, 26);
toolStrip1.TabIndex = 0;
toolStrip1.Text = "toolStrip1";
//
// lblSelectedImage
//
lblSelectedImage.Name = "lblSelectedImage";
lblSelectedImage.Size = new Size(32, 23);
lblSelectedImage.Text = "--/--";
//
// btnToStart
//
btnToStart.DisplayStyle = ToolStripItemDisplayStyle.Image;
btnToStart.Image = Resource1.backward_fast;
btnToStart.ImageTransparentColor = Color.Magenta;
btnToStart.Name = "btnToStart";
btnToStart.Size = new Size(23, 23);
btnToStart.Text = "First";
btnToStart.Click += btnToStart_Click;
//
// btnPrev
//
btnPrev.DisplayStyle = ToolStripItemDisplayStyle.Image;
btnPrev.Image = Resource1.backward;
btnPrev.ImageTransparentColor = Color.Magenta;
btnPrev.Name = "btnPrev";
btnPrev.Size = new Size(23, 23);
btnPrev.Text = "Previous";
btnPrev.Click += btnPrev_Click;
//
// btnPlay
//
btnPlay.CheckOnClick = true;
btnPlay.DisplayStyle = ToolStripItemDisplayStyle.Image;
btnPlay.Image = Resource1.play;
btnPlay.ImageTransparentColor = Color.Magenta;
btnPlay.Name = "btnPlay";
btnPlay.Size = new Size(23, 23);
btnPlay.Text = "Play";
btnPlay.Click += btnPlay_Click;
//
// btnNext
//
btnNext.DisplayStyle = ToolStripItemDisplayStyle.Image;
btnNext.Image = Resource1.forward;
btnNext.ImageTransparentColor = Color.Magenta;
btnNext.Name = "btnNext";
btnNext.Size = new Size(23, 23);
btnNext.Text = "Next";
btnNext.Click += btnNext_Click;
//
// btnToEnd
//
btnToEnd.DisplayStyle = ToolStripItemDisplayStyle.Image;
btnToEnd.Image = Resource1.forward_fast;
btnToEnd.ImageTransparentColor = Color.Magenta;
btnToEnd.Name = "btnToEnd";
btnToEnd.Size = new Size(23, 23);
btnToEnd.Text = "Last";
btnToEnd.Click += btnToEnd_Click;
//
// toolStripSeparator1
//
toolStripSeparator1.Name = "toolStripSeparator1";
toolStripSeparator1.Size = new Size(6, 26);
//
// cbRepeat
//
cbRepeat.CheckOnClick = true;
cbRepeat.DisplayStyle = ToolStripItemDisplayStyle.Image;
cbRepeat.Image = Resource1.repeat;
cbRepeat.ImageTransparentColor = Color.Magenta;
cbRepeat.Name = "cbRepeat";
cbRepeat.Size = new Size(23, 23);
cbRepeat.Text = "Repeat";
//
// toolStripLabel1
//
toolStripLabel1.Name = "toolStripLabel1";
toolStripLabel1.Size = new Size(49, 23);
toolStripLabel1.Text = "Interval:";
//
// ncInterval
//
ncInterval.AutoSize = false;
ncInterval.Name = "ncInterval";
ncInterval.Size = new Size(64, 23);
ncInterval.Text = "100";
//
// ckbExecuteWorkflow
//
ckbExecuteWorkflow.CheckOnClick = true;
ckbExecuteWorkflow.DisplayStyle = ToolStripItemDisplayStyle.Text;
ckbExecuteWorkflow.Image = (Image)resources.GetObject("ckbExecuteWorkflow.Image");
ckbExecuteWorkflow.ImageTransparentColor = Color.Magenta;
ckbExecuteWorkflow.Name = "ckbExecuteWorkflow";
ckbExecuteWorkflow.Size = new Size(104, 23);
ckbExecuteWorkflow.Text = "Execute workflow";
//
// ckbStopOnError
//
ckbStopOnError.CheckOnClick = true;
ckbStopOnError.DisplayStyle = ToolStripItemDisplayStyle.Text;
ckbStopOnError.Image = (Image)resources.GetObject("ckbStopOnError.Image");
ckbStopOnError.ImageTransparentColor = Color.Magenta;
ckbStopOnError.Name = "ckbStopOnError";
ckbStopOnError.Size = new Size(80, 23);
ckbStopOnError.Text = "Stop on error";
//
// ckbStopOnNoError
//
ckbStopOnNoError.CheckOnClick = true;
ckbStopOnNoError.DisplayStyle = ToolStripItemDisplayStyle.Text;
ckbStopOnNoError.Image = (Image)resources.GetObject("ckbStopOnNoError.Image");
ckbStopOnNoError.ImageTransparentColor = Color.Magenta;
ckbStopOnNoError.Name = "ckbStopOnNoError";
ckbStopOnNoError.Size = new Size(97, 23);
ckbStopOnNoError.Text = "Stop on no error";
//
// listView1
//
listView1.Alignment = ListViewAlignment.Left;
listView1.Dock = DockStyle.Fill;
listView1.HeaderStyle = ColumnHeaderStyle.None;
listView1.LabelWrap = false;
listView1.Location = new Point(0, 26);
listView1.MultiSelect = false;
listView1.Name = "listView1";
listView1.Size = new Size(876, 171);
listView1.TabIndex = 1;
listView1.UseCompatibleStateImageBehavior = false;
//
// ImageStripPanel
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(876, 197);
Controls.Add(listView1);
Controls.Add(toolStrip1);
MaximizeBox = false;
MinimizeBox = false;
Name = "ImageStripPanel";
toolStrip1.ResumeLayout(false);
toolStrip1.PerformLayout();
ResumeLayout(false);
PerformLayout();
}
#endregion
private ToolStrip toolStrip1;
private ToolStripButton btnToStart;
private ToolStripButton btnPrev;
private ToolStripButton btnPlay;
private ToolStripButton btnNext;
private ToolStripButton btnToEnd;
private ToolStripSeparator toolStripSeparator1;
private ToolStripButton cbRepeat;
private ListView listView1;
private ToolStripLabel toolStripLabel1;
private ToolStripNumberControl ncInterval;
private ToolStripButton ckbExecuteWorkflow;
private ToolStripLabel lblSelectedImage;
private ToolStripButton ckbStopOnError;
private ToolStripButton ckbStopOnNoError;
}
}

View File

@@ -0,0 +1,319 @@
using System.Drawing.Drawing2D;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using VisionBuilder.UI.Common.RecipeProcessing;
using Size = System.Drawing.Size;
namespace Hawkeye.VisionBuilder.Features.ImagesStrip
{
public partial class ImageStripPanel : Form, IImageSource
{
public ImageStripPanel()
{
InitializeComponent();
listView1.SelectedIndexChanged += ListView1_SelectedIndexChanged;
}
private void ListView1_SelectedIndexChanged(object? sender, EventArgs e)
{
if (listView1.SelectedItems.Count > 0)
{
lblSelectedImage.Text = $"{listView1.SelectedIndices[0] + 1}/{listView1.Items.Count}";
var path = (string)listView1.SelectedItems[0].Tag;
listView1.SelectedItems[0].ImageKey = path;
var img = new Mat(path);
var image = new Workflow.Datatypes.HawkeyeImage()
{
Filename = path,
ImageData = img
};
listView1.LargeImageList.Images.RemoveByKey(path);
listView1.LargeImageList.Images.Add(path, img.Resize(new OpenCvSharp.Size(108, 108)).ToBitmap());
ImageSelected(image);
}
}
public bool IsExecutingWorkflow
{
get => ckbExecuteWorkflow.Checked;
set => ckbExecuteWorkflow.Checked = value;
}
public event Action<Workflow.Datatypes.HawkeyeImage> ImageSelected = delegate { };
public void LoadImage(Mat image)
{
ImageList imageList = new ImageList();
imageList.ImageSize = new Size(108, 108);
listView1.LargeImageList = imageList;
listView1.Items.Clear();
imageList.Images.Add("image", image.ToBitmap());
var item = listView1.Items.Add("image");
item.Tag = new Workflow.Datatypes.HawkeyeImage()
{
Filename = "image",
ImageData = image
};
item.Text = "";
item.ImageKey = "image";
listView1.SelectedIndices.Clear();
listView1.SelectedIndices.Add(0);
}
public Bitmap FitImage(Image image, int targetWidth, int targetHeight)
{
var aspectRatio = (float)image.Width / image.Height;
int width;
int height;
if ((float)targetWidth / targetHeight > aspectRatio)
{
width = (int)(targetHeight * aspectRatio);
height = targetHeight;
}
else
{
width = targetWidth;
height = (int)(targetWidth / aspectRatio);
}
Bitmap bitmap = new Bitmap(targetWidth, targetHeight);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.DrawImage(image, new Rectangle(0, 0, width, height));
return bitmap;
}
}
public void LoadImages(string directory)
{
listView1.BeginUpdate();
ImageList imageList = new ImageList();
imageList.ImageSize = new Size(108, 108);
listView1.LargeImageList = imageList;
listView1.Items.Clear();
var mock = new Bitmap(108, 108);
using (Graphics g = Graphics.FromImage(mock))
{
var brush = new HatchBrush(HatchStyle.Percent50, Color.LightGray, Color.Transparent);
g.FillRectangle(brush, 0, 0, 108, 108);
g.DrawString("Not loaded", new Font("Arial", 12), Brushes.Gray, new PointF(0, 0));
}
var allImages = Directory.GetFiles(directory, "*.bmp")
.Concat(Directory.GetFiles(directory, "*.png"))
.Concat(Directory.GetFiles(directory, "*.jpg"))
.Where(x => !Path.GetFileNameWithoutExtension(x).Contains("_analysis"))
//.Select(x=>new {path=x,bmp = new Bitmap(x)})
.Select(x => new { path = x, bmp = mock })
.ToArray();
imageList.Images.Add("none", mock);
foreach (var image in allImages)
{
var item = listView1.Items.Add(image.path);
item.Text = "";
item.Tag = image.path;
item.ImageKey = "none";
}
if (listView1.Items.Count > 0)
{
listView1.SelectedIndices.Clear();
listView1.SelectedIndices.Add(0);
toolStrip1.Enabled = true;
}
else
{
toolStrip1.Enabled = false;
}
listView1.EndUpdate();
}
private void btnToStart_Click(object sender, EventArgs e)
{
listView1.SelectedIndices.Clear();
listView1.SelectedIndices.Add(0);
listView1.EnsureVisible(listView1.SelectedIndices[0]);
}
public void Prev()
{
btnPrev_Click(null, null);
}
private void btnPrev_Click(object sender, EventArgs e)
{
if (listView1.SelectedIndices.Count == 0) return;
var index = listView1.SelectedIndices[0];
index--;
if (index < 0) index++;
listView1.SelectedIndices.Clear();
listView1.SelectedIndices.Add(index);
listView1.EnsureVisible(listView1.SelectedIndices[0]);
}
public void Next()
{
btnNext_Click(null, null);
}
private void btnNext_Click(object sender, EventArgs e)
{
if (listView1.SelectedIndices.Count == 0) return;
var index = listView1.SelectedIndices[0];
index++;
if (index > listView1.Items.Count - 1) index--;
listView1.SelectedIndices.Clear();
listView1.SelectedIndices.Add(index);
listView1.EnsureVisible(listView1.SelectedIndices[0]);
}
private void btnToEnd_Click(object sender, EventArgs e)
{
listView1.SelectedIndices.Clear();
listView1.SelectedIndices.Add(listView1.Items.Count - 1);
listView1.EnsureVisible(listView1.SelectedIndices[0]);
}
private void btnPlay_Click(object sender, EventArgs e)
{
Task.Run(Playback);
}
private async Task Playback()
{
while (btnPlay.Checked)
{
Action a = () =>
{
if (listView1.SelectedIndices.Count == 0) return;
var index = listView1.SelectedIndices[0];
index++;
if (index > listView1.Items.Count - 1)
{
if (cbRepeat.Checked)
{
index = 0;
}
else
{
btnPlay.Checked = false;
return;
}
}
listView1.SelectedIndices.Clear();
listView1.SelectedIndices.Add(index);
listView1.EnsureVisible(listView1.SelectedIndices[0]);
};
listView1.Invoke(a);
await Task.Delay(int.Parse((string)ncInterval.Text));
}
}
public string GetName()
{
return "ImageStripPanel";
}
public Task<Mat> GetImage(CancellationToken token)
{
return Task.FromResult(GetImage());
}
public Mat GetImage()
{
if (listView1.SelectedIndices.Count == 0) return null;
var path = listView1.SelectedItems[0].ImageKey;
return new Mat(path);
}
public string GetImagePath()
{
if (listView1.SelectedIndices.Count == 0) return null;
var path = listView1.SelectedItems[0].Tag as string;
if (path == null) return null;
return path;
}
public bool StopOnErrors
{
get => ckbStopOnError.Checked;
set => ckbStopOnError.Checked = value;
}
public bool StopOnNoErrors
{
get => ckbStopOnNoError.Checked;
set => ckbStopOnNoError.Checked = value;
}
public void InformImageProcessed(bool result)
{
if (!result)
{
if (ckbStopOnError.Checked)
{
btnPlay.Checked = false;
}
}
else
{
if (ckbStopOnNoError.Checked)
{
btnPlay.Checked = false;
}
}
}
public void RemoveImage(Workflow.Datatypes.HawkeyeImage currentImage)
{
if (listView1.SelectedIndices.Count == 0) return;
var index = listView1.SelectedIndices[0];
listView1.Items.RemoveAt(index);
if (listView1.Items.Count > 0)
{
if (index > listView1.Items.Count - 1) index--;
listView1.SelectedIndices.Clear();
listView1.SelectedIndices.Add(index);
listView1.EnsureVisible(listView1.SelectedIndices[0]);
}
}
public List<string> GetFileList()
{
return listView1.Items.Cast<ListViewItem>().Select(x => (string)x.Tag).ToList();
}
public void ReSelect()
{
if(listView1.SelectedIndices.Count == 0) return;
var index = listView1.SelectedIndices[0];
listView1.SelectedIndices.Clear();
listView1.SelectedIndices.Add(index);
listView1.EnsureVisible(listView1.SelectedIndices[0]);
}
public void SelectImage(string nextFile)
{
var index = listView1.Items.Cast<ListViewItem>().Where(x => (string)x.Tag == nextFile).Select(x => x.Index).FirstOrDefault();
if (index == -1) return;
listView1.SelectedIndices.Clear();
listView1.SelectedIndices.Add(index);
listView1.EnsureVisible(listView1.SelectedIndices[0]);
}
}
}

View File

@@ -0,0 +1,151 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="ckbExecuteWorkflow.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACRSURBVDhPY/j27dt/SjDYACcnJ7IwigEf3n8kCZNswPNb
J/+f6DYF0yA+yQac6Db5f6hWCmwIiE+mC0wIu2DS2Vf/F1x6DefjwlgNyNr34r/0wkdgTMgQDAOQNRNj
CIoBOg0rMTTDMLIhIHbriZeYBmDTiIxBGkEYxge5liQDsGGQqykyAISpZwAlmIEywMAAAAc1/Jwvt6sN
AAAAAElFTkSuQmCC
</value>
</data>
<data name="ckbStopOnError.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACRSURBVDhPY/j27dt/SjDYACcnJ7IwigEf3n8kCZNswPNb
J/+f6DYF0yA+yQac6Db5f6hWCmwIiE+mC0wIu2DS2Vf/F1x6DefjwlgNyNr34r/0wkdgTMgQDAOQNRNj
CIoBOg0rMTTDMLIhIHbriZeYBmDTiIxBGkEYxge5liQDsGGQqykyAISpZwAlmIEywMAAAAc1/Jwvt6sN
AAAAAElFTkSuQmCC
</value>
</data>
<data name="ckbStopOnNoError.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACRSURBVDhPY/j27dt/SjDYACcnJ7IwigEf3n8kCZNswPNb
J/+f6DYF0yA+yQac6Db5f6hWCmwIiE+mC0wIu2DS2Vf/F1x6DefjwlgNyNr34r/0wkdgTMgQDAOQNRNj
CIoBOg0rMTTDMLIhIHbriZeYBmDTiIxBGkEYxge5liQDsGGQqykyAISpZwAlmIEywMAAAAc1/Jwvt6sN
AAAAAElFTkSuQmCC
</value>
</data>
</root>

View File

@@ -0,0 +1,133 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Hawkeye.VisionBuilder.Features.ImagesStrip {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resource1 {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resource1() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Hawkeye.VisionBuilder.Features.ImagesStrip.Resource1", typeof(Resource1).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap backward {
get {
object obj = ResourceManager.GetObject("backward", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap backward_fast {
get {
object obj = ResourceManager.GetObject("backward-fast", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap forward {
get {
object obj = ResourceManager.GetObject("forward", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap forward_fast {
get {
object obj = ResourceManager.GetObject("forward-fast", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap pause {
get {
object obj = ResourceManager.GetObject("pause", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap play {
get {
object obj = ResourceManager.GetObject("play", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap repeat {
get {
object obj = ResourceManager.GetObject("repeat", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
}
}

View File

@@ -0,0 +1,142 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="backward" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>images\backward.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="backward-fast" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>images\backward-fast.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="forward" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>images\forward.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="forward-fast" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>images\forward-fast.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="pause" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>images\pause.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="play" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>images\play.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="repeat" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>images\repeat.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

View File

@@ -0,0 +1,41 @@
using System.Windows.Forms.Design;
namespace Hawkeye.VisionBuilder.Features.ImagesStrip;
[ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.ToolStrip)]
public class ToolStripNumberControl : ToolStripControlHost
{
public ToolStripNumberControl()
: base(new NumericUpDown())
{
(Control as NumericUpDown).Maximum = 10000;
(Control as NumericUpDown).Minimum = 0;
}
protected override void OnSubscribeControlEvents(Control control)
{
base.OnSubscribeControlEvents(control);
((NumericUpDown)control).ValueChanged += new EventHandler(OnValueChanged);
}
protected override void OnUnsubscribeControlEvents(Control control)
{
base.OnUnsubscribeControlEvents(control);
((NumericUpDown)control).ValueChanged -= new EventHandler(OnValueChanged);
}
public event EventHandler ValueChanged;
public Control NumericUpDownControl
{
get { return Control as NumericUpDown; }
}
public void OnValueChanged(object sender, EventArgs e)
{
if (ValueChanged != null)
{
ValueChanged(this, e);
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@@ -0,0 +1,145 @@
using System.Runtime.InteropServices;
namespace Hawkeye.VisionBuilder.Features.ToolEditor
{
public class CodeCompletionControl : ListBox
{
private TextBox textBox;
private readonly Form _form;
[DllImport("user32.dll")]
static extern bool GetCaretPos(out Point lpPoint);
public CodeCompletionControl(TextBox textBox)
{
this.textBox = textBox;
this.Visible = false;
this.Location = new Point(0, 0);
this.Width = 200;
_form = new Form();
_form.Width = this.Width;
_form.Height = 200;
_form.Controls.Add(this);
this.Dock = DockStyle.Fill;
_form.FormBorderStyle = FormBorderStyle.None;
_form.ShowInTaskbar = false;
_form.TopMost = true;
_form.StartPosition = FormStartPosition.Manual;
textBox.TextChanged += TextBox_TextChanged;
textBox.KeyDown += TextBox_KeyDown;
this.KeyDown += CodeCompletionControl_KeyDown;
}
private void CodeCompletionControl_KeyDown(object? sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Up)
{
if (this.SelectedIndex == 0)
{
textBox.Focus();
}
}
else if (e.KeyCode == Keys.Enter && this.Visible && this.SelectedIndex != -1)
{
Accept();
}else if (e.KeyCode == Keys.Escape)
{
this.Visible = false;
_form.Hide();
}
}
private void Cancel()
{
this.Visible = false;
_form.Hide();
}
private void Accept()
{
var start = textBox.Text.LastIndexOf(".");
if (start == -1)
{
textBox.Text = this.SelectedItem.ToString();
textBox.SelectionStart = textBox.Text.Length;
this.Visible = false;
_form.Hide();
return;
}
textBox.Text = textBox.Text.Substring(0,start+1);
textBox.Text += this.SelectedItem.ToString();
textBox.SelectionStart = textBox.Text.Length;
this.Visible = false;
_form.Hide();
}
private void TextBox_TextChanged(object sender, EventArgs e)
{
if(int.TryParse(textBox.Text,out _))return;
if (GetCaretPos(out Point point))
{
// Convert screen position to client position
// Set location of this control
_form.Location = textBox.PointToScreen(new Point(point.X, point.Y + textBox.Size.Height)); ; // Add offset to avoid overlap with text cursor
}
// Update suggestions
var suggestions = GetSuggestions(textBox.Text);
this.Items.Clear();
this.Items.AddRange(suggestions.ToArray());
if (this.Items.Count > 0)
{
_form.Show();
textBox.Focus();
}
else
{
_form.Hide();
}
this.Visible = this.Items.Count > 0;
}
private void TextBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Down && this.Visible)
{
this.Focus();
this.SelectedIndex = 0;
}
else if (e.KeyCode == Keys.Escape)
{
Cancel();
}
else if (e.KeyCode == Keys.Enter && this.Visible && this.SelectedIndex != -1)
{
Accept();
}
}
public delegate void NeedSugestionsDelegate(string input, List<string> suggestions);
public event NeedSugestionsDelegate NeedSugestions =delegate{ };
private List<string> GetSuggestions(string input)
{
var source = new List<string>();
NeedSugestions(input, source);
if (source.Count == 0)
{
Visible = false;
_form.Hide();
}
return source.ToList();
}
}
}

View File

@@ -0,0 +1,130 @@
namespace Hawkeye.VisionBuilder.Features.ToolEditor
{
partial class ToolConfigurationPanel
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
this.panel1 = new System.Windows.Forms.Panel();
this.panel2 = new System.Windows.Forms.Panel();
this.btnOk = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button();
this.cbAutoApply = new System.Windows.Forms.CheckBox();
this.panel1.SuspendLayout();
this.panel2.SuspendLayout();
this.SuspendLayout();
//
// flowLayoutPanel1
//
this.flowLayoutPanel1.AutoScroll = true;
this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.flowLayoutPanel1.FlowDirection = System.Windows.Forms.FlowDirection.TopDown;
this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.flowLayoutPanel1.Name = "flowLayoutPanel1";
this.flowLayoutPanel1.Size = new System.Drawing.Size(800, 392);
this.flowLayoutPanel1.TabIndex = 0;
this.flowLayoutPanel1.WrapContents = false;
//
// panel1
//
this.panel1.Controls.Add(this.panel2);
this.panel1.Controls.Add(this.cbAutoApply);
this.panel1.Dock = System.Windows.Forms.DockStyle.Bottom;
this.panel1.Location = new System.Drawing.Point(0, 392);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(800, 58);
this.panel1.TabIndex = 1;
//
// panel2
//
this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.panel2.Controls.Add(this.btnOk);
this.panel2.Controls.Add(this.btnCancel);
this.panel2.Enabled = false;
this.panel2.Location = new System.Drawing.Point(624, 8);
this.panel2.Name = "panel2";
this.panel2.Size = new System.Drawing.Size(168, 40);
this.panel2.TabIndex = 3;
//
// btnOk
//
this.btnOk.Location = new System.Drawing.Point(8, 8);
this.btnOk.Name = "btnOk";
this.btnOk.Size = new System.Drawing.Size(75, 23);
this.btnOk.TabIndex = 0;
this.btnOk.Text = "Apply";
this.btnOk.UseVisualStyleBackColor = true;
this.btnOk.Click += new System.EventHandler(this.btnOk_Click);
//
// btnCancel
//
this.btnCancel.Location = new System.Drawing.Point(88, 8);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(75, 23);
this.btnCancel.TabIndex = 1;
this.btnCancel.Text = "Revert";
this.btnCancel.UseVisualStyleBackColor = true;
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
//
// cbAutoApply
//
this.cbAutoApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.cbAutoApply.AutoSize = true;
this.cbAutoApply.Location = new System.Drawing.Point(528, 16);
this.cbAutoApply.Name = "cbAutoApply";
this.cbAutoApply.Size = new System.Drawing.Size(86, 19);
this.cbAutoApply.TabIndex = 2;
this.cbAutoApply.Text = "Auto-apply";
this.cbAutoApply.UseVisualStyleBackColor = true;
this.cbAutoApply.Visible = false;
//
// ToolConfigurationPanel
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Controls.Add(this.flowLayoutPanel1);
this.Controls.Add(this.panel1);
this.Name = "ToolConfigurationPanel";
this.Text = "Tool Configuration";
this.panel1.ResumeLayout(false);
this.panel1.PerformLayout();
this.panel2.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private FlowLayoutPanel flowLayoutPanel1;
private Panel panel1;
private Button btnCancel;
private Button btnOk;
private CheckBox cbAutoApply;
private Panel panel2;
}
}

View File

@@ -0,0 +1,311 @@
using System.Reflection;
using Hawkeye.VisionBuilder.Features.ImagePreview;
using Hawkeye.VisionBuilder.Features.VisionSteps;
using Hawkeye.VisionBuilder.Panels;
using Hawkeye.VisionBuilder.Workflow;
using Hawkeye.VisionBuilder.Workflow.Datatypes;
using Hawkeye.VisionBuilder.Workflow.Links;
using Hawkeye.VisionBuilder.Workflow.Operations.Attributes;
using Hawkeye.VisionBuilder.Workflow.Operations.Filters;
using Rectangle = Hawkeye.VisionBuilder.Workflow.Datatypes.Elements.Rectangle.RectangleElement;
namespace Hawkeye.VisionBuilder.Features.ToolEditor
{
public partial class ToolConfigurationPanel : BasePannel
{
private readonly WorkflowList _workflowList;
private readonly VisionStepsPanel _visionStepsPanel;
private BaseOperation _selectedOperation;
private Dictionary<string, object> _parameters;
public ToolConfigurationPanel(WorkflowList workflowList,VisionStepsPanel visionStepsPanel)
{
_workflowList = workflowList;
_visionStepsPanel = visionStepsPanel;
InitializeComponent();
}
public void SetOperation(BaseOperation operation)
{
_selectedOperation=operation;
panel2.Enabled=false;
//todo: generate header
var parameters = operation.GetParameters();
_parameters=parameters;
this.flowLayoutPanel1.Controls.Clear();
foreach (var p in parameters)
{
GenerateParameterField(parameters,p.Key, operation);
}
}
private void GenerateParameterField(Dictionary<string, object> toolParameter, string pKey,
BaseOperation operation)
{
var value = toolParameter[pKey];
if (value is int i)
{
var control = new NumericUpDown() { Minimum = -99999999, Maximum = 99999999, Value = i, };
control.TextChanged += (sender, args) =>
{
panel2.Enabled = true;
TriggerChanged();
};
control.ValueChanged += (sender, args) =>
{
toolParameter[pKey] = ((int) control.Value);
panel2.Enabled = true;
TriggerChanged();
};
var row = new ToolConfigurationRow(BaseOperation.MakeOperationName(pKey), control);
row.Width = flowLayoutPanel1.Width - 50;
this.flowLayoutPanel1.Controls.Add(row);
}else if (value is double d)
{
var control = new NumericUpDown() { Minimum = -99999999, Maximum = 99999999, Value = (decimal)d, Increment = (decimal)0.1, DecimalPlaces = 2};
control.TextChanged += (sender, args) =>
{
panel2.Enabled = true;
TriggerChanged();
};
control.ValueChanged += (sender, args) =>
{
toolParameter[pKey] = ((double) control.Value);
panel2.Enabled = true;
TriggerChanged();
};
var row = new ToolConfigurationRow(BaseOperation.MakeOperationName(pKey), control);
row.Width = flowLayoutPanel1.Width - 50;
this.flowLayoutPanel1.Controls.Add(row);
}else if (value is string s)
{
var control = new TextBox() { Text = s };
control.TextChanged += (sender, args) =>
{
toolParameter[pKey] = (control.Text);
panel2.Enabled = true;
TriggerChanged();
};
var row = new ToolConfigurationRow(BaseOperation.MakeOperationName(pKey), control);
row.Width = flowLayoutPanel1.Width - 50;
this.flowLayoutPanel1.Controls.Add(row);
}
else if (value is FilePath filePath)
{
var control = new Button()
{
Text = filePath.Path,
};
control.Click += (sender, args) =>
{
OpenFileDialog dialog = new OpenFileDialog();
dialog.Filter = filePath.Format;
dialog.FileName = filePath.Path;
if (dialog.ShowDialog() == DialogResult.OK)
{
control.Text = dialog.FileName;
filePath.Path = MakeRelative(dialog.FileName,Environment.CurrentDirectory);
control.Text = filePath.Path;
panel2.Enabled = true;
TriggerChanged();
}
};
var row = new ToolConfigurationRow(BaseOperation.MakeOperationName(pKey), control);
row.Width = flowLayoutPanel1.Width - 50;
this.flowLayoutPanel1.Controls.Add(row);
}
else if (value is SelectFromList selectFromList)
{
var control = new ComboBox()
{
DropDownStyle = ComboBoxStyle.DropDownList
};
control.Items.AddRange(selectFromList.GetList().ToArray());
control.SelectedItem = selectFromList.Value;
control.SelectedIndexChanged += (sender, args) =>
{
selectFromList.Value = (control.SelectedItem as string);
panel2.Enabled = true;
TriggerChanged();
};
var row = new ToolConfigurationRow(BaseOperation.MakeOperationName(pKey), control);
row.Width = flowLayoutPanel1.Width - 50;
this.flowLayoutPanel1.Controls.Add(row);
}
else if (value is ScriptValue scriptValue)
{
var control = new TextBox() { Text = scriptValue.Script };
control.TextChanged += (sender, args) =>
{
scriptValue.Script = (control.Text);
panel2.Enabled = true;
TriggerChanged();
};
var row = new ToolConfigurationRow(BaseOperation.MakeOperationName(pKey), control);
row.Width = flowLayoutPanel1.Width - 50;
this.flowLayoutPanel1.Controls.Add(row);
var cc = new CodeCompletionControl(control);
cc.NeedSugestions += Cc_NeedSugestions;
}
else if (value is bool b)
{
var control = new CheckBox() { Checked = b };
control.CheckedChanged += (sender, args) =>
{
toolParameter[pKey] = (control.Checked);
panel2.Enabled = true;
TriggerChanged();
};
var row = new ToolConfigurationRow(BaseOperation.MakeOperationName(pKey), control);
row.Width = flowLayoutPanel1.Width - 50;
this.flowLayoutPanel1.Controls.Add(row);
}
if (value is Guid refId && pKey.StartsWith("Reference"))
{
var control = new ComboBox()
{
DropDownStyle = ComboBoxStyle.DropDownList
};
control.SelectedIndexChanged += (sender, args) =>
{
toolParameter[pKey] = ((control.SelectedItem)as BaseOperation)?.Id??NoOrigin.Instance.Id;
panel2.Enabled = true;
TriggerChanged();
};
var candidates = _workflowList.Operations.TakeWhile(x=> x.Id != operation.Id);
control.Items.Add(NoOrigin.Instance);
if (pKey.Contains("Edge"))
{
control.Items.AddRange(candidates.Where(x => x is IHaveEdge).Select(x => x as IHaveEdge).ToArray());
}
else
{
control.Items.AddRange(candidates.Where(x => x is IHaveOrigin ).Select(x => x as IHaveOrigin).ToArray());
}
control.DisplayMember = nameof(BaseOperation.Label);
control.SelectedItem = candidates.FirstOrDefault(x=>x.Id==refId)?? NoOrigin.Instance;
var row = new ToolConfigurationRow(BaseOperation.MakeOperationName(pKey), control);
row.Width = flowLayoutPanel1.Width - 50;
this.flowLayoutPanel1.Controls.Add(row);
}
else if(value is Action a)
{
var control = new Button()
{
Text = "Execute"
};
control.Click += (sender, args) => a();
var row = new ToolConfigurationRow(BaseOperation.MakeOperationName(pKey), control);
row.Width = flowLayoutPanel1.Width - 50;
this.flowLayoutPanel1.Controls.Add(row);
}
}
private static string MakeRelative(string path, string basePath)
{
var uri = new Uri(path);
var baseUri = new Uri(basePath);
// if path can't be made relative
if (baseUri.Scheme != uri.Scheme)
{
return path;
}
var res= baseUri.MakeRelativeUri(uri).ToString();
// ensure windows path separator
return "..\\"+res.Replace("/", "\\");
}
private void Cc_NeedSugestions(string input, List<string> suggestions)
{
var start = input.IndexOf(".");
if (start == -1)
{
suggestions.AddRange(_workflowList.Operations.Select(x => x.Label).Where(x=>x.StartsWith(input)));
suggestions.Add("config");
return;
}
var word = input.Substring(0, start);
if (word == "config")
{
GenerateSugestions(input.Substring(start + 1), _workflowList.Configuration, suggestions);
return;
}
var o = _workflowList.Operations.FirstOrDefault(x => x.Label == word);
if (o!=null)
{
GenerateSugestions(input.Substring(start + 1), o, suggestions);
}
}
private IEnumerable<PropertyInfo> GetAllowedProperties(Type type)
{
return type.GetProperties().Where(x => x.GetCustomAttribute<NotForToolAttribute>() == null);
}
private void GenerateSugestions(string input, object o, List<string> suggestions)
{
var start = input.IndexOf(".");
if (start == -1)
{
var props = GetAllowedProperties(o.GetType()).Where(x => x.Name.StartsWith(input)).ToList();
props.ForEach(x => suggestions.Add(x.Name));
}
else
{
var word = input.Substring(0, start);
var prop = GetAllowedProperties(o.GetType()).FirstOrDefault(x => x.Name == word);
if (prop != null)
{
GenerateSugestions(input.Substring(start + 1), prop.GetValue(o), suggestions);
}
}
}
private void TriggerChanged()
{
if(cbAutoApply.Checked)
btnOk_Click(null,null);
}
private void btnOk_Click(object sender, EventArgs e)
{
_selectedOperation.SetParameters(_parameters);
SetOperation(_selectedOperation);
_workflowList.ExecuteTill(_selectedOperation);
_workflowList.ExecuteOne(_selectedOperation);
_visionStepsPanel.UpdateView();
}
private void btnCancel_Click(object sender, EventArgs e)
{
SetOperation(_selectedOperation);
}
}
}

View File

@@ -0,0 +1,60 @@
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,73 @@
namespace Hawkeye.VisionBuilder.Features.ToolEditor
{
partial class ToolConfigurationRow
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.panel1 = new System.Windows.Forms.Panel();
this.SuspendLayout();
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(8, 0);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(38, 15);
this.label1.TabIndex = 0;
this.label1.Text = "label1";
//
// panel1
//
this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.panel1.Location = new System.Drawing.Point(128, 0);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(419, 27);
this.panel1.TabIndex = 1;
//
// ToolConfigurationRow
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.panel1);
this.Controls.Add(this.label1);
this.Margin = new System.Windows.Forms.Padding(8);
this.Name = "ToolConfigurationRow";
this.Size = new System.Drawing.Size(543, 27);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private Label label1;
private Panel panel1;
}
}

View File

@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Hawkeye.VisionBuilder.Features.ToolEditor
{
public partial class ToolConfigurationRow : UserControl
{
private readonly Control _input;
public ToolConfigurationRow(string name,Control input)
{
_input = input;
InitializeComponent();
label1.Text = name;
panel1.Controls.Add(input);
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
_input.Width = this.Width - panel1.Left - 15;
}
}
}

View File

@@ -0,0 +1,60 @@
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,191 @@
namespace Hawkeye.VisionBuilder.Features.VisionSteps
{
partial class VisionStepsPanel
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
dataGridView1 = new DataGridView();
panel1 = new Panel();
lblProcessingTime = new Label();
label1 = new Label();
btnTest = new Button();
button1 = new Button();
Indicator = new DataGridViewTextBoxColumn();
Link = new DataGridViewTextBoxColumn();
UserName = new DataGridViewTextBoxColumn();
Result = new DataGridViewTextBoxColumn();
TypeName = new DataGridViewTextBoxColumn();
Time = new DataGridViewTextBoxColumn();
((System.ComponentModel.ISupportInitialize)dataGridView1).BeginInit();
panel1.SuspendLayout();
SuspendLayout();
//
// dataGridView1
//
dataGridView1.AllowDrop = true;
dataGridView1.AllowUserToAddRows = false;
dataGridView1.AllowUserToDeleteRows = false;
dataGridView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
dataGridView1.Columns.AddRange(new DataGridViewColumn[] { Indicator, Link, UserName, Result, TypeName, Time });
dataGridView1.Dock = DockStyle.Fill;
dataGridView1.Location = new Point(0, 40);
dataGridView1.MultiSelect = false;
dataGridView1.Name = "dataGridView1";
dataGridView1.ReadOnly = true;
dataGridView1.RowHeadersVisible = false;
dataGridView1.RowTemplate.Height = 25;
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dataGridView1.Size = new Size(540, 562);
dataGridView1.TabIndex = 0;
dataGridView1.DragDrop += dataGridView1_DragDrop;
dataGridView1.DragOver += dataGridView1_DragOver;
dataGridView1.KeyDown += dataGridView1_KeyDown;
dataGridView1.MouseDown += dataGridView1_MouseDown;
dataGridView1.MouseMove += dataGridView1_MouseMove;
dataGridView1.MouseUp += dataGridView1_MouseUp;
//
// panel1
//
panel1.Controls.Add(lblProcessingTime);
panel1.Controls.Add(label1);
panel1.Controls.Add(btnTest);
panel1.Controls.Add(button1);
panel1.Dock = DockStyle.Top;
panel1.Location = new Point(0, 0);
panel1.Name = "panel1";
panel1.Size = new Size(540, 40);
panel1.TabIndex = 1;
//
// lblProcessingTime
//
lblProcessingTime.AutoSize = true;
lblProcessingTime.Location = new Point(312, 16);
lblProcessingTime.Name = "lblProcessingTime";
lblProcessingTime.Size = new Size(32, 15);
lblProcessingTime.TabIndex = 3;
lblProcessingTime.Text = "0 ms";
//
// label1
//
label1.AutoSize = true;
label1.Location = new Point(216, 16);
label1.Name = "label1";
label1.Size = new Size(94, 15);
label1.TabIndex = 2;
label1.Text = "Processing time:";
//
// btnTest
//
btnTest.Location = new Point(112, 8);
btnTest.Name = "btnTest";
btnTest.Size = new Size(96, 23);
btnTest.TabIndex = 1;
btnTest.Text = "Test run";
btnTest.UseVisualStyleBackColor = true;
btnTest.Click += btnTest_Click;
//
// button1
//
button1.Location = new Point(8, 8);
button1.Name = "button1";
button1.Size = new Size(96, 23);
button1.TabIndex = 0;
button1.Text = "&Add tool";
button1.UseVisualStyleBackColor = true;
button1.Click += button1_Click;
//
// Indicator
//
Indicator.HeaderText = "";
Indicator.MinimumWidth = 20;
Indicator.Name = "Indicator";
Indicator.ReadOnly = true;
Indicator.Width = 32;
//
// Link
//
Link.HeaderText = "";
Link.Name = "Link";
Link.ReadOnly = true;
Link.Width = 32;
//
// UserName
//
UserName.HeaderText = "Label";
UserName.Name = "UserName";
UserName.ReadOnly = true;
//
// Result
//
Result.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
Result.HeaderText = "Result";
Result.Name = "Result";
Result.ReadOnly = true;
//
// TypeName
//
TypeName.HeaderText = "Type";
TypeName.Name = "TypeName";
TypeName.ReadOnly = true;
//
// Time
//
Time.HeaderText = "Time";
Time.Name = "Time";
Time.ReadOnly = true;
//
// VisionStepsPanel
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(540, 602);
Controls.Add(dataGridView1);
Controls.Add(panel1);
Name = "VisionStepsPanel";
Text = "Vision Steps";
((System.ComponentModel.ISupportInitialize)dataGridView1).EndInit();
panel1.ResumeLayout(false);
panel1.PerformLayout();
ResumeLayout(false);
}
#endregion
private DataGridView dataGridView1;
private Panel panel1;
private Button button1;
private Button btnTest;
private Label lblProcessingTime;
private Label label1;
private DataGridViewTextBoxColumn Indicator;
private DataGridViewTextBoxColumn Link;
private DataGridViewTextBoxColumn UserName;
private DataGridViewTextBoxColumn Result;
private DataGridViewTextBoxColumn TypeName;
private DataGridViewTextBoxColumn Time;
}
}

View File

@@ -0,0 +1,355 @@
using System.Diagnostics;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using Hawkeye.VisionBuilder.Features.ImagePreview;
using Hawkeye.VisionBuilder.Panels;
using Hawkeye.VisionBuilder.Workflow;
using Hawkeye.VisionBuilder.Workflow.Datatypes;
using Hawkeye.VisionBuilder.Workflow.Datatypes.Elements;
using Hawkeye.VisionBuilder.Workflow.Links;
using Rectangle = System.Drawing.Rectangle;
namespace Hawkeye.VisionBuilder.Features.VisionSteps
{
public partial class VisionStepsPanel : BasePannel
{
private readonly WorkflowList _workflowList;
private readonly OperationDiscoveryService _discoveryService;
private readonly ImagePreviewPanel _imagePreviewPanel;
private BindingSource _bindingSource = new BindingSource();
public VisionStepsPanel(Workflow.WorkflowList workflowList, OperationDiscoveryService discoveryService,
ImagePreview.ImagePreviewPanel imagePreviewPanel)
{
_workflowList = workflowList;
_discoveryService = discoveryService;
_imagePreviewPanel = imagePreviewPanel;
InitializeComponent();
dataGridView1.AutoGenerateColumns = false;
dataGridView1.DataSource = _bindingSource;
dataGridView1.Columns[0].DataPropertyName = nameof(BaseOperationDecorator.Result);
dataGridView1.Columns[2].DataPropertyName = nameof(BaseOperationDecorator.Label);
dataGridView1.Columns[2].ReadOnly = false;
dataGridView1.ReadOnly = false;
dataGridView1.Columns[3].DataPropertyName = nameof(BaseOperationDecorator.ResultString);
dataGridView1.Columns[4].DataPropertyName = nameof(BaseOperationDecorator.TypeName);
dataGridView1.Columns[5].DataPropertyName = nameof(BaseOperationDecorator.ExecutionTimeString);
dataGridView1.DefaultCellStyle.SelectionBackColor = Color.Bisque;
dataGridView1.DefaultCellStyle.SelectionForeColor = Color.Black;
dataGridView1.CellPainting += DataGridView1_CellPainting;
dataGridView1.SelectionChanged += DataGridView1_SelectionChanged;
RefreshWorkflow();
//dataGridView1.Paint += DataGridView1_Paint;
}
public void RefreshWorkflow()
{
_bindingSource.Clear();
foreach (BaseOperation operation in _workflowList.Operations)
{
_bindingSource.Add(new BaseOperationDecorator(operation));
}
}
public event Action<BaseOperation> OperationSelected = delegate { };
private void DataGridView1_SelectionChanged(object? sender, EventArgs e)
{
}
public void UpdateView()
{
_imagePreviewPanel.ClearGraphics();
_imagePreviewPanel.SetImage(_workflowList.Context.ActiveImage);
_workflowList.Context.GraphicsElements.ForEach(_imagePreviewPanel.AddGraphics);
_imagePreviewPanel.Refresh();
Refresh();
}
private void DataGridView1_Paint(object? sender, PaintEventArgs e)
{
var g = e.Graphics;
var c1 = dataGridView1.GetCellDisplayRectangle(1, 0, true);
var c2 = dataGridView1.GetCellDisplayRectangle(1, 1, true);
Pen start = new Pen(Color.Blue, 2);
Pen body = new Pen(Color.Blue, 2);
Pen end = new Pen(Color.Blue, 2);
end.EndCap = LineCap.Custom;
AdjustableArrowCap bigArrow = new AdjustableArrowCap(5, 5);
end.CustomEndCap = bigArrow;
g.DrawLine(start, c1.Right, (c1.Bottom - c1.Top) / 2 + c1.Top, (c1.Right - c1.Left) / 2 + c1.Left,
(c1.Bottom - c1.Top) / 2 + c1.Top);
g.DrawLine(body, (c1.Right - c1.Left) / 2 + c1.Left, (c1.Bottom - c1.Top) / 2 + c1.Top,
(c2.Right - c2.Left) / 2 + c1.Left, (c2.Bottom - c2.Top) / 2 + c2.Top);
g.DrawLine(end, (c2.Right - c2.Left) / 2 + c2.Left, (c2.Bottom - c2.Top) / 2 + c2.Top, c2.Right,
(c2.Bottom - c2.Top) / 2 + c2.Top);
}
private void DataGridView1_CellPainting(object? sender, DataGridViewCellPaintingEventArgs e)
{
if (e.ColumnIndex == 0 && e.RowIndex > -1 && e.Value != null)
{
var cx = e.CellBounds.Width / 2 + e.CellBounds.Left;
var cy = e.CellBounds.Height / 2 + e.CellBounds.Top;
var radius = e.CellBounds.Height / 2 - 3;
var c1 = dataGridView1.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, true);
e.PaintBackground(c1, true);
if ((bool)e.Value)
{
e.Graphics.FillEllipse(Brushes.Green, cx - radius, cy - radius, radius * 2, radius * 2);
}
else
{
e.Graphics.FillEllipse(Brushes.Red, cx - radius, cy - radius, radius * 2, radius * 2);
}
e.Handled = true;
}
}
private static ToolStripMenuItem EnsureCategory(ToolStripItemCollection collection, string category)
{
var name = category.Split("/", StringSplitOptions.RemoveEmptyEntries);
ToolStripMenuItem currentCategory = null;
foreach (var s in name)
{
if (currentCategory == null)
{
if (!collection.ContainsKey(s))
{
currentCategory = new ToolStripMenuItem()
{
Name = s,
Text = s
};
collection.Add(currentCategory);
}
else
{
currentCategory = collection[s] as ToolStripMenuItem;
}
}
else
{
if (!currentCategory.DropDownItems.ContainsKey(s))
{
var newCategory = new ToolStripMenuItem()
{
Name = s,
Text = s
};
currentCategory.DropDownItems.Add(newCategory);
currentCategory = newCategory;
}
else
{
currentCategory = currentCategory.DropDownItems[s] as ToolStripMenuItem;
}
}
}
return currentCategory!;
}
private void button1_Click(object sender, EventArgs e)
{
var factories = _discoveryService.DiscoverOperations();
var context = new ContextMenuStrip();
foreach (OperationDescription desc in factories)
{
var descCategory = desc.Category;
ToolStripMenuItem currentCategory = EnsureCategory(context.Items, descCategory);
currentCategory.DropDownItems.Add(desc.Name).Click += (o, args) =>
{
var operation = _discoveryService.CreateInstance(desc.Type);
_workflowList.Operations.Add(operation);
int num = 1;
while (_workflowList.Operations.Any(x => x.Label == operation.Label + num)) num++;//generate unique name
operation.Label += "" + num;
_bindingSource.Add(new BaseOperationDecorator(operation));
dataGridView1.ClearSelection();
dataGridView1.Rows[^1].Selected = true;
ProcessRowSelection();
};
}
context.Show(button1, button1.Location);
}
private void btnTest_Click(object sender, EventArgs e)
{
ExecuteWorkflow();
}
public WorkflowList WorkflowList => _workflowList;
public void ExecuteWorkflow()
{
_workflowList.Context = new Context();
var sw = Stopwatch.StartNew();
_workflowList.Operations.ForEach(x => x.NeedsUpdate = true);
_workflowList.Execute();
sw.Stop();
lblProcessingTime.Text = sw.ElapsedMilliseconds.ToString() + " ms";
_imagePreviewPanel.SetImage(_workflowList.Context.ActiveImage);
_imagePreviewPanel.ClearGraphics();
_workflowList.Context.GraphicsElements.ForEach(_imagePreviewPanel.AddGraphics);
Refresh();
}
private void dataGridView1_MouseUp(object sender, MouseEventArgs e)
{
ProcessRowSelection();
}
public BaseOperation? GetSelectedOperation()
{
if (dataGridView1.SelectedRows.Count == 0) return null;
var rowIndex = dataGridView1.SelectedRows[0].Index;
return (_bindingSource[rowIndex] as BaseOperationDecorator)?.Operation;
}
public void ProcessRowSelection()
{
if (dataGridView1.SelectedRows.Count == 0) return;
var rowIndex = dataGridView1.SelectedRows[0].Index;
var x = (_bindingSource[rowIndex] as BaseOperationDecorator);
OperationSelected.Invoke(x.Operation);
_imagePreviewPanel.ClearGraphics();
foreach (BaseOperation operation in _workflowList.Operations)
{
if (operation.NeedsUpdate) _workflowList.ExecuteOne(operation);
if (operation == x.Operation) break;
}
UpdateView();
}
private void dataGridView1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Delete)
{
if (dataGridView1.SelectedRows.Count == 0) return;
var rowIndex = dataGridView1.SelectedRows[0].Index;
_bindingSource.RemoveAt(rowIndex);
_workflowList.Operations.RemoveAt(rowIndex);
if (rowIndex > 0)
{
dataGridView1.ClearSelection();
dataGridView1.Rows[rowIndex - 1].Selected = true;
ProcessRowSelection();
}
}
}
private Rectangle dragBoxFromMouseDown;
private int rowIndexFromMouseDown;
private int rowIndexOfItemUnderMouseToDrop;
private void dataGridView1_MouseMove(object sender, MouseEventArgs e)
{
if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
{
// If the mouse moves outside the rectangle, start the drag.
if (dragBoxFromMouseDown != Rectangle.Empty &&
!dragBoxFromMouseDown.Contains(e.X, e.Y))
{
// Proceed with the drag and drop, passing in the list item.
DragDropEffects dropEffect = dataGridView1.DoDragDrop(
dataGridView1.Rows[rowIndexFromMouseDown],
DragDropEffects.Move);
}
}
}
private void dataGridView1_MouseDown(object sender, MouseEventArgs e)
{
// Get the index of the item the mouse is below.
rowIndexFromMouseDown = dataGridView1.HitTest(e.X, e.Y).RowIndex;
if (rowIndexFromMouseDown != -1)
{
// Remember the point where the mouse down occurred.
// The DragSize indicates the size that the mouse can move
// before a drag event should be started.
Size dragSize = SystemInformation.DragSize;
// Create a rectangle using the DragSize, with the mouse position being
// at the center of the rectangle.
dragBoxFromMouseDown = new Rectangle(new Point(e.X - (dragSize.Width / 2),
e.Y - (dragSize.Height / 2)),
dragSize);
}
else
// Reset the rectangle if the mouse is not over an item in the ListBox.
dragBoxFromMouseDown = Rectangle.Empty;
}
private void dataGridView1_DragOver(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void dataGridView1_DragDrop(object sender, DragEventArgs e)
{
// The mouse locations are relative to the screen, so they must be
// converted to client coordinates.
Point clientPoint = dataGridView1.PointToClient(new Point(e.X, e.Y));
// Get the row index of the item the mouse is below.
rowIndexOfItemUnderMouseToDrop =
dataGridView1.HitTest(clientPoint.X, clientPoint.Y).RowIndex;
var movable = _workflowList.Operations[rowIndexFromMouseDown];
_workflowList.Operations.RemoveAt(rowIndexFromMouseDown);
if (rowIndexOfItemUnderMouseToDrop == -1) rowIndexOfItemUnderMouseToDrop = _workflowList.Operations.Count;
_workflowList.Operations.Insert(rowIndexOfItemUnderMouseToDrop, movable);
dataGridView1.ClearSelection();
RefreshWorkflow();
dataGridView1.Rows[rowIndexOfItemUnderMouseToDrop].Selected = true;
ProcessRowSelection();
}
}
}

View File

@@ -0,0 +1,78 @@
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="Indicator.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="Link.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="UserName.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="Result.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="TypeName.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="Time.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
</root>

View File

@@ -0,0 +1,193 @@
namespace Hawkeye.VisionBuilder.Features.Yolo
{
partial class AttributeSetter
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
label1 = new Label();
tbMinWidth = new TextBox();
tbMaxWidth = new TextBox();
Label2 = new Label();
tbMinHeight = new TextBox();
label3 = new Label();
tbMaxHeight = new TextBox();
label4 = new Label();
tbMinArea = new TextBox();
label5 = new Label();
tbMaxArea = new TextBox();
label6 = new Label();
button1 = new Button();
SuspendLayout();
//
// label1
//
label1.AutoSize = true;
label1.Location = new Point(16, 16);
label1.Name = "label1";
label1.Size = new Size(60, 15);
label1.TabIndex = 0;
label1.Text = "MinWidth";
//
// tbMinWidth
//
tbMinWidth.Location = new Point(88, 16);
tbMinWidth.Name = "tbMinWidth";
tbMinWidth.Size = new Size(100, 23);
tbMinWidth.TabIndex = 1;
//
// tbMaxWidth
//
tbMaxWidth.Location = new Point(88, 48);
tbMaxWidth.Name = "tbMaxWidth";
tbMaxWidth.Size = new Size(100, 23);
tbMaxWidth.TabIndex = 3;
//
// Label2
//
Label2.AutoSize = true;
Label2.Location = new Point(16, 48);
Label2.Name = "Label2";
Label2.Size = new Size(62, 15);
Label2.TabIndex = 2;
Label2.Text = "MaxWidth";
//
// tbMinHeight
//
tbMinHeight.Location = new Point(88, 80);
tbMinHeight.Name = "tbMinHeight";
tbMinHeight.Size = new Size(100, 23);
tbMinHeight.TabIndex = 5;
//
// label3
//
label3.AutoSize = true;
label3.Location = new Point(16, 80);
label3.Name = "label3";
label3.Size = new Size(64, 15);
label3.TabIndex = 4;
label3.Text = "MinHeight";
//
// tbMaxHeight
//
tbMaxHeight.Location = new Point(88, 112);
tbMaxHeight.Name = "tbMaxHeight";
tbMaxHeight.Size = new Size(100, 23);
tbMaxHeight.TabIndex = 7;
//
// label4
//
label4.AutoSize = true;
label4.Location = new Point(16, 112);
label4.Name = "label4";
label4.Size = new Size(66, 15);
label4.TabIndex = 6;
label4.Text = "MaxHeight";
//
// tbMinArea
//
tbMinArea.Location = new Point(88, 144);
tbMinArea.Name = "tbMinArea";
tbMinArea.Size = new Size(100, 23);
tbMinArea.TabIndex = 9;
//
// label5
//
label5.AutoSize = true;
label5.Location = new Point(16, 144);
label5.Name = "label5";
label5.Size = new Size(52, 15);
label5.TabIndex = 8;
label5.Text = "MinArea";
//
// tbMaxArea
//
tbMaxArea.Location = new Point(88, 176);
tbMaxArea.Name = "tbMaxArea";
tbMaxArea.Size = new Size(100, 23);
tbMaxArea.TabIndex = 11;
//
// label6
//
label6.AutoSize = true;
label6.Location = new Point(16, 176);
label6.Name = "label6";
label6.Size = new Size(54, 15);
label6.TabIndex = 10;
label6.Text = "MaxArea";
//
// button1
//
button1.Location = new Point(64, 208);
button1.Name = "button1";
button1.Size = new Size(75, 23);
button1.TabIndex = 12;
button1.Text = "Apply";
button1.UseVisualStyleBackColor = true;
button1.Click += button1_Click;
//
// AttributeSetter
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(216, 247);
Controls.Add(button1);
Controls.Add(tbMaxArea);
Controls.Add(label6);
Controls.Add(tbMinArea);
Controls.Add(label5);
Controls.Add(tbMaxHeight);
Controls.Add(label4);
Controls.Add(tbMinHeight);
Controls.Add(label3);
Controls.Add(tbMaxWidth);
Controls.Add(Label2);
Controls.Add(tbMinWidth);
Controls.Add(label1);
FormBorderStyle = FormBorderStyle.FixedToolWindow;
Name = "AttributeSetter";
Text = "AttributeSetter";
ResumeLayout(false);
PerformLayout();
}
#endregion
private Label label1;
private TextBox tbMinWidth;
private TextBox tbMaxWidth;
private Label Label2;
private TextBox tbMinHeight;
private Label label3;
private TextBox tbMaxHeight;
private Label label4;
private TextBox tbMinArea;
private Label label5;
private TextBox tbMaxArea;
private Label label6;
private Button button1;
}
}

View File

@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Hawkeye.VisionBuilder.Workflow;
namespace Hawkeye.VisionBuilder.Features.Yolo
{
public partial class AttributeSetter : Form
{
private readonly WorkflowList _list;
public AttributeSetter(WorkflowList list)
{
_list = list;
InitializeComponent();
}
void TrySet(TextBox textBox, Action<int> setter)
{
if (int.TryParse(textBox.Text, out var v))
{
setter(v);
}
}
private void button1_Click(object sender, EventArgs e)
{
foreach (var operation in _list.Operations)
{
if (operation is Hawkeye.VisionBuilder.Workflow.Operations.AI.YoloPickDetected yolo)
{
TrySet(tbMinWidth, v => yolo.MinWidth = v);
TrySet(tbMinHeight, v => yolo.MinHeight = v);
TrySet(tbMaxWidth, v => yolo.MaxWidth = v);
TrySet(tbMaxHeight, v => yolo.MaxHeight = v);
TrySet(tbMinArea, v => yolo.MinArea = v);
TrySet(tbMaxArea, v => yolo.MaxArea = v);
}
}
DialogResult = DialogResult.OK;
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,56 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
<Configurations>Debug;Release;CPU</Configurations>
<OutputType>WinExe</OutputType>
</PropertyGroup>
<ItemGroup>
<Folder Include="Localization\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AutoCompleteMenu-ScintillaNET" Version="2.1.0" />
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />
<PackageReference Include="OpenCvSharp4" Version="4.6.0.20220608" />
<PackageReference Include="OpenCvSharp4.Extensions" Version="4.6.0.20220608" />
<PackageReference Include="OpenCvSharp4.runtime.win" Version="4.6.0.20220608" />
<PackageReference Include="Scintilla.NET" Version="5.3.2.7" />
<PackageReference Include="WindowsAPICodePack" Version="8.0.6" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\framework\Inspectron.Camera\Inspectron.Camera.csproj" />
<ProjectReference Include="..\framework\Inspectron.Settings.WindowsWizard\Inspectron.Settings.WindowsWizard.csproj" />
<ProjectReference Include="..\Hawkeye.VisionBuilder.Workflow\Hawkeye.VisionBuilder.Workflow.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="Features\ImagesStrip\Resource1.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resource1.resx</DependentUpon>
</Compile>
<Compile Update="Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Features\ImagesStrip\Resource1.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resource1.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Update="Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,6 @@
namespace Hawkeye.VisionBuilder.Localization;
public interface ILocalizer
{
string Localize(string text);
}

View File

@@ -0,0 +1,9 @@
namespace Hawkeye.VisionBuilder.Localization;
public class NoLocalization:ILocalizer
{
public string Localize(string text)
{
return text;
}
}

View File

@@ -0,0 +1,248 @@
namespace Hawkeye.VisionBuilder
{
partial class MainWindow
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
toolStrip1 = new ToolStrip();
toolStripButton1 = new ToolStripButton();
toolBtnConfiguration = new ToolStripButton();
menuStrip1 = new MenuStrip();
fileToolStripMenuItem = new ToolStripMenuItem();
loadRecipeToolStripMenuItem = new ToolStripMenuItem();
saveRecipeToolStripMenuItem = new ToolStripMenuItem();
editToolStripMenuItem = new ToolStripMenuItem();
copyPathToolStripMenuItem = new ToolStripMenuItem();
copyOnStopToolStripMenuItem = new ToolStripMenuItem();
saveAsToolStripMenuItem = new ToolStripMenuItem();
toolsToolStripMenuItem = new ToolStripMenuItem();
generateFromColorProfileToolStripMenuItem = new ToolStripMenuItem();
colorProfilesToolStripMenuItem = new ToolStripMenuItem();
updateAllToolStripMenuItem = new ToolStripMenuItem();
yoloToolStripMenuItem = new ToolStripMenuItem();
generateFromModelToolStripMenuItem = new ToolStripMenuItem();
massSetAttributeToolStripMenuItem = new ToolStripMenuItem();
windowsToolStripMenuItem = new ToolStripMenuItem();
imageStatisticsToolStripMenuItem = new ToolStripMenuItem();
toolStrip1.SuspendLayout();
menuStrip1.SuspendLayout();
SuspendLayout();
//
// toolStrip1
//
toolStrip1.Items.AddRange(new ToolStripItem[] { toolStripButton1, toolBtnConfiguration });
toolStrip1.Location = new Point(0, 24);
toolStrip1.Name = "toolStrip1";
toolStrip1.Size = new Size(1461, 25);
toolStrip1.TabIndex = 1;
toolStrip1.Text = "toolStrip1";
//
// toolStripButton1
//
toolStripButton1.Image = Resources.grid;
toolStripButton1.ImageTransparentColor = Color.Magenta;
toolStripButton1.Name = "toolStripButton1";
toolStripButton1.Size = new Size(124, 22);
toolStripButton1.Text = "Organize windows";
toolStripButton1.Click += OrganizeWindows;
//
// toolBtnConfiguration
//
toolBtnConfiguration.Image = Resources.diaphragm;
toolBtnConfiguration.ImageTransparentColor = Color.Magenta;
toolBtnConfiguration.Name = "toolBtnConfiguration";
toolBtnConfiguration.Size = new Size(101, 22);
toolBtnConfiguration.Text = "Configuration";
toolBtnConfiguration.Click += toolBtnConfiguration_Click;
//
// menuStrip1
//
menuStrip1.Items.AddRange(new ToolStripItem[] { fileToolStripMenuItem, editToolStripMenuItem, toolsToolStripMenuItem, windowsToolStripMenuItem });
menuStrip1.Location = new Point(0, 0);
menuStrip1.Name = "menuStrip1";
menuStrip1.Size = new Size(1461, 24);
menuStrip1.TabIndex = 3;
menuStrip1.Text = "menuStrip1";
//
// fileToolStripMenuItem
//
fileToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { loadRecipeToolStripMenuItem, saveRecipeToolStripMenuItem });
fileToolStripMenuItem.Name = "fileToolStripMenuItem";
fileToolStripMenuItem.Size = new Size(37, 20);
fileToolStripMenuItem.Text = "File";
//
// loadRecipeToolStripMenuItem
//
loadRecipeToolStripMenuItem.Name = "loadRecipeToolStripMenuItem";
loadRecipeToolStripMenuItem.Size = new Size(135, 22);
loadRecipeToolStripMenuItem.Text = "Load recipe";
loadRecipeToolStripMenuItem.Click += loadRecipeToolStripMenuItem_Click;
//
// saveRecipeToolStripMenuItem
//
saveRecipeToolStripMenuItem.Name = "saveRecipeToolStripMenuItem";
saveRecipeToolStripMenuItem.Size = new Size(135, 22);
saveRecipeToolStripMenuItem.Text = "Save recipe";
saveRecipeToolStripMenuItem.Click += saveRecipeToolStripMenuItem_Click;
//
// editToolStripMenuItem
//
editToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { copyPathToolStripMenuItem, copyOnStopToolStripMenuItem, saveAsToolStripMenuItem });
editToolStripMenuItem.Name = "editToolStripMenuItem";
editToolStripMenuItem.Size = new Size(39, 20);
editToolStripMenuItem.Text = "Edit";
//
// copyPathToolStripMenuItem
//
copyPathToolStripMenuItem.Name = "copyPathToolStripMenuItem";
copyPathToolStripMenuItem.Size = new Size(196, 22);
copyPathToolStripMenuItem.Text = "Copy path";
copyPathToolStripMenuItem.Click += copyPathToolStripMenuItem_Click;
//
// copyOnStopToolStripMenuItem
//
copyOnStopToolStripMenuItem.CheckOnClick = true;
copyOnStopToolStripMenuItem.Name = "copyOnStopToolStripMenuItem";
copyOnStopToolStripMenuItem.Size = new Size(196, 22);
copyOnStopToolStripMenuItem.Text = "Copy on stop";
copyOnStopToolStripMenuItem.Click += copyOnErrorToolStripMenuItem_Click;
//
// saveAsToolStripMenuItem
//
saveAsToolStripMenuItem.Name = "saveAsToolStripMenuItem";
saveAsToolStripMenuItem.ShortcutKeys = Keys.Control | Keys.Shift | Keys.S;
saveAsToolStripMenuItem.Size = new Size(196, 22);
saveAsToolStripMenuItem.Text = "Save as ...";
saveAsToolStripMenuItem.Click += saveAsToolStripMenuItem_Click;
//
// toolsToolStripMenuItem
//
toolsToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { generateFromColorProfileToolStripMenuItem, colorProfilesToolStripMenuItem, yoloToolStripMenuItem });
toolsToolStripMenuItem.Name = "toolsToolStripMenuItem";
toolsToolStripMenuItem.Size = new Size(46, 20);
toolsToolStripMenuItem.Text = "Tools";
//
// generateFromColorProfileToolStripMenuItem
//
generateFromColorProfileToolStripMenuItem.Name = "generateFromColorProfileToolStripMenuItem";
generateFromColorProfileToolStripMenuItem.Size = new Size(217, 22);
generateFromColorProfileToolStripMenuItem.Text = "Generate from color profile";
generateFromColorProfileToolStripMenuItem.Click += generateFromColorProfileToolStripMenuItem_Click;
//
// colorProfilesToolStripMenuItem
//
colorProfilesToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { updateAllToolStripMenuItem });
colorProfilesToolStripMenuItem.Name = "colorProfilesToolStripMenuItem";
colorProfilesToolStripMenuItem.Size = new Size(217, 22);
colorProfilesToolStripMenuItem.Text = "Color profiles";
//
// updateAllToolStripMenuItem
//
updateAllToolStripMenuItem.Name = "updateAllToolStripMenuItem";
updateAllToolStripMenuItem.Size = new Size(127, 22);
updateAllToolStripMenuItem.Text = "Update all";
updateAllToolStripMenuItem.Click += updateAllToolStripMenuItem_Click;
//
// yoloToolStripMenuItem
//
yoloToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { generateFromModelToolStripMenuItem, massSetAttributeToolStripMenuItem });
yoloToolStripMenuItem.Name = "yoloToolStripMenuItem";
yoloToolStripMenuItem.Size = new Size(217, 22);
yoloToolStripMenuItem.Text = "Yolo";
//
// generateFromModelToolStripMenuItem
//
generateFromModelToolStripMenuItem.Name = "generateFromModelToolStripMenuItem";
generateFromModelToolStripMenuItem.Size = new Size(187, 22);
generateFromModelToolStripMenuItem.Text = "Generate from model";
generateFromModelToolStripMenuItem.Click += generateFromYoloToolStripMenuItem_Click;
//
// massSetAttributeToolStripMenuItem
//
massSetAttributeToolStripMenuItem.Name = "massSetAttributeToolStripMenuItem";
massSetAttributeToolStripMenuItem.Size = new Size(187, 22);
massSetAttributeToolStripMenuItem.Text = "Mass set attribute";
massSetAttributeToolStripMenuItem.Click += massSetAttributeToolStripMenuItem_Click;
//
// windowsToolStripMenuItem
//
windowsToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { imageStatisticsToolStripMenuItem });
windowsToolStripMenuItem.Name = "windowsToolStripMenuItem";
windowsToolStripMenuItem.Size = new Size(68, 20);
windowsToolStripMenuItem.Text = "Windows";
//
// imageStatisticsToolStripMenuItem
//
imageStatisticsToolStripMenuItem.Name = "imageStatisticsToolStripMenuItem";
imageStatisticsToolStripMenuItem.Size = new Size(180, 22);
imageStatisticsToolStripMenuItem.Text = "Image statistics";
imageStatisticsToolStripMenuItem.Click += imageStatisticsToolStripMenuItem_Click;
//
// MainWindow
//
AutoScaleDimensions = new SizeF(7F, 15F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(1461, 768);
Controls.Add(toolStrip1);
Controls.Add(menuStrip1);
IsMdiContainer = true;
MainMenuStrip = menuStrip1;
Name = "MainWindow";
StartPosition = FormStartPosition.CenterScreen;
Text = "Hawkeye Vision Builder";
toolStrip1.ResumeLayout(false);
toolStrip1.PerformLayout();
menuStrip1.ResumeLayout(false);
menuStrip1.PerformLayout();
ResumeLayout(false);
PerformLayout();
}
#endregion
private ToolStrip toolStrip1;
private ToolStripButton toolStripButton1;
private MenuStrip menuStrip1;
private ToolStripMenuItem fileToolStripMenuItem;
private ToolStripMenuItem loadRecipeToolStripMenuItem;
private ToolStripMenuItem saveRecipeToolStripMenuItem;
private ToolStripButton toolBtnConfiguration;
private ToolStripMenuItem toolsToolStripMenuItem;
private ToolStripMenuItem generateFromColorProfileToolStripMenuItem;
private ToolStripMenuItem colorProfilesToolStripMenuItem;
private ToolStripMenuItem updateAllToolStripMenuItem;
private ToolStripMenuItem editToolStripMenuItem;
private ToolStripMenuItem copyPathToolStripMenuItem;
private ToolStripMenuItem copyOnStopToolStripMenuItem;
private ToolStripMenuItem yoloToolStripMenuItem;
private ToolStripMenuItem generateFromModelToolStripMenuItem;
private ToolStripMenuItem massSetAttributeToolStripMenuItem;
private ToolStripMenuItem saveAsToolStripMenuItem;
private ToolStripMenuItem windowsToolStripMenuItem;
private ToolStripMenuItem imageStatisticsToolStripMenuItem;
}
}

View File

@@ -0,0 +1,418 @@
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 (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);
OrganizeWindows(null, null);
}
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 = "*.hrcp|*.hrcp";
PrepareDialog(dialog);
if (dialog.ShowDialog() == DialogResult.OK)
{
var path = dialog.FileName;
LoadRecipe(path);
}
}
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 LoadRecipe(string path)
{
_loadedPath = path;
var bytes = File.ReadAllBytes(path);
MemoryStream stream = new MemoryStream(bytes);
BinaryReader reader = new BinaryReader(stream);
_workflowList.PythonMissing += _workflowList_PythonMissing;
_workflowList.Load(reader, _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 = "*.hrcp|*.hrcp";
PrepareDialog(dialog);
if (dialog.ShowDialog() == DialogResult.OK)
{
MemoryStream ms = new MemoryStream();
BinaryWriter bw = new BinaryWriter(ms);
_workflowList.RecipeImage = _workflowList.Context.LastCameraImage.ImageData;
_workflowList.Save(bw);
ms.Close();
File.WriteAllBytes(dialog.FileName, ms.ToArray());
}
}
private void toolBtnConfiguration_Click(object sender, EventArgs e)
{
SetupConfig();
ReinitCameraPanel(_workflowList);
OrganizeWindows(null, null);
}
private void SetupConfig()
{
SetupPage.Begin("Camera", "Configuration")
.AddItem<EnumEditor>(_workflowList.Configuration, nameof(_workflowList.Configuration.RuntimeCameraType))
.AddItem<EnumEditor>(_workflowList.Configuration,
nameof(_workflowList.Configuration.DevelopmentCameraType))
.AddItem<PathEditor>(_workflowList.Configuration, nameof(_workflowList.Configuration.EmulationPath),
editor => editor.FolderPick = true)
.Next("Recipe selection")
.AddItem<CheckEditor>(_workflowList.Configuration.RecipeSelectionConfig, nameof(RecipeSelectionConfig.SerialEnabled))
.AddItem<StringEditor>(_workflowList.Configuration.RecipeSelectionConfig, nameof(RecipeSelectionConfig.ComPort))
.Next("Outputs")
.AddItem<EnumEditor>(_workflowList.Configuration, nameof(_workflowList.Configuration.Outputs))
.AddItem<NumberEditor>(_workflowList.Configuration, nameof(_workflowList.Configuration.ResultPin))
.AddItem<StringEditor>(_workflowList.Configuration, nameof(_workflowList.Configuration.SerialPort))
.AddItem<NumberEditor>(_workflowList.Configuration, nameof(_workflowList.Configuration.Delay), editor => editor.Max = 1000)
.Next("Python")
.AddItem<PathEditor>(_workflowList.Configuration, nameof(_workflowList.Configuration.PythonPath),
editor => editor.FolderPick = false)
.Next("Bad tweak")
.AddItem<CheckEditor>(_workflowList.Configuration.BadTweakLearning, nameof(BadTweakLearning.Enabled))
.AddItem<NumberEditor>(_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);
}
}
}

View File

@@ -0,0 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="menuStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>122, 17</value>
</metadata>
</root>

View File

@@ -0,0 +1,49 @@
namespace Hawkeye.VisionBuilder.Panels
{
partial class BasePannel
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.SuspendLayout();
//
// BasePannel
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.SizableToolWindow;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "BasePannel";
this.Text = "BasePannel";
this.ResumeLayout(false);
}
#endregion
}
}

View File

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Hawkeye.VisionBuilder.Panels
{
public partial class BasePannel : Form
{
public BasePannel()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,60 @@
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,9 @@
using Hawkeye.VisionBuilder.Localization;
namespace Hawkeye.VisionBuilder;
public interface IInitializable
{
void Initialize(ILocalizer localizer);
}

View File

@@ -0,0 +1,43 @@
using System.Globalization;
using Hawkeye.VisionBuilder.Workflow;
using Hawkeye.VisionBuilder.Workflow.Operations;
using Ninject;
namespace Hawkeye.VisionBuilder
{
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
ApplicationConfiguration.Initialize();
WinConsole.Initialize();
ThreadPool.SetMinThreads(64, 4);
Thread.CurrentThread.CurrentCulture=new CultureInfo("en-US");
Thread.CurrentThread.CurrentUICulture=new CultureInfo("en-US");
StandardKernel kernel = new StandardKernel();
WorkflowList workflow = new WorkflowList();
OperationDiscoveryService service = new OperationDiscoveryService(workflow);
workflow.Operations.Add(new GetImageOperation(workflow));
kernel.Bind<OperationDiscoveryService>().ToConstant(service);
kernel.Bind<WorkflowList>().ToConstant(workflow);
Application.Run(kernel.Get<MainWindow>());
}
}
}

View File

@@ -0,0 +1,83 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Hawkeye.VisionBuilder {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Hawkeye.VisionBuilder.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap diaphragm {
get {
object obj = ResourceManager.GetObject("diaphragm", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap grid {
get {
object obj = ResourceManager.GetObject("grid", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
}
}

View File

@@ -0,0 +1,127 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="diaphragm" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>icons\diaphragm.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="grid" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>icons\grid.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

View File

@@ -0,0 +1,6 @@
using System;
namespace Hawkeye.VisionBuilder;
public delegate void UIEventHandler<TControl, TArgs>(TControl? sender, TArgs e)
where TControl : Control where TArgs : EventArgs;

View File

@@ -0,0 +1,118 @@
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
namespace Hawkeye.VisionBuilder
{
public static class WinConsole
{
public static void Initialize(bool alwaysCreateNewConsole = true, bool minimizeWindow = false)
{
bool consoleAttached = true;
if (alwaysCreateNewConsole
|| (AttachConsole(ATTACH_PARRENT) == 0
&& Marshal.GetLastWin32Error() != ERROR_ACCESS_DENIED))
{
consoleAttached = AllocConsole() != 0;
}
if (consoleAttached)
{
InitializeOutStream();
InitializeInStream();
}
if (minimizeWindow)
{
const int SW_MINIMIZE = 6;
var handle = GetConsoleWindow();
ShowWindow(handle, SW_MINIMIZE);
}
}
public static void MinimizeWindow()
{
const int SW_MINIMIZE = 6;
var handle = GetConsoleWindow();
ShowWindow(handle, SW_MINIMIZE);
}
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("kernel32.dll")]
private static extern IntPtr GetConsoleWindow();
private static void InitializeOutStream()
{
var fs = CreateFileStream("CONOUT$", GENERIC_WRITE, FILE_SHARE_WRITE, FileAccess.Write);
if (fs != null)
{
var writer = new StreamWriter(fs) { AutoFlush = true };
Console.SetOut(writer);
Console.SetError(writer);
}
}
private static void InitializeInStream()
{
var fs = CreateFileStream("CONIN$", GENERIC_READ, FILE_SHARE_READ, FileAccess.Read);
if (fs != null)
{
Console.SetIn(new StreamReader(fs));
}
}
private static FileStream CreateFileStream(string name, uint win32DesiredAccess, uint win32ShareMode,
FileAccess dotNetFileAccess)
{
var file = new SafeFileHandle(CreateFileW(name, win32DesiredAccess, win32ShareMode, IntPtr.Zero, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, IntPtr.Zero), true);
if (!file.IsInvalid)
{
var fs = new FileStream(file, dotNetFileAccess);
return fs;
}
return null;
}
#region Win API Functions and Constants
[DllImport("kernel32.dll",
EntryPoint = "AllocConsole",
SetLastError = true,
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern int AllocConsole();
[DllImport("kernel32.dll",
EntryPoint = "AttachConsole",
SetLastError = true,
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern UInt32 AttachConsole(UInt32 dwProcessId);
[DllImport("kernel32.dll",
EntryPoint = "CreateFileW",
SetLastError = true,
CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr CreateFileW(
string lpFileName,
UInt32 dwDesiredAccess,
UInt32 dwShareMode,
IntPtr lpSecurityAttributes,
UInt32 dwCreationDisposition,
UInt32 dwFlagsAndAttributes,
IntPtr hTemplateFile
);
private const UInt32 GENERIC_WRITE = 0x40000000;
private const UInt32 GENERIC_READ = 0x80000000;
private const UInt32 FILE_SHARE_READ = 0x00000001;
private const UInt32 FILE_SHARE_WRITE = 0x00000002;
private const UInt32 OPEN_EXISTING = 0x00000003;
private const UInt32 FILE_ATTRIBUTE_NORMAL = 0x80;
private const UInt32 ERROR_ACCESS_DENIED = 5;
private const UInt32 ATTACH_PARRENT = 0xFFFFFFFF;
#endregion
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 515 B