From 6c0b778ba65eaf1296c997b8827ff21f784fb516 Mon Sep 17 00:00:00 2001 From: meelstorm <8780022+TesAnti@users.noreply.github.com> Date: Thu, 18 Sep 2025 10:50:50 +0200 Subject: [PATCH] finished candybox --- .../Forms/MapEditor.Designer.cs | 124 +++++++- Plugins/CandyboxPlugin/Forms/MapEditor.cs | 49 +++- Plugins/CandyboxPlugin/Forms/MaskControl.cs | 271 ++++++++++++++++-- Plugins/CandyboxPlugin/Recipe/HistoRecipe.cs | 81 ++++-- .../Recipe/LearningParameters.cs | 4 +- .../ViewModel/SingleCameraVM.cs | 13 +- .../SingleCameraControl.Designer.cs | 42 ++- .../Components/SingleCameraControl.cs | 4 + VisionBuilder.UI.Windows/Components/Stats.cs | 2 + 9 files changed, 535 insertions(+), 55 deletions(-) diff --git a/Plugins/CandyboxPlugin/Forms/MapEditor.Designer.cs b/Plugins/CandyboxPlugin/Forms/MapEditor.Designer.cs index 22efc8a..a151410 100644 --- a/Plugins/CandyboxPlugin/Forms/MapEditor.Designer.cs +++ b/Plugins/CandyboxPlugin/Forms/MapEditor.Designer.cs @@ -1,5 +1,4 @@ - -namespace Lindt.Candybox.Demo +namespace Lindt.Candybox.Demo { partial class MapEditor { @@ -35,6 +34,12 @@ namespace Lindt.Candybox.Demo this.materialRaisedButton3 = new MaterialSkin.Controls.MaterialRaisedButton(); this.label1 = new System.Windows.Forms.Label(); this.udMemoryBuffer = new System.Windows.Forms.NumericUpDown(); + this.btnBrush = new MaterialSkin.Controls.MaterialRaisedButton(); + this.btnDrawLine = new MaterialSkin.Controls.MaterialRaisedButton(); + this.btnRemoveLine = new MaterialSkin.Controls.MaterialRaisedButton(); + this.btnMoveLine = new MaterialSkin.Controls.MaterialRaisedButton(); + this.btnMoveVertices = new MaterialSkin.Controls.MaterialRaisedButton(); + this.label2 = new System.Windows.Forms.Label(); ((System.ComponentModel.ISupportInitialize)(this.udMemoryBuffer)).BeginInit(); this.SuspendLayout(); // @@ -54,7 +59,7 @@ namespace Lindt.Candybox.Demo this.materialRaisedButton1.Depth = 0; this.materialRaisedButton1.DrawBorder = true; this.materialRaisedButton1.Icon = null; - this.materialRaisedButton1.Location = new System.Drawing.Point(928, 104); + this.materialRaisedButton1.Location = new System.Drawing.Point(928, 424); this.materialRaisedButton1.MouseState = MaterialSkin.MouseState.HOVER; this.materialRaisedButton1.Name = "materialRaisedButton1"; this.materialRaisedButton1.Primary = false; @@ -71,7 +76,7 @@ namespace Lindt.Candybox.Demo this.materialRaisedButton3.Depth = 0; this.materialRaisedButton3.DrawBorder = true; this.materialRaisedButton3.Icon = null; - this.materialRaisedButton3.Location = new System.Drawing.Point(928, 32); + this.materialRaisedButton3.Location = new System.Drawing.Point(928, 352); this.materialRaisedButton3.MouseState = MaterialSkin.MouseState.HOVER; this.materialRaisedButton3.Name = "materialRaisedButton3"; this.materialRaisedButton3.Primary = true; @@ -85,7 +90,7 @@ namespace Lindt.Candybox.Demo // this.label1.AutoSize = true; this.label1.BackColor = System.Drawing.Color.White; - this.label1.Location = new System.Drawing.Point(928, 184); + this.label1.Location = new System.Drawing.Point(928, 504); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(90, 15); this.label1.TabIndex = 4; @@ -93,16 +98,117 @@ namespace Lindt.Candybox.Demo // // udMemoryBuffer // - this.udMemoryBuffer.Location = new System.Drawing.Point(928, 208); + this.udMemoryBuffer.Location = new System.Drawing.Point(928, 528); this.udMemoryBuffer.Name = "udMemoryBuffer"; this.udMemoryBuffer.Size = new System.Drawing.Size(120, 23); this.udMemoryBuffer.TabIndex = 5; // + // btnBrush + // + this.btnBrush.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.btnBrush.Cursor = System.Windows.Forms.Cursors.Hand; + this.btnBrush.Depth = 0; + this.btnBrush.DrawBorder = true; + this.btnBrush.Icon = null; + this.btnBrush.Location = new System.Drawing.Point(928, 64); + this.btnBrush.MouseState = MaterialSkin.MouseState.HOVER; + this.btnBrush.Name = "btnBrush"; + this.btnBrush.Primary = false; + this.btnBrush.Size = new System.Drawing.Size(128, 32); + this.btnBrush.TabIndex = 6; + this.btnBrush.Text = "Brush"; + this.btnBrush.UseVisualStyleBackColor = true; + this.btnBrush.Click += new System.EventHandler(this.btnBrush_Click); + // + // btnDrawLine + // + this.btnDrawLine.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.btnDrawLine.Cursor = System.Windows.Forms.Cursors.Hand; + this.btnDrawLine.Depth = 0; + this.btnDrawLine.DrawBorder = true; + this.btnDrawLine.Icon = null; + this.btnDrawLine.Location = new System.Drawing.Point(928, 104); + this.btnDrawLine.MouseState = MaterialSkin.MouseState.HOVER; + this.btnDrawLine.Name = "btnDrawLine"; + this.btnDrawLine.Primary = false; + this.btnDrawLine.Size = new System.Drawing.Size(128, 32); + this.btnDrawLine.TabIndex = 7; + this.btnDrawLine.Text = "Draw Line"; + this.btnDrawLine.UseVisualStyleBackColor = true; + this.btnDrawLine.Click += new System.EventHandler(this.btnDrawLine_Click); + // + // btnRemoveLine + // + this.btnRemoveLine.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.btnRemoveLine.Cursor = System.Windows.Forms.Cursors.Hand; + this.btnRemoveLine.Depth = 0; + this.btnRemoveLine.DrawBorder = true; + this.btnRemoveLine.Icon = null; + this.btnRemoveLine.Location = new System.Drawing.Point(928, 144); + this.btnRemoveLine.MouseState = MaterialSkin.MouseState.HOVER; + this.btnRemoveLine.Name = "btnRemoveLine"; + this.btnRemoveLine.Primary = false; + this.btnRemoveLine.Size = new System.Drawing.Size(128, 32); + this.btnRemoveLine.TabIndex = 8; + this.btnRemoveLine.Text = "Remove Line"; + this.btnRemoveLine.UseVisualStyleBackColor = true; + this.btnRemoveLine.Click += new System.EventHandler(this.btnRemoveLine_Click); + // + // btnMoveLine + // + this.btnMoveLine.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.btnMoveLine.Cursor = System.Windows.Forms.Cursors.Hand; + this.btnMoveLine.Depth = 0; + this.btnMoveLine.DrawBorder = true; + this.btnMoveLine.Icon = null; + this.btnMoveLine.Location = new System.Drawing.Point(928, 184); + this.btnMoveLine.MouseState = MaterialSkin.MouseState.HOVER; + this.btnMoveLine.Name = "btnMoveLine"; + this.btnMoveLine.Primary = false; + this.btnMoveLine.Size = new System.Drawing.Size(128, 32); + this.btnMoveLine.TabIndex = 9; + this.btnMoveLine.Text = "Move Line"; + this.btnMoveLine.UseVisualStyleBackColor = true; + this.btnMoveLine.Click += new System.EventHandler(this.btnMoveLine_Click); + // + // btnMoveVertices + // + this.btnMoveVertices.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.btnMoveVertices.Cursor = System.Windows.Forms.Cursors.Hand; + this.btnMoveVertices.Depth = 0; + this.btnMoveVertices.DrawBorder = true; + this.btnMoveVertices.Icon = null; + this.btnMoveVertices.Location = new System.Drawing.Point(928, 224); + this.btnMoveVertices.MouseState = MaterialSkin.MouseState.HOVER; + this.btnMoveVertices.Name = "btnMoveVertices"; + this.btnMoveVertices.Primary = false; + this.btnMoveVertices.Size = new System.Drawing.Size(128, 32); + this.btnMoveVertices.TabIndex = 10; + this.btnMoveVertices.Text = "Move Vertices"; + this.btnMoveVertices.UseVisualStyleBackColor = true; + this.btnMoveVertices.Click += new System.EventHandler(this.btnMoveVertices_Click); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.BackColor = System.Drawing.Color.White; + this.label2.Location = new System.Drawing.Point(928, 32); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(68, 15); + this.label2.TabIndex = 11; + this.label2.Text = "Edit Modes:"; + // // MapEditor // this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(1066, 824); + this.Controls.Add(this.label2); + this.Controls.Add(this.btnMoveVertices); + this.Controls.Add(this.btnMoveLine); + this.Controls.Add(this.btnRemoveLine); + this.Controls.Add(this.btnDrawLine); + this.Controls.Add(this.btnBrush); this.Controls.Add(this.udMemoryBuffer); this.Controls.Add(this.label1); this.Controls.Add(this.materialRaisedButton3); @@ -126,5 +232,11 @@ namespace Lindt.Candybox.Demo private MaterialSkin.Controls.MaterialRaisedButton materialRaisedButton3; private System.Windows.Forms.Label label1; private System.Windows.Forms.NumericUpDown udMemoryBuffer; + private MaterialSkin.Controls.MaterialRaisedButton btnBrush; + private MaterialSkin.Controls.MaterialRaisedButton btnDrawLine; + private MaterialSkin.Controls.MaterialRaisedButton btnRemoveLine; + private MaterialSkin.Controls.MaterialRaisedButton btnMoveLine; + private MaterialSkin.Controls.MaterialRaisedButton btnMoveVertices; + private System.Windows.Forms.Label label2; } } \ No newline at end of file diff --git a/Plugins/CandyboxPlugin/Forms/MapEditor.cs b/Plugins/CandyboxPlugin/Forms/MapEditor.cs index 85cc59f..9fcd076 100644 --- a/Plugins/CandyboxPlugin/Forms/MapEditor.cs +++ b/Plugins/CandyboxPlugin/Forms/MapEditor.cs @@ -52,6 +52,53 @@ namespace Lindt.Candybox.Demo maskControl1.Mask = matContours2.ToBitmap(); maskControl1.Original = original.Clone().ToBitmap(); + maskControl1.VectorLines = _recipe.LearnedParameters.Cuts.Select(x=>x.Scale(1800f/512f, 1408f/512f)).ToList(); + // Set default mode to Brush + SetMode(EditMode.Brush); + } + + private void SetMode(EditMode mode) + { + maskControl1.CurrentMode = mode; + + // Reset button colors + btnBrush.Primary = mode==EditMode.Brush; + btnDrawLine.Primary = mode==EditMode.DrawLine; + btnRemoveLine.Primary = mode==EditMode.RemoveLine; + btnMoveLine.Primary = mode==EditMode.MoveLine; + btnMoveVertices.Primary = mode==EditMode.MoveVertices; + btnBrush.Invalidate(); + btnDrawLine.Invalidate(); + btnRemoveLine.Invalidate(); + btnMoveLine.Invalidate(); + btnMoveVertices.Invalidate(); + + + } + + private void btnBrush_Click(object sender, EventArgs e) + { + SetMode(EditMode.Brush); + } + + private void btnDrawLine_Click(object sender, EventArgs e) + { + SetMode(EditMode.DrawLine); + } + + private void btnRemoveLine_Click(object sender, EventArgs e) + { + SetMode(EditMode.RemoveLine); + } + + private void btnMoveLine_Click(object sender, EventArgs e) + { + SetMode(EditMode.MoveLine); + } + + private void btnMoveVertices_Click(object sender, EventArgs e) + { + SetMode(EditMode.MoveVertices); } private void materialRaisedButton3_Click(object sender, EventArgs e) @@ -63,7 +110,7 @@ namespace Lindt.Candybox.Demo } _recipe.LearnedParameters.Configuration.MemoryBuffer = (int)udMemoryBuffer.Value; - _recipe.LearnContours(contours.ToArray(), _original); + _recipe.LearnContours(contours.ToArray(), _original,maskControl1.VectorLines.Select(x=>x.Scale(512f/1800f, 512f/1408f)).ToList()); DialogResult = DialogResult.OK; } diff --git a/Plugins/CandyboxPlugin/Forms/MaskControl.cs b/Plugins/CandyboxPlugin/Forms/MaskControl.cs index c02eba1..074f48f 100644 --- a/Plugins/CandyboxPlugin/Forms/MaskControl.cs +++ b/Plugins/CandyboxPlugin/Forms/MaskControl.cs @@ -13,19 +13,140 @@ using OpenCvSharp; using OpenCvSharp.Extensions; using Point = System.Drawing.Point; - namespace Lindt.Candybox.Demo { + public enum EditMode + { + Brush, + DrawLine, + RemoveLine, + MoveLine, + MoveVertices + } + + public class VectorLine + { + public Point StartPoint { get; set; } + public Point EndPoint { get; set; } + public bool Selected { get; set; } + + public VectorLine() + { + } + + public VectorLine Scale(float sX, float sY) + { + return new VectorLine(new Point((int)(StartPoint.X * sX), (int)(StartPoint.Y * sY)), + new Point((int)(EndPoint.X * sX), (int)(EndPoint.Y * sY))); + } + + public VectorLine(Point start, Point end) + { + StartPoint = start; + EndPoint = end; + Selected = false; + } + + public bool IsPointOnLine(Point point, int tolerance = 10) + { + // Calculate distance from point to line segment + double A = point.X - StartPoint.X; + double B = point.Y - StartPoint.Y; + double C = EndPoint.X - StartPoint.X; + double D = EndPoint.Y - StartPoint.Y; + + double dot = A * C + B * D; + double lenSq = C * C + D * D; + + if (lenSq == 0) return Math.Sqrt(A * A + B * B) <= tolerance; + + double param = dot / lenSq; + + double xx, yy; + if (param < 0) + { + xx = StartPoint.X; + yy = StartPoint.Y; + } + else if (param > 1) + { + xx = EndPoint.X; + yy = EndPoint.Y; + } + else + { + xx = StartPoint.X + param * C; + yy = StartPoint.Y + param * D; + } + + double dx = point.X - xx; + double dy = point.Y - yy; + return Math.Sqrt(dx * dx + dy * dy) <= tolerance; + } + + public bool IsPointNearVertex(Point point, out bool isStartVertex, int tolerance = 15) + { + isStartVertex = false; + double distToStart = Math.Sqrt(Math.Pow(point.X - StartPoint.X, 2) + Math.Pow(point.Y - StartPoint.Y, 2)); + double distToEnd = Math.Sqrt(Math.Pow(point.X - EndPoint.X, 2) + Math.Pow(point.Y - EndPoint.Y, 2)); + + if (distToStart <= tolerance) + { + isStartVertex = true; + return true; + } + if (distToEnd <= tolerance) + { + isStartVertex = false; + return true; + } + return false; + } + } + public partial class MaskControl : UserControl { private Bitmap _backBuffer; private GrahamConvexHull _hull; + private List _vectorLines; + private EditMode _currentMode = EditMode.Brush; + private bool _isDrawingLine = false; + private Point _lineStartPoint; + private VectorLine _selectedLine; + private bool _isDraggingLine = false; + private bool _isDraggingVertex = false; + private bool _isDraggingStartVertex = false; + private Point _dragOffset; public MaskControl() { InitializeComponent(); _backBuffer = new Bitmap(1800, 1408); _hull = new GrahamConvexHull(); + _vectorLines = new List(); + } + + [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] + public EditMode CurrentMode + { + get => _currentMode; + set + { + _currentMode = value; + // Clear any ongoing operations when mode changes + _isDrawingLine = false; + _isDraggingLine = false; + _isDraggingVertex = false; + _selectedLine = null; + Invalidate(); + } + } + + [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] + public List VectorLines + { + get => _vectorLines; + set => _vectorLines = value; } [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] @@ -41,55 +162,138 @@ namespace Lindt.Candybox.Demo private bool _isDown = false; private Point _lastMouse; - protected override void OnMouseDown(MouseEventArgs e) { _isDown = true; _lastMouse = ConvertCoordinates(new Point(e.X, e.Y)); + + switch (_currentMode) + { + case EditMode.DrawLine: + if (!_isDrawingLine) + { + _isDrawingLine = true; + _lineStartPoint = _lastMouse; + } + else + { + // Finish drawing line + var newLine = new VectorLine(_lineStartPoint, _lastMouse); + _vectorLines.Add(newLine); + _isDrawingLine = false; + Invalidate(); + } + break; + + case EditMode.RemoveLine: + var lineToRemove = _vectorLines.FirstOrDefault(line => line.IsPointOnLine(_lastMouse)); + if (lineToRemove != null) + { + _vectorLines.Remove(lineToRemove); + Invalidate(); + } + break; + + case EditMode.MoveLine: + _selectedLine = _vectorLines.FirstOrDefault(line => line.IsPointOnLine(_lastMouse)); + if (_selectedLine != null) + { + _isDraggingLine = true; + _dragOffset = new Point(_lastMouse.X - _selectedLine.StartPoint.X, _lastMouse.Y - _selectedLine.StartPoint.Y); + } + break; + + case EditMode.MoveVertices: + foreach (var line in _vectorLines) + { + if (line.IsPointNearVertex(_lastMouse, out bool isStartVertex)) + { + _selectedLine = line; + _isDraggingVertex = true; + _isDraggingStartVertex = isStartVertex; + break; + } + } + break; + } } protected override void OnMouseUp(MouseEventArgs e) { _isDown = false; + _isDraggingLine = false; + _isDraggingVertex = false; } private Pen _pen = new Pen(Color.White, 30); private Pen _penBlack = new Pen(Color.Black, 30); + protected override void OnMouseMove(MouseEventArgs e) { + var currentPoint = ConvertCoordinates(new Point(e.X, e.Y)); - if (_isDown&&e.Button==MouseButtons.Left) + // Handle brush mode (existing functionality) + if (_currentMode == EditMode.Brush) { - var curPoint = ConvertCoordinates(new Point(e.X, e.Y)); - using (Graphics g = Graphics.FromImage(Mask)) + if (_isDown && e.Button == MouseButtons.Left) { - g.DrawLine(_pen, curPoint.X, curPoint.Y,_lastMouse.X,_lastMouse.Y); - g.FillEllipse(Brushes.White, _lastMouse.X - 15, _lastMouse.Y - 15, 30,30); + using (Graphics g = Graphics.FromImage(Mask)) + { + g.DrawLine(_pen, currentPoint.X, currentPoint.Y, _lastMouse.X, _lastMouse.Y); + g.FillEllipse(Brushes.White, _lastMouse.X - 15, _lastMouse.Y - 15, 30, 30); + } + } + if (_isDown && e.Button == MouseButtons.Right) + { + using (Graphics g = Graphics.FromImage(Mask)) + { + g.DrawLine(_penBlack, currentPoint.X, currentPoint.Y, _lastMouse.X, _lastMouse.Y); + g.FillEllipse(Brushes.Black, _lastMouse.X - 15, _lastMouse.Y - 15, 30, 30); + } } } - if (_isDown && e.Button == MouseButtons.Right) + // Handle line dragging + else if (_currentMode == EditMode.MoveLine && _isDraggingLine && _selectedLine != null) { - var curPoint = ConvertCoordinates(new Point(e.X, e.Y)); - using (Graphics g = Graphics.FromImage(Mask)) + var deltaX = currentPoint.X - _lastMouse.X; + var deltaY = currentPoint.Y - _lastMouse.Y; + + _selectedLine.StartPoint = new Point(_selectedLine.StartPoint.X + deltaX, _selectedLine.StartPoint.Y + deltaY); + _selectedLine.EndPoint = new Point(_selectedLine.EndPoint.X + deltaX, _selectedLine.EndPoint.Y + deltaY); + } + // Handle vertex dragging + else if (_currentMode == EditMode.MoveVertices && _isDraggingVertex && _selectedLine != null) + { + if (_isDraggingStartVertex) { - g.DrawLine(_penBlack, curPoint.X, curPoint.Y, _lastMouse.X, _lastMouse.Y); - g.FillEllipse(Brushes.Black, _lastMouse.X - 15, _lastMouse.Y - 15, 30, 30); + _selectedLine.StartPoint = currentPoint; + } + else + { + _selectedLine.EndPoint = currentPoint; } } - _lastMouse = ConvertCoordinates(new Point(e.X, e.Y)); + + _lastMouse = currentPoint; Invalidate(); } private Pen _contourPen = new Pen(Color.GreenYellow, 3); + private Pen _vectorLinePen = new Pen(Color.DeepPink, 12); + private Brush _vertexBrush = new SolidBrush(Color.Orange); + protected override void OnPaint(PaintEventArgs e) { var mat = Mask.ToMat().CvtColor(ColorConversionCodes.BGR2GRAY); var contours = mat.FindContoursAsArray(RetrievalModes.External, ContourApproximationModes.ApproxNone); LastContours = contours; + using (Graphics g = Graphics.FromImage(_backBuffer)) { + g.Clear(Color.Transparent); g.DrawImage(Original, 0, 0); + // Draw contours for (int i = 0; i < contours.Length; i++) { if (contours[i].Length > 1) @@ -98,10 +302,46 @@ namespace Lindt.Candybox.Demo g.DrawPolygon(_contourPen, points); } } - g.DrawEllipse(Pens.Gray,_lastMouse.X-15, _lastMouse.Y - 15,30,30); + + // Draw vector lines + foreach (var line in _vectorLines) + { + // Convert coordinates back to display coordinates + var startDisplay = new Point(line.StartPoint.X , line.StartPoint.Y ); + var endDisplay = new Point(line.EndPoint.X , line.EndPoint.Y ); + + g.DrawLine(_vectorLinePen, startDisplay, endDisplay); + + // Draw vertices when in move vertices mode + if (_currentMode == EditMode.MoveVertices) + { + g.FillEllipse(_vertexBrush, startDisplay.X - 5, startDisplay.Y - 5, 10, 10); + g.FillEllipse(_vertexBrush, endDisplay.X - 5, endDisplay.Y - 5, 10, 10); + } + } + + // Draw temporary line when drawing + if (_currentMode == EditMode.DrawLine && _isDrawingLine) + { + var startDisplay = new Point(_lineStartPoint.X , _lineStartPoint.Y ); + var endDisplay = new Point(_lastMouse.X , _lastMouse.Y ); + using (var tempPen = new Pen(Color.DeepPink, 12) { DashStyle = System.Drawing.Drawing2D.DashStyle.Dash }) + { + g.DrawLine(tempPen, startDisplay, endDisplay); + } + } + + // Draw mouse cursor indicator for brush mode + if (_currentMode == EditMode.Brush) + { + var cursorDisplay = new Point(_lastMouse.X , _lastMouse.Y ); + g.DrawEllipse(Pens.Gray, cursorDisplay.X - 15, cursorDisplay.Y - 15, 30, 30); + } } - e.Graphics.DrawImage(_backBuffer,0, 0,Width,Height); + + e.Graphics.DrawImage(_backBuffer, 0, 0, Width, Height); } + [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)] public OpenCvSharp.Point[][] LastContours { get; set; } @@ -113,7 +353,6 @@ namespace Lindt.Candybox.Demo protected override void OnResize(EventArgs e) { base.OnResize(e); - } } } diff --git a/Plugins/CandyboxPlugin/Recipe/HistoRecipe.cs b/Plugins/CandyboxPlugin/Recipe/HistoRecipe.cs index 1958e62..ecccb03 100644 --- a/Plugins/CandyboxPlugin/Recipe/HistoRecipe.cs +++ b/Plugins/CandyboxPlugin/Recipe/HistoRecipe.cs @@ -5,6 +5,7 @@ using OpenCvSharp; using System.Diagnostics; using System.Drawing.Imaging; using System.Text.Json; +using Lindt.Candybox.Demo; using VisionBuilder.UI.Common.NullClasses; using Point = System.Drawing.Point; using Size = OpenCvSharp.Size; @@ -53,12 +54,12 @@ namespace CandyboxPlugin.Recipe } } - public void LearnContours(OpenCvSharp.Point[][] contours, Mat image) + public void LearnContours(OpenCvSharp.Point[][] contours, Mat image, List cuts) { lock (_lockObject) { - + _learnedParameters.Cuts = cuts; if (_learnedParameters.CandyParameters.Count == 0)//initial learning { _learnedParameters.BlisterAngle = _blisterAngle; @@ -80,8 +81,8 @@ namespace CandyboxPlugin.Recipe }; p.Histogram.Enqueue(histData); _learnedParameters.CandyParameters.Add(p); - } + } else { @@ -156,6 +157,15 @@ namespace CandyboxPlugin.Recipe Mat res = _learner.Eval(resized); Mat resBlister = _blister.Eval(resized); + + var element = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(50, 50)); + Mat blisterOpened = resBlister.Threshold(128,255,ThresholdTypes.Binary).MorphologyEx(MorphTypes.Open,element); + + + resBlister.Dispose(); + resBlister = blisterOpened; + Cv2.WaitKey(1); + sw1.Stop(); Console.WriteLine("AI Time:" + sw1.ElapsedMilliseconds); Mat inverted = null; @@ -195,32 +205,33 @@ namespace CandyboxPlugin.Recipe )) .ToList()); - var dbg=triangles.Where(x => x.IsInside(points[15])).ToList(); - var dbgEdges = Voronoi.Voronoi.GenerateEdgesFromDelaunay(dbg); - foreach (var triangle in dbg) - { - Cv2.Line( - numbersOverlay, - new OpenCvSharp.Point(triangle.Vertices[0].X, triangle.Vertices[0].Y), - new OpenCvSharp.Point(triangle.Vertices[1].X, triangle.Vertices[1].Y), - new Scalar(255, 255, 0, 255), // Aqua color in BGR - 1 // Thickness - ); - Cv2.Line( - numbersOverlay, - new OpenCvSharp.Point(triangle.Vertices[1].X, triangle.Vertices[1].Y), - new OpenCvSharp.Point(triangle.Vertices[2].X, triangle.Vertices[2].Y), - new Scalar(255, 255, 0, 255), // Aqua color in BGR - 1 // Thickness - ); - Cv2.Line( - numbersOverlay, - new OpenCvSharp.Point(triangle.Vertices[2].X, triangle.Vertices[2].Y), - new OpenCvSharp.Point(triangle.Vertices[0].X, triangle.Vertices[0].Y), - new Scalar(255, 255, 0, 255), // Aqua color in BGR - 1 // Thickness - ); - } + //var dbg=triangles.Where(x => x.IsInside(points[15])).ToList(); + //var dbgEdges = Voronoi.Voronoi.GenerateEdgesFromDelaunay(dbg); + //foreach (var triangle in dbg) + //{ + // Cv2.Line( + // numbersOverlay, + // new OpenCvSharp.Point(triangle.Vertices[0].X, triangle.Vertices[0].Y), + // new OpenCvSharp.Point(triangle.Vertices[1].X, triangle.Vertices[1].Y), + // new Scalar(255, 255, 0, 255), // Aqua color in BGR + // 1 // Thickness + // ); + // Cv2.Line( + // numbersOverlay, + // new OpenCvSharp.Point(triangle.Vertices[1].X, triangle.Vertices[1].Y), + // new OpenCvSharp.Point(triangle.Vertices[2].X, triangle.Vertices[2].Y), + // new Scalar(255, 255, 0, 255), // Aqua color in BGR + // 1 // Thickness + // ); + // Cv2.Line( + // numbersOverlay, + // new OpenCvSharp.Point(triangle.Vertices[2].X, triangle.Vertices[2].Y), + // new OpenCvSharp.Point(triangle.Vertices[0].X, triangle.Vertices[0].Y), + // new Scalar(255, 255, 0, 255), // Aqua color in BGR + // 1 // Thickness + // ); + //} + //foreach (Edge edge in dbgEdges) //{ // Cv2.Line( @@ -257,7 +268,19 @@ namespace CandyboxPlugin.Recipe // ); //} } + foreach (VectorLine cut in _learnedParameters.Cuts) + { + Cv2.Line(res, new OpenCvSharp.Point(cut.StartPoint.X, cut.StartPoint.Y), + new OpenCvSharp.Point(cut.EndPoint.X, cut.EndPoint.Y), new Scalar(0, 0, 0), 3); + } + + //foreach (VectorLine cut in _learnedParameters.Cuts) + //{ + // Cv2.Line(numbersOverlay, new OpenCvSharp.Point(cut.StartPoint.X, cut.StartPoint.Y), + // new OpenCvSharp.Point(cut.EndPoint.X, cut.EndPoint.Y), new Scalar(255, 0, 255,255), 3); + + //} var mat = res; Cv2.Threshold(mat, mat, 128, 255, ThresholdTypes.Binary); diff --git a/Plugins/CandyboxPlugin/Recipe/LearningParameters.cs b/Plugins/CandyboxPlugin/Recipe/LearningParameters.cs index e7fa6ee..b18fc7c 100644 --- a/Plugins/CandyboxPlugin/Recipe/LearningParameters.cs +++ b/Plugins/CandyboxPlugin/Recipe/LearningParameters.cs @@ -1,4 +1,5 @@ -using Point = System.Drawing.Point; +using Lindt.Candybox.Demo; +using Point = System.Drawing.Point; namespace CandyboxPlugin.Recipe { @@ -9,5 +10,6 @@ namespace CandyboxPlugin.Recipe public Point BlisterPosition { get; set; } public List CandyParameters { get; set; } = new List(); public int ImageWidth { get; set; } = 1800; + public List Cuts { get; set; } = new List(); } } \ No newline at end of file diff --git a/VisionBuilder.UI.Common/ViewModel/SingleCameraVM.cs b/VisionBuilder.UI.Common/ViewModel/SingleCameraVM.cs index 86ff6f2..ff05a18 100644 --- a/VisionBuilder.UI.Common/ViewModel/SingleCameraVM.cs +++ b/VisionBuilder.UI.Common/ViewModel/SingleCameraVM.cs @@ -28,6 +28,8 @@ namespace VisionBuilder.UI.Common [ObservableProperty] [NotifyPropertyChangedFor(nameof(CanStart))] [NotifyPropertyChangedFor(nameof(CanStop))] + [NotifyPropertyChangedFor(nameof(CanPause))] + [NotifyPropertyChangedFor(nameof(CanResume))] [NotifyCanExecuteChangedFor(nameof(SelectRecipeCommand))] [NotifyCanExecuteChangedFor(nameof(StartCommand))] [NotifyCanExecuteChangedFor(nameof(StopCommand))] @@ -42,13 +44,20 @@ namespace VisionBuilder.UI.Common [ObservableProperty] [NotifyPropertyChangedFor(nameof(CameraLabelAndStatus))] + [NotifyPropertyChangedFor(nameof(IsResumed))] + [NotifyPropertyChangedFor(nameof(CanPause))] + [NotifyPropertyChangedFor(nameof(CanResume))] + [NotifyCanExecuteChangedFor(nameof(ResumeCommand))] + [NotifyCanExecuteChangedFor(nameof(PauseCommand))] private bool _isPaused; public bool IsResumed => !IsPaused; public bool CanStop => IsRunning; public bool CanStart => !IsRunning && SelectedRecipe!=null; - + public bool CanPause => IsRunning && !IsPaused; + public bool CanResume => IsRunning && IsPaused; + public bool IsNotRunning => !IsRunning; private bool _handlingEnabled = true; @@ -62,6 +71,8 @@ namespace VisionBuilder.UI.Common [NotifyCanExecuteChangedFor(nameof(SelectRecipeCommand))] [NotifyCanExecuteChangedFor(nameof(StartCommand))] [NotifyCanExecuteChangedFor(nameof(StopCommand))] + [NotifyCanExecuteChangedFor(nameof(ResumeCommand))] + [NotifyCanExecuteChangedFor(nameof(PauseCommand))] [NotifyPropertyChangedFor(nameof(RecipeSelected))] [NotifyPropertyChangedFor(nameof(RecipeNotSelected))] private RecipeData? _selectedRecipe; diff --git a/VisionBuilder.UI.Windows/Components/SingleCameraControl.Designer.cs b/VisionBuilder.UI.Windows/Components/SingleCameraControl.Designer.cs index 395b5ca..93ca2b6 100644 --- a/VisionBuilder.UI.Windows/Components/SingleCameraControl.Designer.cs +++ b/VisionBuilder.UI.Windows/Components/SingleCameraControl.Designer.cs @@ -39,7 +39,9 @@ flowLayoutPanel2 = new FlowLayoutPanel(); btnSelectRecipe = new MaterialSkin.Controls.MaterialRaisedButton(); btnStop = new MaterialSkin.Controls.MaterialRaisedButton(); + btnPause = new MaterialSkin.Controls.MaterialRaisedButton(); materialDivider2 = new MaterialSkin.Controls.MaterialDivider(); + btnResume = new MaterialSkin.Controls.MaterialRaisedButton(); ((System.ComponentModel.ISupportInitialize)previewWindow1).BeginInit(); flowLayoutPanel1.SuspendLayout(); flowLayoutPanel2.SuspendLayout(); @@ -140,9 +142,11 @@ flowLayoutPanel2.Controls.Add(btnSelectRecipe); flowLayoutPanel2.Controls.Add(btnStart); flowLayoutPanel2.Controls.Add(btnStop); + flowLayoutPanel2.Controls.Add(btnPause); + flowLayoutPanel2.Controls.Add(btnResume); flowLayoutPanel2.Location = new Point(21, 27); flowLayoutPanel2.Name = "flowLayoutPanel2"; - flowLayoutPanel2.Size = new Size(200, 237); + flowLayoutPanel2.Size = new Size(200, 365); flowLayoutPanel2.TabIndex = 12; // // btnSelectRecipe @@ -179,6 +183,23 @@ btnStop.Text = "Stop"; btnStop.UseVisualStyleBackColor = true; // + // btnPause + // + btnPause.Anchor = AnchorStyles.Top | AnchorStyles.Right; + btnPause.AutoSizeMode = AutoSizeMode.GrowAndShrink; + btnPause.Depth = 0; + btnPause.DrawBorder = true; + btnPause.Font = new Font("Segoe UI", 9F, FontStyle.Bold); + btnPause.Icon = null; + btnPause.Location = new Point(21, 213); + btnPause.MouseState = MaterialSkin.MouseState.HOVER; + btnPause.Name = "btnPause"; + btnPause.Primary = false; + btnPause.Size = new Size(176, 64); + btnPause.TabIndex = 12; + btnPause.Text = "Pause"; + btnPause.UseVisualStyleBackColor = true; + // // materialDivider2 // materialDivider2.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Right; @@ -191,6 +212,23 @@ materialDivider2.TabIndex = 11; materialDivider2.Text = "materialDivider2"; // + // btnResume + // + btnResume.Anchor = AnchorStyles.Top | AnchorStyles.Right; + btnResume.AutoSizeMode = AutoSizeMode.GrowAndShrink; + btnResume.Depth = 0; + btnResume.DrawBorder = true; + btnResume.Font = new Font("Segoe UI", 9F, FontStyle.Bold); + btnResume.Icon = null; + btnResume.Location = new Point(21, 283); + btnResume.MouseState = MaterialSkin.MouseState.HOVER; + btnResume.Name = "btnResume"; + btnResume.Primary = false; + btnResume.Size = new Size(176, 64); + btnResume.TabIndex = 13; + btnResume.Text = "Resume"; + btnResume.UseVisualStyleBackColor = true; + // // SingleCameraControl // AutoScaleDimensions = new SizeF(7F, 15F); @@ -226,5 +264,7 @@ private MaterialSkin.Controls.MaterialRaisedButton btnSelectRecipe; private MaterialSkin.Controls.MaterialDivider materialDivider2; private FlowLayoutPanel flowLayoutPanel2; + private MaterialSkin.Controls.MaterialRaisedButton btnPause; + private MaterialSkin.Controls.MaterialRaisedButton btnResume; } } diff --git a/VisionBuilder.UI.Windows/Components/SingleCameraControl.cs b/VisionBuilder.UI.Windows/Components/SingleCameraControl.cs index b06b93e..9daa563 100644 --- a/VisionBuilder.UI.Windows/Components/SingleCameraControl.cs +++ b/VisionBuilder.UI.Windows/Components/SingleCameraControl.cs @@ -37,12 +37,16 @@ namespace VisionBuilder.UI.Windows.Components btnStart.Command=_singleCameraVm.StartCommand; btnStop.Command=_singleCameraVm.StopCommand; btnSelectRecipe.Command=_singleCameraVm.SelectRecipeCommand; + btnPause.Command=_singleCameraVm.PauseCommand; + btnResume.Command=_singleCameraVm.ResumeCommand; lblCameraName.DataBindings.Add("Text", _singleCameraVm, nameof(_singleCameraVm.CameraLabelAndStatus), true, DataSourceUpdateMode.OnPropertyChanged); btnSelectRecipe.DataBindings.Add("Text", _singleCameraVm, nameof(_singleCameraVm.CurrentRecipeName), true, DataSourceUpdateMode.OnPropertyChanged); btnStart.DataBindings.Add(nameof(btnStart.Visible), _singleCameraVm, nameof(_singleCameraVm.CanStart), true, DataSourceUpdateMode.OnPropertyChanged); btnStop.DataBindings.Add(nameof(btnStop.Visible), _singleCameraVm, nameof(_singleCameraVm.CanStop), true, DataSourceUpdateMode.OnPropertyChanged); btnSelectRecipe.DataBindings.Add(nameof(btnSelectRecipe.Primary), _singleCameraVm, nameof(_singleCameraVm.RecipeNotSelected), true, DataSourceUpdateMode.OnPropertyChanged); + btnPause.DataBindings.Add(nameof(btnPause.Visible), _singleCameraVm, nameof(_singleCameraVm.CanPause), true, DataSourceUpdateMode.OnPropertyChanged); + btnResume.DataBindings.Add(nameof(btnResume.Visible), _singleCameraVm, nameof(_singleCameraVm.CanResume), true, DataSourceUpdateMode.OnPropertyChanged); } diff --git a/VisionBuilder.UI.Windows/Components/Stats.cs b/VisionBuilder.UI.Windows/Components/Stats.cs index 61f9a69..e8c9626 100644 --- a/VisionBuilder.UI.Windows/Components/Stats.cs +++ b/VisionBuilder.UI.Windows/Components/Stats.cs @@ -29,6 +29,8 @@ namespace VisionBuilder.UI.Windows.Components switch (e.PropertyName) { case nameof(StatisticsVM.SessionStarted): + Clear(); + InitializeFields(); UpdateMeta(StartedAtLabel, _statisticsVm.SessionStarted, true); break; case nameof(StatisticsVM.RecipeName):