Files
UVtools/UVtools.Core/Operations/OperationMask.cs
T
Tiago Conceição 43c1a6a944 v3.5.4
- **PCB Exposure:**
   - (Add) Parse of deprecated commands (G70, G71, G90, G91)
   - (Fix) Able to have parameterless macro apertures (#503)
- **UI:**
   - (Add) Menu -> File -> Free unused RAM: Force the garbage collection of all unused objects within the program to free unused memory (RAM).
                                            It's never required for the end user run this. The program will automatically take care of it when required.
                                            This function is for debug purposes.
   - (Improvement) Window title bar: Show elapsed minutes and seconds instead of total seconds minutes and second
- (Fix) Tool - Mask: Loaded image resolution shows as (unloaded)
- (Fix) Applying a large set of modifications in layer depth with pixel editor cause huge memory spike due layer aggregation without disposing, leading to program crash on most cases where RAM is insufficient (#506)
- (Upgrade) AvaloniaUI from 0.10.15 to 0.10.16
2022-07-14 23:24:39 +01:00

121 lines
3.5 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 Emgu.CV;
using System;
using System.Drawing;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using Emgu.CV.CvEnum;
using Emgu.CV.DepthAI;
using UVtools.Core.FileFormats;
namespace UVtools.Core.Operations;
[Serializable]
public class OperationMask : Operation
{
#region Overrides
public override string IconClass => "fa-solid fa-mask";
public override string Title => "Mask";
public override string Description =>
"Mask the intensity of the LCD output using a greyscale input image.\n\n" +
"Useful to correct LCD light uniformity for a specific printer.\n\n" +
"NOTE: This operation should be run only after repairs and other transformations. The provided" +
"input mask image must match the output resolution of the target printer.";
public override string ConfirmationText =>
$"mask layers from {LayerIndexStart} through {LayerIndexEnd}";
public override string ProgressTitle =>
$"Masking layers from {LayerIndexStart} through {LayerIndexEnd}";
public override string ProgressAction => "Masked layers";
public override bool CanHaveProfiles => false;
public override string? ValidateInternally()
{
var sb = new StringBuilder();
if (!HaveInputMask)
{
sb.AppendLine("The mask can not be empty.");
}
return sb.ToString();
}
#endregion
#region Properties
[XmlIgnore]
public Mat? Mask { get; set; }
public bool HaveInputMask => Mask is not null;
#endregion
#region Constructor
public OperationMask() { }
public OperationMask(FileFormat slicerFile) : base(slicerFile) { }
#endregion
#region Methods
/// <summary>
/// Loads mask from a image file
/// </summary>
/// <param name="filePath"></param>
/// <param name="invertMask"></param>
/// <param name="maskSize"></param>
public void LoadFromFile(string filePath, bool invertMask = false, Size maskSize = default)
{
Mask = CvInvoke.Imread(filePath, ImreadModes.Grayscale);
if (maskSize.Width > 0 && maskSize.Height > 0 && Mask.Size != maskSize)
{
CvInvoke.Resize(Mask, Mask, maskSize);
}
if (invertMask)
{
InvertMask();
}
}
public void InvertMask()
{
if (!HaveInputMask) return;
CvInvoke.BitwiseNot(Mask, Mask);
}
protected override bool ExecuteInternally(OperationProgress progress)
{
Parallel.For(LayerIndexStart, LayerIndexEnd + 1, CoreSettings.GetParallelOptions(progress), layerIndex =>
{
using var mat = SlicerFile[layerIndex].LayerMat;
Execute(mat);
SlicerFile[layerIndex].LayerMat = mat;
progress.LockAndIncrement();
});
return !progress.Token.IsCancellationRequested;
}
public override bool Execute(Mat mat, params object[]? arguments)
{
var target = GetRoiOrDefault(mat);
using var mask = GetMask(mat);
if (Mask!.Size != target.Size) return false;
CvInvoke.BitwiseAnd(target, Mask, target, mask);
return true;
}
#endregion
}