mirror of
https://github.com/riegera2412/UVtools.git
synced 2026-07-08 17:42:31 +02:00
Improvements on contours classes and add a contour cache to layer
This commit is contained in:
@@ -35,7 +35,7 @@ public class EmguContour : IReadOnlyCollection<Point>, IDisposable, IComparable<
|
||||
|
||||
#region Members
|
||||
|
||||
private VectorOfPoint _points = null!;
|
||||
private VectorOfPoint _points;
|
||||
private Rectangle? _bounds;
|
||||
private RotatedRect? _boundsBestFit;
|
||||
private CircleF? _minEnclosingCircle;
|
||||
@@ -106,7 +106,7 @@ public class EmguContour : IReadOnlyCollection<Point>, IDisposable, IComparable<
|
||||
(int)Math.Round(Moments.M01 / Moments.M00));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the contour <see cref="Point"/>
|
||||
/// Gets or sets the contour points
|
||||
/// </summary>
|
||||
public VectorOfPoint Points
|
||||
{
|
||||
@@ -224,7 +224,7 @@ public class EmguContour : IReadOnlyCollection<Point>, IDisposable, IComparable<
|
||||
#region Static methods
|
||||
public static Point GetCentroid(VectorOfPoint points)
|
||||
{
|
||||
if (points is null || points.Length == 0) return EmguExtensions.AnchorCenter;
|
||||
if (points.Length == 0) return EmguExtensions.AnchorCenter;
|
||||
using var moments = CvInvoke.Moments(points);
|
||||
return moments.M00 == 0 ? EmguExtensions.AnchorCenter :
|
||||
new Point(
|
||||
@@ -235,6 +235,13 @@ public class EmguContour : IReadOnlyCollection<Point>, IDisposable, IComparable<
|
||||
|
||||
#region Implementations
|
||||
|
||||
public EmguContour Clone()
|
||||
{
|
||||
var clone = (EmguContour)MemberwiseClone();
|
||||
clone._points = new VectorOfPoint(_points.ToArray());
|
||||
return clone;
|
||||
}
|
||||
|
||||
public IEnumerator<Point> GetEnumerator()
|
||||
{
|
||||
return (IEnumerator<Point>) _points.ToArray().GetEnumerator();
|
||||
@@ -254,8 +261,9 @@ public class EmguContour : IReadOnlyCollection<Point>, IDisposable, IComparable<
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_points?.Dispose();
|
||||
_points.Dispose();
|
||||
_moments?.Dispose();
|
||||
_moments = null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -295,6 +303,4 @@ public class EmguContour : IReadOnlyCollection<Point>, IDisposable, IComparable<
|
||||
return x._area.CompareTo(y._area);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
@@ -44,6 +44,21 @@ public class EmguContours : IReadOnlyList<EmguContour>, IDisposable
|
||||
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
public EmguContours(VectorOfVectorOfPoint vectorOfPointsOfPoints)
|
||||
{
|
||||
_contours = new EmguContour[vectorOfPointsOfPoints.Size];
|
||||
@@ -53,6 +68,11 @@ public class EmguContours : IReadOnlyList<EmguContour>, IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
public EmguContours(Point[][] points, int[,] hierarchy) : this(points)
|
||||
{
|
||||
Hierarchy = hierarchy;
|
||||
}
|
||||
|
||||
public EmguContours(VectorOfVectorOfPoint vectorOfPointsOfPoints, int[,] hierarchy) : this(vectorOfPointsOfPoints)
|
||||
{
|
||||
Hierarchy = hierarchy;
|
||||
@@ -96,6 +116,18 @@ public class EmguContours : IReadOnlyList<EmguContour>, IDisposable
|
||||
return items;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var contour in _contours)
|
||||
@@ -104,6 +136,17 @@ public class EmguContours : IReadOnlyList<EmguContour>, IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets contours inside a point
|
||||
/// </summary>
|
||||
@@ -331,10 +374,11 @@ public class EmguContours : IReadOnlyList<EmguContour>, IDisposable
|
||||
{
|
||||
var contour1Rect = CvInvoke.BoundingRectangle(contour1[0]);
|
||||
var contour2Rect = CvInvoke.BoundingRectangle(contour2[0]);
|
||||
|
||||
|
||||
/* early exit if the bounding rectangles don't intersect */
|
||||
if (!contour1Rect.IntersectsWith(contour2Rect)) return 0;
|
||||
var totalRect = Rectangle.Union(contour1Rect, contour2Rect);
|
||||
//var totalRect = Rectangle.Union(contour1Rect, contour2Rect);
|
||||
var totalRect = RectangleExtensions.SmallestRectangle(contour1Rect, contour2Rect);
|
||||
|
||||
using var contour1Mat = EmguExtensions.InitMat(totalRect.Size);
|
||||
using var contour2Mat = EmguExtensions.InitMat(totalRect.Size);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* of this license document, but changing it is not allowed.
|
||||
*/
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
namespace UVtools.Core.Extensions;
|
||||
|
||||
@@ -25,4 +26,32 @@ public static class RectangleExtensions
|
||||
|
||||
public static Rectangle OffsetBy(this Rectangle src, Point position) => src.OffsetBy(position.X, position.Y);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the smallest rectangle among all rectangles
|
||||
/// </summary>
|
||||
/// <param name="rectangles"></param>
|
||||
/// <returns>The smallest rectangle</returns>
|
||||
public static Rectangle SmallestRectangle(params Rectangle[] rectangles) => rectangles.MinBy(rectangle => rectangle.Area());
|
||||
|
||||
/// <summary>
|
||||
/// Gets the smallest rectangle among all rectangles
|
||||
/// </summary>
|
||||
/// <param name="rectangles"></param>
|
||||
/// <returns>The smallest rectangle</returns>
|
||||
public static RectangleF SmallestRectangle(params RectangleF[] rectangles) => rectangles.MinBy(rectangle => rectangle.Area());
|
||||
|
||||
/// <summary>
|
||||
/// Gets the largest rectangle among all rectangles
|
||||
/// </summary>
|
||||
/// <param name="rectangles"></param>
|
||||
/// <returns>The largest rectangle</returns>
|
||||
public static Rectangle LargestRectangle(params Rectangle[] rectangles) => rectangles.MaxBy(rectangle => rectangle.Area());
|
||||
|
||||
/// <summary>
|
||||
/// Gets the largest rectangle among all rectangles
|
||||
/// </summary>
|
||||
/// <param name="rectangles"></param>
|
||||
/// <returns>The largest rectangle</returns>
|
||||
public static RectangleF LargestRectangle(params RectangleF[] rectangles) => rectangles.MaxBy(rectangle => rectangle.Area());
|
||||
|
||||
}
|
||||
@@ -83,6 +83,8 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
|
||||
private byte _lightPWM = FileFormat.DefaultLightPWM;
|
||||
private float _materialMilliliters;
|
||||
|
||||
private EmguContours? _contours;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
@@ -794,6 +796,8 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
|
||||
_compressedBytes = value;
|
||||
IsModified = true;
|
||||
SlicerFile.BoundingRectangle = Rectangle.Empty;
|
||||
_contours?.Dispose();
|
||||
_contours = null;
|
||||
RaisePropertyChanged();
|
||||
RaisePropertyChanged(nameof(HaveImage));
|
||||
}
|
||||
@@ -1027,6 +1031,31 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
|
||||
/// </summary>
|
||||
public bool IsUsingTSMC => LiftHeight2 > 0 || RetractHeight2 > 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets tree contours cache for this layer, however should call <see cref="GetContours"/> instead with <see cref="LayerMat"/> instance
|
||||
/// </summary>
|
||||
public EmguContours Contours
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_contours is null)
|
||||
{
|
||||
using var mat = LayerMat;
|
||||
_contours = new EmguContours(mat);
|
||||
}
|
||||
|
||||
return _contours;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets tree contours cache for this layer
|
||||
/// </summary>
|
||||
public EmguContours GetContours(IInputOutputArray mat)
|
||||
{
|
||||
return _contours ??= new EmguContours(mat);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
@@ -1694,6 +1723,7 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
|
||||
layer.ResolutionX = _resolutionX;
|
||||
layer.ResolutionY = _resolutionY;
|
||||
layer.CompressedBytes = _compressedBytes?.ToArray();
|
||||
layer._contours = _contours?.Clone();
|
||||
layer.BoundingRectangle = _boundingRectangle;
|
||||
layer.NonZeroPixelCount = _nonZeroPixelCount;
|
||||
}
|
||||
@@ -1702,6 +1732,7 @@ public class Layer : BindableBase, IEquatable<Layer>, IEquatable<uint>
|
||||
{
|
||||
var layer = (Layer)MemberwiseClone();
|
||||
layer._compressedBytes = _compressedBytes?.ToArray();
|
||||
layer._contours = _contours?.Clone();
|
||||
//Debug.WriteLine(ReferenceEquals(_compressedBytes, layer.CompressedBytes));
|
||||
return layer;
|
||||
/*return new (_index, CompressedBytes?.ToArray()!, SlicerFile)
|
||||
|
||||
Reference in New Issue
Block a user