diff options
Diffstat (limited to 'UVtools.Core/Operations/OperationLayerExportSkeleton.cs')
-rw-r--r-- | UVtools.Core/Operations/OperationLayerExportSkeleton.cs | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/UVtools.Core/Operations/OperationLayerExportSkeleton.cs b/UVtools.Core/Operations/OperationLayerExportSkeleton.cs new file mode 100644 index 0000000..0fd56d0 --- /dev/null +++ b/UVtools.Core/Operations/OperationLayerExportSkeleton.cs @@ -0,0 +1,139 @@ +/* + * 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.Threading.Tasks; +using Emgu.CV; +using UVtools.Core.Extensions; +using UVtools.Core.FileFormats; + +namespace UVtools.Core.Operations +{ + [Serializable] + public sealed class OperationLayerExportSkeleton : Operation + { + #region Members + private string _filePath; + private bool _cropByRoi = true; + + #endregion + + #region Overrides + + public override bool CanHaveProfiles => false; + public override string Title => "Export layers to skeleton"; + + public override string Description => + "Export a layer range to a skeletonized image that is the sum of each layer skeleton."; + + public override string ConfirmationText => + $"skeletonize from layers {LayerIndexStart} through {LayerIndexEnd}?"; + + public override string ProgressTitle => + $"Skeletonizing from layers {LayerIndexStart} through {LayerIndexEnd}"; + + public override string ProgressAction => "Skeletonized layers"; + + public override string ToString() + { + var result = $"[Crop by ROI: {_cropByRoi}]" + + LayerRangeString; + if (!string.IsNullOrEmpty(ProfileName)) result = $"{ProfileName}: {result}"; + return result; + } + + #endregion + + #region Properties + + public string FilePath + { + get => _filePath; + set => RaiseAndSetIfChanged(ref _filePath, value); + } + + public bool CropByROI + { + get => _cropByRoi; + set => RaiseAndSetIfChanged(ref _cropByRoi, value); + } + + #endregion + + #region Constructor + + public OperationLayerExportSkeleton() + { } + + public OperationLayerExportSkeleton(FileFormat slicerFile) : base(slicerFile) + { + _filePath = SlicerFile.FileFullPath + ".skeleton.png"; + } + + #endregion + + #region Methods + + protected override bool ExecuteInternally(OperationProgress progress) + { + using var skeletonSum = EmguExtensions.InitMat(SlicerFile.Resolution); + var skeletonSumRoi = GetRoiOrDefault(skeletonSum); + using var mask = GetMask(skeletonSum); + + + Parallel.For(LayerIndexStart, LayerIndexEnd+1, layerIndex => + { + if (progress.Token.IsCancellationRequested) return; + + using var mat = SlicerFile[layerIndex].LayerMat; + var matRoi = GetRoiOrDefault(mat); + using var skeletonRoi = matRoi.Skeletonize(); + lock (progress.Mutex) + { + CvInvoke.Add(skeletonSumRoi, skeletonRoi, skeletonSumRoi, mask); + progress++; + } + }); + + if (!progress.Token.IsCancellationRequested) + { + if (_cropByRoi && HaveROI) + { + skeletonSumRoi.Save(_filePath); + } + else + { + skeletonSum.Save(_filePath); + } + } + + return !progress.Token.IsCancellationRequested; + } + + #endregion + + #region Equality + + private bool Equals(OperationLayerExportSkeleton other) + { + return _filePath == other._filePath && _cropByRoi == other._cropByRoi; + } + + public override bool Equals(object obj) + { + return ReferenceEquals(this, obj) || obj is OperationLayerExportSkeleton other && Equals(other); + } + + public override int GetHashCode() + { + return HashCode.Combine(_filePath, _cropByRoi); + } + + #endregion + } +} |