diff --git a/UVtools.Core/EmguCV/EmguContour.cs b/UVtools.Core/EmguCV/EmguContour.cs
index b4af097..1878a7a 100644
--- a/UVtools.Core/EmguCV/EmguContour.cs
+++ b/UVtools.Core/EmguCV/EmguContour.cs
@@ -22,7 +22,7 @@ namespace UVtools.Core.EmguCV;
///
/// A contour cache for OpenCV
///
-public class EmguContour : IReadOnlyCollection, IDisposable, IComparable, IComparer
+public class EmguContour : IReadOnlyList, IComparable, IComparer, IDisposable
{
#region Constants
@@ -35,7 +35,7 @@ public class EmguContour : IReadOnlyCollection, IDisposable, IComparable<
#region Members
- private VectorOfPoint _points;
+ private VectorOfPoint _contour;
private Rectangle? _bounds;
private RotatedRect? _boundsBestFit;
private CircleF? _minEnclosingCircle;
@@ -56,13 +56,13 @@ public class EmguContour : IReadOnlyCollection, IDisposable, IComparable<
public int YMax => Bounds.Bottom;
- public Rectangle Bounds => _bounds ??= CvInvoke.BoundingRectangle(_points);
+ public Rectangle Bounds => _bounds ??= CvInvoke.BoundingRectangle(_contour);
- public RotatedRect BoundsBestFit => _boundsBestFit ??= CvInvoke.MinAreaRect(_points);
+ public RotatedRect BoundsBestFit => _boundsBestFit ??= CvInvoke.MinAreaRect(_contour);
- public CircleF MinEnclosingCircle => _minEnclosingCircle ??= CvInvoke.MinEnclosingCircle(_points);
+ public CircleF MinEnclosingCircle => _minEnclosingCircle ??= CvInvoke.MinEnclosingCircle(_contour);
- public bool IsConvex => _isConvex ??= CvInvoke.IsContourConvex(_points);
+ public bool IsConvex => _isConvex ??= CvInvoke.IsContourConvex(_contour);
///
/// Gets the area of the contour
@@ -73,7 +73,7 @@ public class EmguContour : IReadOnlyCollection, IDisposable, IComparable<
{
if (double.IsNaN(_area))
{
- _area = CvInvoke.ContourArea(_points);
+ _area = CvInvoke.ContourArea(_contour);
}
return _area;
@@ -89,13 +89,13 @@ public class EmguContour : IReadOnlyCollection, IDisposable, IComparable<
{
if (double.IsNaN(_perimeter))
{
- _perimeter = CvInvoke.ArcLength(_points, true);
+ _perimeter = CvInvoke.ArcLength(_contour, true);
}
return _perimeter;
}
}
- public Moments Moments => _moments ??= CvInvoke.Moments(_points);
+ public Moments Moments => _moments ??= CvInvoke.Moments(_contour);
///
/// Gets the centroid of the contour
@@ -108,13 +108,13 @@ public class EmguContour : IReadOnlyCollection, IDisposable, IComparable<
///
/// Gets or sets the contour points
///
- public VectorOfPoint Points
+ public VectorOfPoint Contour
{
- get => _points;
+ get => _contour;
set
{
Dispose();
- _points = value ?? throw new ArgumentNullException(nameof(Points));
+ _contour = value ?? throw new ArgumentNullException(nameof(Contour));
}
}
@@ -122,16 +122,18 @@ public class EmguContour : IReadOnlyCollection, IDisposable, IComparable<
///
/// Gets if this contour have any point
///
- public bool IsEmpty => _points.Size == 0;
+ public bool IsEmpty => _contour.Size == 0;
#endregion
#region Constructor
- public EmguContour(VectorOfPoint points) : this(points.ToArray())
- { }
- public EmguContour(Point[] points)
+ public EmguContour(VectorOfPoint points)
+ {
+ _contour = points;
+ }
+
+ public EmguContour(Point[] points) : this(new VectorOfPoint(points))
{
- Points = new VectorOfPoint(points);
}
#endregion
@@ -152,19 +154,19 @@ public class EmguContour : IReadOnlyCollection, IDisposable, IComparable<
public bool IsInside(Point point)
{
if (!IsInsideBounds(point)) return false;
- return CvInvoke.PointPolygonTest(_points, point, false) >= 0;
+ return CvInvoke.PointPolygonTest(_contour, point, false) >= 0;
}
public double MeasureDist(Point point)
{
if (!IsInsideBounds(point)) return -1;
- return CvInvoke.PointPolygonTest(_points, point, true);
+ return CvInvoke.PointPolygonTest(_contour, point, true);
}
public IOutputArray ContourApproximation(double epsilon = 0.1)
{
var mat = new Mat();
- CvInvoke.ApproxPolyDP(_points, mat, epsilon*Perimeter, true);
+ CvInvoke.ApproxPolyDP(_contour, mat, epsilon*Perimeter, true);
return mat;
}
@@ -237,14 +239,12 @@ public class EmguContour : IReadOnlyCollection, IDisposable, IComparable<
public EmguContour Clone()
{
- var clone = (EmguContour)MemberwiseClone();
- clone._points = new VectorOfPoint(_points.ToArray());
- return clone;
+ return new EmguContour(Contour.ToArray());
}
public IEnumerator GetEnumerator()
{
- return (IEnumerator) _points.ToArray().GetEnumerator();
+ return (IEnumerator) _contour.ToArray().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
@@ -252,16 +252,20 @@ public class EmguContour : IReadOnlyCollection, IDisposable, IComparable<
return GetEnumerator();
}
- public int Count => _points.Size;
+ public int Count => _contour.Size;
- public Point this[int index] => _points[index];
- public Point this[uint index] => _points[(int) index];
- public Point this[long index] => _points[(int) index];
- public Point this[ulong index] => _points[(int) index];
+ public Point this[sbyte index] => _contour[index];
+ public Point this[byte index] => _contour[index];
+ public Point this[short index] => _contour[index];
+ public Point this[ushort index] => _contour[index];
+ public Point this[int index] => _contour[index];
+ public Point this[uint index] => _contour[(int) index];
+ public Point this[long index] => _contour[(int) index];
+ public Point this[ulong index] => _contour[(int) index];
public void Dispose()
{
- _points.Dispose();
+ _contour.Dispose();
_moments?.Dispose();
_moments = null;
}
@@ -272,7 +276,7 @@ public class EmguContour : IReadOnlyCollection, IDisposable, IComparable<
protected bool Equals(EmguContour other)
{
if (Count != other.Count) return false;
- return _points.ToArray().SequenceEqual(other.ToArray());
+ return _contour.ToArray().SequenceEqual(other.ToArray());
}
public override bool Equals(object? obj)
@@ -285,7 +289,7 @@ public class EmguContour : IReadOnlyCollection, IDisposable, IComparable<
public override int GetHashCode()
{
- return _points.GetHashCode();
+ return _contour.GetHashCode();
}
public int CompareTo(EmguContour? other)
diff --git a/UVtools.Core/EmguCV/EmguContours.cs b/UVtools.Core/EmguCV/EmguContours.cs
index bc82109..0915351 100644
--- a/UVtools.Core/EmguCV/EmguContours.cs
+++ b/UVtools.Core/EmguCV/EmguContours.cs
@@ -25,49 +25,43 @@ namespace UVtools.Core.EmguCV;
///
public class EmguContours : IReadOnlyList, IDisposable
{
+ #region Members
private readonly EmguContour[] _contours;
- public IEnumerator GetEnumerator()
- {
- return ((IEnumerable)_contours).GetEnumerator();
- }
+ ///
+ /// Gets the contours inside
+ ///
+ public readonly VectorOfVectorOfPoint VectorOfContours;
- IEnumerator IEnumerable.GetEnumerator()
- {
- return _contours.GetEnumerator();
- }
+ ///
+ /// Gets the contours hierarchy
+ ///
+ public readonly int[,] Hierarchy = new int[0, 0];
- public int Count => _contours.Length;
+ #endregion
- public readonly int[,] Hierarchy = new int[0,0];
+ #region Properties
+ ///
+ /// Gets if this collection have any contours
+ ///
+ public bool IsEmpty => Count == 0;
+ #endregion
-
- public EmguContour this[int index] => _contours[index];
-
- private EmguContours(int count, int[,] hierarchy)
- {
- _contours = new EmguContour[count];
- Hierarchy = hierarchy;
- }
-
- public EmguContours(Point[][] points)
- {
- _contours = new EmguContour[points.Length];
- for (int i = 0; i < points.Length; i++)
- {
- _contours[i] = new EmguContour(points[i]);
- }
- }
+ #region Constructor
public EmguContours(VectorOfVectorOfPoint vectorOfPointsOfPoints)
{
- _contours = new EmguContour[vectorOfPointsOfPoints.Size];
- for (int i = 0; i < _contours.Length; i++)
+ VectorOfContours = vectorOfPointsOfPoints;
+ _contours = new EmguContour[VectorOfContours.Size];
+ for (int i = 0; i < Count; i++)
{
- _contours[i] = new EmguContour(vectorOfPointsOfPoints[i]);
+ _contours[i] = new EmguContour(VectorOfContours[i]);
}
}
+ public EmguContours(Point[][] points) : this(new VectorOfVectorOfPoint(points))
+ { }
+
public EmguContours(Point[][] points, int[,] hierarchy) : this(points)
{
Hierarchy = hierarchy;
@@ -80,13 +74,41 @@ public class EmguContours : IReadOnlyList, IDisposable
public EmguContours(IInputOutputArray mat, RetrType mode = RetrType.List, ChainApproxMethod method = ChainApproxMethod.ChainApproxSimple, Point offset = default)
{
- using var contours = mat.FindContours(out Hierarchy, mode, method, offset);
- _contours = new EmguContour[contours.Size];
+ VectorOfContours = mat.FindContours(out Hierarchy, mode, method, offset);
+ _contours = new EmguContour[VectorOfContours.Size];
for (int i = 0; i < _contours.Length; i++)
{
- _contours[i] = new EmguContour(contours[i]);
+ _contours[i] = new EmguContour(VectorOfContours[i]);
}
}
+ #endregion
+
+ #region Indexers
+
+ public EmguContour this[sbyte index] => _contours[index];
+ public EmguContour this[byte index] => _contours[index];
+ public EmguContour this[short index] => _contours[index];
+ public EmguContour this[ushort index] => _contours[index];
+ public EmguContour this[int index] => _contours[index];
+ public EmguContour this[uint index] => _contours[index];
+ public EmguContour this[ulong index] => _contours[index];
+ public EmguContour this[long index] => _contours[index];
+
+ #endregion
+
+ #region IReadOnlyList Implementation
+ public IEnumerator GetEnumerator()
+ {
+ return ((IEnumerable)_contours).GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return _contours.GetEnumerator();
+ }
+
+ public int Count => _contours.Length;
+ #endregion
public (int Index, EmguContour Contour, double Distance)[][] CalculateCentroidDistances(bool includeOwn = false, bool sortByDistance = true)
{
@@ -118,35 +140,19 @@ public class EmguContours : IReadOnlyList, IDisposable
public EmguContours Clone()
{
- var clone = new EmguContours(_contours.Length, Hierarchy);
-
- for (int i = 0; i < _contours.Length; i++)
- {
- clone._contours[i] = this[i].Clone();
- }
-
- return clone;
+ return new EmguContours(VectorOfContours.ToArrayOfArray(), Hierarchy);
}
public void Dispose()
{
+ VectorOfContours.Dispose();
foreach (var contour in _contours)
{
contour.Dispose();
}
}
-
-
-
-
-
-
-
-
-
-
-
+ #region Static methods
///
/// Gets contours inside a point
///
@@ -402,4 +408,6 @@ public class EmguContours : IReadOnlyList, IDisposable
{
return ContoursIntersectingPixels(contour1, contour2) > 0;
}
+
+ #endregion
}
\ No newline at end of file
diff --git a/UVtools.Core/Layers/Layer.cs b/UVtools.Core/Layers/Layer.cs
index ae65ea8..7bbd958 100644
--- a/UVtools.Core/Layers/Layer.cs
+++ b/UVtools.Core/Layers/Layer.cs
@@ -1041,7 +1041,7 @@ public class Layer : BindableBase, IEquatable, IEquatable
if (_contours is null)
{
using var mat = LayerMat;
- _contours = new EmguContours(mat);
+ _contours = new EmguContours(mat, RetrType.Tree);
}
return _contours;
@@ -1053,7 +1053,7 @@ public class Layer : BindableBase, IEquatable, IEquatable
///
public EmguContours GetContours(IInputOutputArray mat)
{
- return _contours ??= new EmguContours(mat);
+ return _contours ??= new EmguContours(mat, RetrType.Tree);
}
#endregion
diff --git a/UVtools.Core/Operations/OperationRaftRelief.cs b/UVtools.Core/Operations/OperationRaftRelief.cs
index c6f0ea8..9503a26 100644
--- a/UVtools.Core/Operations/OperationRaftRelief.cs
+++ b/UVtools.Core/Operations/OperationRaftRelief.cs
@@ -336,7 +336,7 @@ public class OperationRaftRelief : Operation
break;
case RaftReliefTypes.LinkedLines:
{
- using var contours = new EmguContours(supportsMatOriginal.FindContours());
+ using var contours = new EmguContours(supportsMatOriginal);
using var supportsRedraw = _linkedExternalSupports ? supportsMatOriginal.Clone() : null;
using var supportsBrightnessCorrection = _highBrightness < byte.MaxValue ? supportsMat.Clone() : null;
@@ -423,7 +423,7 @@ public class OperationRaftRelief : Operation
break;
case RaftReliefTypes.Tabs:
{
- using var contours = mat.FindContours(RetrType.External);
+ using var contours = new EmguContours(mat, RetrType.External);
var span = mat.GetDataByteSpan();
var minX = 10;
@@ -443,10 +443,8 @@ public class OperationRaftRelief : Operation
};
var color = new MCvScalar(_highBrightness);
-
- for (var i = 0; i < contours.Size; i++)
+ foreach(var contour in contours)
{
- using var contour = new EmguContour(contours[i]);
if(contour.Centroid.IsAnyNegative() || contour.Area < 10000) continue;
for (var dir = 0; dir < directions.Length; dir++)
@@ -473,7 +471,7 @@ public class OperationRaftRelief : Operation
continue;
}
- if (CvInvoke.PointPolygonTest(contours[i], new PointF(x, y), false) == 0) // Must be on edge
+ if (CvInvoke.PointPolygonTest(contour.Contour, new PointF(x, y), false) == 0) // Must be on edge
{
foundPoint = true;
break;
diff --git a/documentation/UVtools.Core.xml b/documentation/UVtools.Core.xml
index 3236aba..cb9550d 100644
--- a/documentation/UVtools.Core.xml
+++ b/documentation/UVtools.Core.xml
@@ -137,7 +137,7 @@
Gets the centroid of the contour
-
+
Gets or sets the contour points
@@ -167,6 +167,21 @@
Use only with Tree type
+
+
+ Gets the contours inside
+
+
+
+
+ Gets the contours hierarchy
+
+
+
+
+ Gets if this collection have any contours
+
+
Gets contours inside a point