Files
UVtools/UVtools.Core/Operations/OperationMorph.cs
T
Tiago Conceição 6cfedea4cc v2.9.1
* **File formats:**
   * PhotonS: Implement the write/encode method to allow to use this format and fix the thumbnail
   * VDT: Allow to auto convert the .vdt to the target printer format using the Machine - Notes, using a flag: FILEFORMAT_YourPrinterExtension, for example: FILEFORMAT_CTB
   * (Fix) Unable to convert files with no thumbnails to other file format that requires thumbnails
* **Tools:**
   * (Add) Re-height: Option to Anti-Aliasing layers
   * (Fix) Morph and Blur: The combobox was not setting to the selected item when preform a redo operation (Ctrl+Shift+Z)
* **GUI:**
   * (Change) Progress window to be a grid element inside MainWindow, this allow to reuse the graphics and its elements without the need of spawning a Window instance everytime a progress is shown, resulting in better performance and more fluid transaction
   * (Improvement) Clear issues when generating calibration tests
2021-04-18 00:18:42 +01:00

193 lines
6.1 KiB
C#

/*
* GNU AFFERO GENERAL PUBLIC LICENSE
* Version 3, 19 November 2007
* Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
* Everyone is permitted to copy and distribute verbatim copies
* of this license document, but changing it is not allowed.
*/
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Xml.Serialization;
using Emgu.CV;
using Emgu.CV.CvEnum;
using UVtools.Core.FileFormats;
using UVtools.Core.Objects;
namespace UVtools.Core.Operations
{
[Serializable]
public sealed class OperationMorph : Operation
{
#region Enums
public enum MorphOperations
{
[Description("Erode: Contracts the boundaries within the object")]
Erode = MorphOp.Erode,
[Description("Dilate: Expands the boundaries within the object")]
Dilate = MorphOp.Dilate,
[Description("Gap Closing - Closes small holes inside the objects")]
Close = MorphOp.Close,
[Description("Noise Removal - Removes small isolated pixels")]
Open = MorphOp.Open,
[Description("Gradient - Removes the interior areas of objects")]
Gradient = MorphOp.Gradient,
}
#endregion
#region Members
private MorphOperations _morphOperation = MorphOperations.Erode;
private uint _iterationsStart = 1;
private uint _iterationsEnd = 1;
private bool _chamfer;
#endregion
#region Overrides
public override string Title => "Morph";
public override string Description =>
$"Morph Model - " +
$"Various operations that can be used to change the physical structure of the model or individual layers.";
public override string ConfirmationText =>
$"morph model layers {LayerIndexStart} through {LayerIndexEnd}?";
public override string ProgressTitle =>
$"Morphing layers {LayerIndexStart} through {LayerIndexEnd}";
public override string ProgressAction => "Morphed layers";
#endregion
#region Properties
public MorphOperations MorphOperation
{
get => _morphOperation;
set => RaiseAndSetIfChanged(ref _morphOperation, value);
}
public uint Iterations
{
get => IterationsStart;
set => IterationsStart = IterationsEnd = value;
}
public uint IterationsStart
{
get => _iterationsStart;
set => RaiseAndSetIfChanged(ref _iterationsStart, value);
}
public uint IterationsEnd
{
get => _iterationsEnd;
set => RaiseAndSetIfChanged(ref _iterationsEnd, value);
}
public bool Chamfer
{
get => _chamfer;
set => RaiseAndSetIfChanged(ref _chamfer, value);
}
[XmlIgnore]
public Kernel Kernel { get; set; } = new();
public override string ToString()
{
var result = $"[{_morphOperation}] [Iterations: {_iterationsStart}/{_iterationsEnd}] [Chamfer: {_chamfer}]" + LayerRangeString;
if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}";
return result;
}
#endregion
#region Constructor
public OperationMorph() { }
public OperationMorph(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Equality
private bool Equals(OperationMorph other)
{
return _morphOperation == other._morphOperation && _iterationsStart == other._iterationsStart && _iterationsEnd == other._iterationsEnd && _chamfer == other._chamfer;
}
public override bool Equals(object obj)
{
return ReferenceEquals(this, obj) || obj is OperationMorph other && Equals(other);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = (int) _morphOperation;
hashCode = (hashCode * 397) ^ (int) _iterationsStart;
hashCode = (hashCode * 397) ^ (int) _iterationsEnd;
hashCode = (hashCode * 397) ^ _chamfer.GetHashCode();
return hashCode;
}
}
#endregion
#region Methods
protected override bool ExecuteInternally(OperationProgress progress)
{
var isFade = Chamfer;
LayerManager.MutateGetVarsIterationChamfer(
LayerIndexStart,
LayerIndexEnd,
(int)IterationsStart,
(int)IterationsEnd,
ref isFade,
out var iterationSteps,
out var maxIteration
);
Parallel.For(LayerIndexStart, LayerIndexEnd + 1,
//new ParallelOptions {MaxDegreeOfParallelism = 1},
layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
int iterations = LayerManager.MutateGetIterationVar(isFade, (int)IterationsStart, (int)IterationsEnd, iterationSteps, maxIteration, LayerIndexStart, (uint)layerIndex);
using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat, iterations);
SlicerFile[layerIndex].LayerMat = mat;
progress.LockAndIncrement();
});
return !progress.Token.IsCancellationRequested;
}
public override bool Execute(Mat mat, params object[] arguments)
{
int iterations = (int) _iterationsStart;
if (arguments is not null && arguments.Length >= 1)
{
iterations = (int) arguments[0];
}
using var original = mat.Clone();
var target = GetRoiOrDefault(mat);
CvInvoke.MorphologyEx(target, target, (MorphOp) MorphOperation, Kernel.Matrix, Kernel.Anchor, iterations, BorderType.Reflect101, default);
ApplyMask(original, mat);
return true;
}
#endregion
}
}