mirror of
https://github.com/riegera2412/UVtools.git
synced 2026-07-08 17:42:31 +02:00
Improvement on contour classes
This commit is contained in:
@@ -22,7 +22,7 @@ namespace UVtools.Core.EmguCV;
|
||||
/// <summary>
|
||||
/// A contour cache for OpenCV
|
||||
/// </summary>
|
||||
public class EmguContour : IReadOnlyCollection<Point>, IDisposable, IComparable<EmguContour>, IComparer<EmguContour>
|
||||
public class EmguContour : IReadOnlyList<Point>, IComparable<EmguContour>, IComparer<EmguContour>, IDisposable
|
||||
{
|
||||
#region Constants
|
||||
|
||||
@@ -35,7 +35,7 @@ public class EmguContour : IReadOnlyCollection<Point>, 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<Point>, 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);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the area of the contour
|
||||
@@ -73,7 +73,7 @@ public class EmguContour : IReadOnlyCollection<Point>, IDisposable, IComparable<
|
||||
{
|
||||
if (double.IsNaN(_area))
|
||||
{
|
||||
_area = CvInvoke.ContourArea(_points);
|
||||
_area = CvInvoke.ContourArea(_contour);
|
||||
}
|
||||
|
||||
return _area;
|
||||
@@ -89,13 +89,13 @@ public class EmguContour : IReadOnlyCollection<Point>, 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);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the centroid of the contour
|
||||
@@ -108,13 +108,13 @@ public class EmguContour : IReadOnlyCollection<Point>, IDisposable, IComparable<
|
||||
/// <summary>
|
||||
/// Gets or sets the contour points
|
||||
/// </summary>
|
||||
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<Point>, IDisposable, IComparable<
|
||||
/// <summary>
|
||||
/// Gets if this contour have any point
|
||||
/// </summary>
|
||||
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<Point>, 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<Point>, IDisposable, IComparable<
|
||||
|
||||
public EmguContour Clone()
|
||||
{
|
||||
var clone = (EmguContour)MemberwiseClone();
|
||||
clone._points = new VectorOfPoint(_points.ToArray());
|
||||
return clone;
|
||||
return new EmguContour(Contour.ToArray());
|
||||
}
|
||||
|
||||
public IEnumerator<Point> GetEnumerator()
|
||||
{
|
||||
return (IEnumerator<Point>) _points.ToArray().GetEnumerator();
|
||||
return (IEnumerator<Point>) _contour.ToArray().GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
@@ -252,16 +252,20 @@ public class EmguContour : IReadOnlyCollection<Point>, 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<Point>, 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<Point>, IDisposable, IComparable<
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return _points.GetHashCode();
|
||||
return _contour.GetHashCode();
|
||||
}
|
||||
|
||||
public int CompareTo(EmguContour? other)
|
||||
|
||||
@@ -25,49 +25,43 @@ namespace UVtools.Core.EmguCV;
|
||||
/// </summary>
|
||||
public class EmguContours : IReadOnlyList<EmguContour>, IDisposable
|
||||
{
|
||||
#region Members
|
||||
private readonly EmguContour[] _contours;
|
||||
|
||||
public IEnumerator<EmguContour> GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable<EmguContour>)_contours).GetEnumerator();
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the contours inside <see cref="VectorOfVectorOfPoint"/>
|
||||
/// </summary>
|
||||
public readonly VectorOfVectorOfPoint VectorOfContours;
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return _contours.GetEnumerator();
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the contours hierarchy
|
||||
/// </summary>
|
||||
public readonly int[,] Hierarchy = new int[0, 0];
|
||||
|
||||
public int Count => _contours.Length;
|
||||
#endregion
|
||||
|
||||
public readonly int[,] Hierarchy = new int[0,0];
|
||||
#region Properties
|
||||
/// <summary>
|
||||
/// Gets if this collection have any contours
|
||||
/// </summary>
|
||||
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<EmguContour>, 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<EmguContour> GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable<EmguContour>)_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<EmguContour>, 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
|
||||
/// <summary>
|
||||
/// Gets contours inside a point
|
||||
/// </summary>
|
||||
@@ -402,4 +408,6 @@ public class EmguContours : IReadOnlyList<EmguContour>, IDisposable
|
||||
{
|
||||
return ContoursIntersectingPixels(contour1, contour2) > 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1041,7 +1041,7 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
|
||||
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<Layer>, IEquatable<uint>
|
||||
/// </summary>
|
||||
public EmguContours GetContours(IInputOutputArray mat)
|
||||
{
|
||||
return _contours ??= new EmguContours(mat);
|
||||
return _contours ??= new EmguContours(mat, RetrType.Tree);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -137,7 +137,7 @@
|
||||
Gets the centroid of the contour
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:UVtools.Core.EmguCV.EmguContour.Points">
|
||||
<member name="P:UVtools.Core.EmguCV.EmguContour.Contour">
|
||||
<summary>
|
||||
Gets or sets the contour points
|
||||
</summary>
|
||||
@@ -167,6 +167,21 @@
|
||||
Use only with Tree type
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:UVtools.Core.EmguCV.EmguContours.VectorOfContours">
|
||||
<summary>
|
||||
Gets the contours inside <see cref="T:Emgu.CV.Util.VectorOfVectorOfPoint"/>
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:UVtools.Core.EmguCV.EmguContours.Hierarchy">
|
||||
<summary>
|
||||
Gets the contours hierarchy
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:UVtools.Core.EmguCV.EmguContours.IsEmpty">
|
||||
<summary>
|
||||
Gets if this collection have any contours
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:UVtools.Core.EmguCV.EmguContours.GetContoursInside(Emgu.CV.Util.VectorOfVectorOfPoint,System.Int32[0:,0:],System.Drawing.Point,System.Boolean)">
|
||||
<summary>
|
||||
Gets contours inside a point
|
||||
|
||||
Reference in New Issue
Block a user