Improvement on contour classes

This commit is contained in:
Tiago Conceição
2023-01-08 00:31:26 +00:00
parent 516b87d209
commit 86a432e212
5 changed files with 118 additions and 93 deletions
+36 -32
View File
@@ -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)
+60 -52
View File
@@ -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
}
+2 -2
View File
@@ -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;
+16 -1
View File
@@ -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