Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/sn4k3/UVtools.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'UVtools.Core/Operations/OperationRepairLayers.cs')
-rw-r--r--UVtools.Core/Operations/OperationRepairLayers.cs220
1 files changed, 219 insertions, 1 deletions
diff --git a/UVtools.Core/Operations/OperationRepairLayers.cs b/UVtools.Core/Operations/OperationRepairLayers.cs
index 2622432..e46d3c2 100644
--- a/UVtools.Core/Operations/OperationRepairLayers.cs
+++ b/UVtools.Core/Operations/OperationRepairLayers.cs
@@ -7,9 +7,19 @@
*/
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
using System.Text;
+using System.Threading.Tasks;
using System.Xml.Serialization;
+using Emgu.CV;
+using Emgu.CV.CvEnum;
+using Emgu.CV.Structure;
+using Emgu.CV.Util;
+using UVtools.Core.Extensions;
+using UVtools.Core.FileFormats;
using UVtools.Core.Objects;
namespace UVtools.Core.Operations
@@ -17,13 +27,17 @@ namespace UVtools.Core.Operations
[Serializable]
public class OperationRepairLayers : Operation
{
+ #region Members
private bool _repairIslands = true;
private bool _repairResinTraps = true;
private bool _removeEmptyLayers = true;
private byte _removeIslandsBelowEqualPixelCount = 5;
private ushort _removeIslandsRecursiveIterations = 4;
private uint _gapClosingIterations = 1;
- private uint _noiseRemovalIterations = 0;
+ private uint _noiseRemovalIterations;
+ #endregion
+
+ #region Overrides
public override bool CanROI => false;
public override string Title => "Repair layers and issues";
public override string Description => null;
@@ -48,7 +62,9 @@ namespace UVtools.Core.Operations
return new StringTag(sb.ToString());
}
+ #endregion
+ #region Properties
public bool RepairIslands
{
get => _repairIslands;
@@ -96,5 +112,207 @@ namespace UVtools.Core.Operations
[XmlIgnore]
public List<LayerIssue> Issues { get; set; }
+ #endregion
+
+ #region Methods
+
+ public override bool Execute(FileFormat slicerFile, OperationProgress progress = null)
+ {
+ progress ??= new OperationProgress();
+
+
+
+ // Remove islands
+ if (!ReferenceEquals(Issues, null)
+ && !ReferenceEquals(IslandDetectionConfig, null)
+ && RepairIslands
+ && RemoveIslandsBelowEqualPixelCount > 0
+ && RemoveIslandsRecursiveIterations != 1)
+ {
+ progress.Reset("Removed recursive islands", 0);
+ ushort limit = RemoveIslandsRecursiveIterations == 0
+ ? ushort.MaxValue
+ : RemoveIslandsRecursiveIterations;
+
+ var recursiveIssues = Issues;
+ ConcurrentBag<uint> islandsToRecompute = null;
+
+ var islandConfig = IslandDetectionConfig;
+ var overhangConfig = new OverhangDetectionConfiguration(false);
+ var touchingBoundsConfig = new TouchingBoundDetectionConfiguration(false);
+ var resinTrapsConfig = new ResinTrapDetectionConfiguration(false);
+ var emptyLayersConfig = false;
+
+ islandConfig.Enabled = true;
+ islandConfig.RequiredAreaToProcessCheck = (byte)Math.Ceiling(RemoveIslandsBelowEqualPixelCount / 2m);
+
+ for (uint i = 0; i < limit; i++)
+ {
+ if (i > 0)
+ {
+ /*var whiteList = islandsToRecompute.GroupBy(u => u)
+ .Select(grp => grp.First())
+ .ToList();*/
+ islandConfig.WhiteListLayers = islandsToRecompute.ToList();
+ recursiveIssues = slicerFile.LayerManager.GetAllIssues(islandConfig, overhangConfig, resinTrapsConfig, touchingBoundsConfig, emptyLayersConfig);
+ //Debug.WriteLine(i);
+ }
+
+ var issuesGroup =
+ recursiveIssues
+ .Where(issue => issue.Type == LayerIssue.IssueType.Island &&
+ issue.Pixels.Length <= RemoveIslandsBelowEqualPixelCount)
+ .GroupBy(issue => issue.LayerIndex);
+
+ if (!issuesGroup.Any()) break; // Nothing to process
+ islandsToRecompute = new ConcurrentBag<uint>();
+ Parallel.ForEach(issuesGroup, group =>
+ {
+ if (progress.Token.IsCancellationRequested) return;
+ Layer layer = slicerFile[group.Key];
+ Mat image = layer.LayerMat;
+ Span<byte> bytes = image.GetPixelSpan<byte>();
+ foreach (var issue in group)
+ {
+ foreach (var issuePixel in issue.Pixels)
+ {
+ bytes[image.GetPixelPos(issuePixel)] = 0;
+ }
+
+ lock (progress.Mutex)
+ {
+ progress++;
+ }
+ }
+
+ var nextLayerIndex = group.Key + 1;
+ if (nextLayerIndex < slicerFile.LayerCount)
+ islandsToRecompute.Add(nextLayerIndex);
+
+ layer.LayerMat = image;
+ });
+
+ if (islandsToRecompute.IsEmpty) break; // No more leftovers
+ }
+ }
+
+ progress.Reset(ProgressAction, LayerRangeCount);
+ if (RepairIslands || RepairResinTraps)
+ {
+ Parallel.For(LayerIndexStart, LayerIndexEnd, layerIndex =>
+ {
+ if (progress.Token.IsCancellationRequested) return;
+ Layer layer = slicerFile[layerIndex];
+ Mat image = null;
+
+ void initImage()
+ {
+ image ??= layer.LayerMat;
+ }
+
+ if (Issues is not null)
+ {
+ if (RepairIslands && RemoveIslandsBelowEqualPixelCount > 0 && RemoveIslandsRecursiveIterations == 1)
+ {
+ Span<byte> bytes = null;
+ foreach (var issue in Issues)
+ {
+ if (
+ issue.LayerIndex != layerIndex ||
+ issue.Type != LayerIssue.IssueType.Island ||
+ issue.Pixels.Length > RemoveIslandsBelowEqualPixelCount) continue;
+
+ initImage();
+ if (bytes == null)
+ bytes = image.GetPixelSpan<byte>();
+
+ foreach (var issuePixel in issue.Pixels)
+ {
+ bytes[image.GetPixelPos(issuePixel)] = 0;
+ }
+ }
+ /*if (issues.TryGetValue((uint)layerIndex, out var issueList))
+ {
+ var bytes = image.GetPixelSpan<byte>();
+ foreach (var issue in issueList.Where(issue =>
+ issue.Type == LayerIssue.IssueType.Island && issue.Pixels.Length <= removeIslandsBelowEqualPixels))
+ {
+ foreach (var issuePixel in issue.Pixels)
+ {
+ bytes[image.GetPixelPos(issuePixel)] = 0;
+ }
+ }
+ }*/
+ }
+
+ if (RepairResinTraps)
+ {
+ foreach (var issue in Issues.Where(issue => issue.LayerIndex == layerIndex && issue.Type == LayerIssue.IssueType.ResinTrap))
+ {
+ initImage();
+ using var vec = new VectorOfVectorOfPoint(new VectorOfPoint(issue.Pixels));
+ CvInvoke.DrawContours(image,
+ vec,
+ -1,
+ EmguExtensions.WhiteByte,
+ -1);
+ }
+ }
+ }
+
+ if (RepairIslands && (GapClosingIterations > 0 || NoiseRemovalIterations > 0))
+ {
+ initImage();
+ using Mat kernel = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new Size(3, 3),
+ new Point(-1, -1));
+ if (GapClosingIterations > 0)
+ {
+ CvInvoke.MorphologyEx(image, image, MorphOp.Close, kernel, new Point(-1, -1),
+ (int)GapClosingIterations, BorderType.Default, default);
+ }
+
+ if (NoiseRemovalIterations > 0)
+ {
+ CvInvoke.MorphologyEx(image, image, MorphOp.Open, kernel, new Point(-1, -1),
+ (int)NoiseRemovalIterations, BorderType.Default, default);
+ }
+ }
+
+ if (!ReferenceEquals(image, null))
+ {
+ layer.LayerMat = image;
+ image.Dispose();
+ }
+
+ lock (progress.Mutex)
+ {
+ progress++;
+ }
+ });
+ }
+
+ if (RemoveEmptyLayers)
+ {
+ List<uint> removeLayers = new List<uint>();
+ for (uint layerIndex = LayerIndexStart; layerIndex <= LayerIndexEnd; layerIndex++)
+ {
+ if (slicerFile[layerIndex].NonZeroPixelCount == 0)
+ {
+ removeLayers.Add(layerIndex);
+ }
+ }
+
+ if (removeLayers.Count > 0)
+ {
+ OperationLayerRemove.RemoveLayers(slicerFile, removeLayers, progress);
+ }
+ }
+
+ progress.Token.ThrowIfCancellationRequested();
+
+ return true;
+ }
+
+ #endregion
}
}