diff --git a/UVtools.Core/EmguCV/EmguContours.cs b/UVtools.Core/EmguCV/EmguContours.cs index 8c0889e..62bfd47 100644 --- a/UVtools.Core/EmguCV/EmguContours.cs +++ b/UVtools.Core/EmguCV/EmguContours.cs @@ -210,6 +210,12 @@ namespace UVtools.Core.EmguCV return result; } + /// + /// Checks if two contours intersects + /// + /// Contour 1 + /// Contour 2 + /// public static bool ContoursIntersect(VectorOfVectorOfPoint contour1, VectorOfVectorOfPoint contour2) { var contour1Rect = CvInvoke.BoundingRectangle(contour1[0]); @@ -228,16 +234,14 @@ namespace UVtools.Core.EmguCV using var contour1Mat = EmguExtensions.InitMat(totalRect.Size); using var contour2Mat = EmguExtensions.InitMat(totalRect.Size); - using var overlapCheck = EmguExtensions.InitMat(totalRect.Size); var inverseOffset = new Point(minX * -1, minY * -1); CvInvoke.DrawContours(contour1Mat, contour1, -1, EmguExtensions.WhiteColor, -1, Emgu.CV.CvEnum.LineType.EightConnected, null, int.MaxValue, inverseOffset); CvInvoke.DrawContours(contour2Mat, contour2, -1, EmguExtensions.WhiteColor, -1, Emgu.CV.CvEnum.LineType.EightConnected, null, int.MaxValue, inverseOffset); - CvInvoke.BitwiseAnd(contour1Mat, contour2Mat, overlapCheck); - - return CvInvoke.CountNonZero(overlapCheck) > 0; + CvInvoke.BitwiseAnd(contour1Mat, contour2Mat, contour1Mat); + return contour1Mat.FindFirstPositivePixel() != -1; } } } diff --git a/UVtools.Core/Extensions/EmguExtensions.cs b/UVtools.Core/Extensions/EmguExtensions.cs index 7b4577e..90473c4 100644 --- a/UVtools.Core/Extensions/EmguExtensions.cs +++ b/UVtools.Core/Extensions/EmguExtensions.cs @@ -527,6 +527,114 @@ namespace UVtools.Core.Extensions } #endregion + #region Find methods + + /// + /// Finds the first negative (Black) pixel + /// + /// + /// Pixel position in the span, or -1 if not found + public static int FindFirstNegativePixel(this Mat mat) + { + return mat.FindFirstPixelEqualTo(0); + } + + /// + /// Finds the first positive pixel + /// + /// + /// Pixel position in the span, or -1 if not found + public static int FindFirstPositivePixel(this Mat mat) + { + return mat.FindFirstPixelEqualOrGreaterThan(1); + } + + /// + /// Finds the first pixel that is + /// + /// + /// + /// Pixel position in the span, or -1 if not found + public static int FindFirstPixelEqualTo(this Mat mat, byte value) + { + var span = mat.GetDataByteSpan(); + for (var i = 0; i < span.Length; i++) + { + if (span[i] == value) return i; + } + + return -1; + } + + /// + /// Finds the first pixel that is at less than + /// + /// + /// + /// Pixel position in the span, or -1 if not found + public static int FindFirstPixelLessThan(this Mat mat, byte value) + { + var span = mat.GetDataByteSpan(); + for (var i = 0; i < span.Length; i++) + { + if (span[i] < value) return i; + } + + return -1; + } + + /// + /// Finds the first pixel that is at less or equal than + /// + /// + /// + /// Pixel position in the span, or -1 if not found + public static int FindFirstPixelEqualOrLessThan(this Mat mat, byte value) + { + var span = mat.GetDataByteSpan(); + for (var i = 0; i < span.Length; i++) + { + if (span[i] <= value) return i; + } + + return -1; + } + + /// + /// Finds the first pixel that is at greater than + /// + /// + /// + /// Pixel position in the span, or -1 if not found + public static int FindFirstPixelGreaterThan(this Mat mat, byte value) + { + var span = mat.GetDataByteSpan(); + for (var i = 0; i < span.Length; i++) + { + if (span[i] > value) return i; + } + + return -1; + } + + /// + /// Finds the first pixel that is at equal or greater than + /// + /// + /// + /// Pixel position in the span, or -1 if not found + public static int FindFirstPixelEqualOrGreaterThan(this Mat mat, byte value) + { + var span = mat.GetDataByteSpan(); + for (var i = 0; i < span.Length; i++) + { + if (span[i] >= value) return i; + } + + return -1; + } + #endregion + #region Transform methods public static void Transform(this Mat src, double xScale, double yScale, double xTrans = 0, double yTrans = 0, Size dstSize = default, Inter interpolation = Inter.Linear) { @@ -1009,7 +1117,7 @@ namespace UVtools.Core.Extensions // if there are no more 'white' pixels in the image, then // break from the loop - if (CvInvoke.CountNonZero(image) == 0) break; + if (image.FindFirstPixelEqualOrGreaterThan(1) == -1) break; } return skeleton; diff --git a/UVtools.Core/Extensions/PointExtensions.cs b/UVtools.Core/Extensions/PointExtensions.cs index 30202bd..d95572e 100644 --- a/UVtools.Core/Extensions/PointExtensions.cs +++ b/UVtools.Core/Extensions/PointExtensions.cs @@ -14,6 +14,7 @@ namespace UVtools.Core.Extensions { public static double FindLength(Point start, Point end) => Math.Sqrt(Math.Pow(end.Y - start.Y, 2) + Math.Pow(end.X - start.X, 2)); + public static bool IsAnyNegative(this Point point) => point.X < 0 || point.Y < 0; public static bool IsBothNegative(this Point point) => point.X < 0 && point.Y < 0; public static bool IsBothZeroOrPositive(this Point point) => point.X >= 0 && point.Y >= 0; diff --git a/UVtools.Core/Managers/IssueManager.cs b/UVtools.Core/Managers/IssueManager.cs index 4de0495..6eb6874 100644 --- a/UVtools.Core/Managers/IssueManager.cs +++ b/UVtools.Core/Managers/IssueManager.cs @@ -606,12 +606,12 @@ namespace UVtools.Core.Managers { if (matCache[layerIndex] is not null) return; int fromLayerIndex = (int)layerIndex; - int toLayerIndex = (int)Math.Min(SlicerFile.LayerCount, layerIndex + Environment.ProcessorCount * 10 + 1); + int toLayerIndex = (int)Math.Min(SlicerFile.LayerCount, layerIndex + 1 + Environment.ProcessorCount * 5); if (!direction) { toLayerIndex = fromLayerIndex + 1; - fromLayerIndex = (int)Math.Max(resinTrapConfig.StartLayerIndex, fromLayerIndex - Environment.ProcessorCount * 10); + fromLayerIndex = (int)Math.Max(resinTrapConfig.StartLayerIndex, fromLayerIndex - Environment.ProcessorCount * 5); } Parallel.For(fromLayerIndex, toLayerIndex, @@ -899,7 +899,6 @@ namespace UVtools.Core.Managers resinTraps[layerIndex] = null; break; } - } } @@ -1031,9 +1030,8 @@ namespace UVtools.Core.Managers var overlappingGroupIndexes = new List(); for (var x = 0; x < suctionGroups.Count; x++) { - if (suctionGroups[x].Last().LayerIndex != layerIndex + 1) continue; - - using var vec = new VectorOfVectorOfPoint(suctionGroups[x].Last().Contours); + if (suctionGroups[x][^1].LayerIndex != layerIndex + 1) continue; + using var vec = new VectorOfVectorOfPoint(suctionGroups[x][^1].Contours); if (EmguContours.ContoursIntersect(trap, vec)) { overlappingGroupIndexes.Add(x); @@ -1103,25 +1101,23 @@ namespace UVtools.Core.Managers public MainIssue[] DrillSuctionCupsForIssues(IEnumerable issues, int ventHoleDiameter, OperationProgress progress) { - (bool canDrill, Point location) GetDrillLocation(IssueOfContours issue, int diameter) + Point GetDrillLocation(IssueOfContours issue, int diameter) { using var vecCentroid = new VectorOfPoint(issue.Contours[0]); var centroid = EmguContour.GetCentroid(vecCentroid); + if (centroid.IsAnyNegative()) return centroid; using var circleCheck = EmguExtensions.InitMat(issue.BoundingRectangle.Size); using var contourMat = EmguExtensions.InitMat(issue.BoundingRectangle.Size); - using var overlapCheck = EmguExtensions.InitMat(issue.BoundingRectangle.Size); var inverseOffset = new Point(issue.BoundingRectangle.X * -1, issue.BoundingRectangle.Y * -1); using var vec = new VectorOfVectorOfPoint(issue.Contours); CvInvoke.DrawContours(contourMat, vec, -1, EmguExtensions.WhiteColor, -1, LineType.EightConnected, null, int.MaxValue, inverseOffset); - CvInvoke.Circle(circleCheck, new(centroid.X + inverseOffset.X, centroid.Y + inverseOffset.Y), diameter, EmguExtensions.WhiteColor, -1); + CvInvoke.BitwiseAnd(circleCheck, contourMat, circleCheck); - CvInvoke.BitwiseAnd(circleCheck, contourMat, overlapCheck); - - return CvInvoke.CountNonZero(overlapCheck) > 0 - ? (true, centroid) /* 5px centroid is inside layer! drill baby drill */ - : (false, new Point()); /* centroid is not inside the actual contour, no drill */ + return circleCheck.FindFirstPositivePixel() != -1 + ? centroid /* 5px centroid is inside layer! drill baby drill */ + : new Point(-1,-1); /* centroid is not inside the actual contour, no drill */ } var drillOps = new List(); @@ -1131,8 +1127,8 @@ namespace UVtools.Core.Managers foreach (var mainIssue in issues) { var drillPoint = GetDrillLocation((IssueOfContours)mainIssue[0], ventHoleDiameter); - if (!drillPoint.canDrill) continue; - drillOps.Add(new PixelDrainHole(mainIssue.StartLayerIndex, drillPoint.location, (ushort)ventHoleDiameter)); + if (drillPoint.IsAnyNegative()) continue; + drillOps.Add(new PixelDrainHole(mainIssue.StartLayerIndex, drillPoint, (ushort)ventHoleDiameter)); drilledIssues.Add(mainIssue); }