Files
UVtools/UVtools.Core/Operations/OperationLayerExportHeatMap.cs
T
Tiago Conceição 15c500ecaf v3.5.0
- **PCB Exposure:**
   - (Add) Able to select multiple files and create a layer per file or merge them into one layer
   - (Add) Able to import files from a zip file
   - (Improvement) Round pixel coordinates and line thickness
   - (Improvement) Better position precision for primitives
   - (Improvement) Disable the ok button if no files were selected
   - (Change) Do not auto mirror based on printer lcd mirror type
   - (Fix) Limit line thickness to 1px minimum
   - (Fix) Allow leading zero omit from XY coordinates (#492)
   - (Fix) Mirror option was shifting the board position
- (Add) Calibrate - Blooming effect: Generates test models with various strategies and increments to measure the blooming effect
- (Add) Setting: Issues - Default order by, changes the default order on the issues list (#482)
- (Improvement) CTBv4 and encrypted: Fetch `BottomWaitTimes` virtual property from first bottom layer that has at least 2 pixels (#483)
- (Fix) Linux: Enable desktop integration for AppImages (#490)
- (Fix) Extracting zip contents inside folders would cause a error and not extract those contents
- (Upgrade) AvaloniaUI from 0.10.14 to 0.10.15 [Fixes auto-size problems]
2022-06-19 04:19:23 +01:00

220 lines
6.3 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 Emgu.CV.CvEnum;
using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UVtools.Core.Extensions;
using UVtools.Core.FileFormats;
namespace UVtools.Core.Operations;
[Serializable]
public sealed class OperationLayerExportHeatMap : Operation
{
#region Members
private string _filePath = null!;
private RotateDirection _rotateDirection = RotateDirection.None;
private FlipDirection _flipDirection = FlipDirection.None;
private bool _mergeSamePositionedLayers = true;
private bool _cropByRoi = true;
#endregion
#region Overrides
public override bool CanHaveProfiles => false;
public override string IconClass => "fa-solid fa-file-image";
public override string Title => "Export layers to heat map";
public override string Description =>
"Export a layer range to a grayscale heat map image that represents the median of the mass in the Z depth/perception.\n" +
"The pixel brightness/intensity shows where the most mass are concentrated.";
public override string ConfirmationText =>
$"generate a heatmap from layers {LayerIndexStart} through {LayerIndexEnd}?";
public override string ProgressTitle =>
$"Generating a heatmap from layers {LayerIndexStart} through {LayerIndexEnd}";
public override string ProgressAction => "Packed layers";
public override string? ValidateInternally()
{
var sb = new StringBuilder();
if (LayerRangeCount < 2)
{
sb.AppendLine("To generate a heat map at least two layers are required.");
}
return sb.ToString();
}
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 RotateDirection RotateDirection
{
get => _rotateDirection;
set => RaiseAndSetIfChanged(ref _rotateDirection, value);
}
public FlipDirection FlipDirection
{
get => _flipDirection;
set => RaiseAndSetIfChanged(ref _flipDirection, value);
}
public bool MergeSamePositionedLayers
{
get => _mergeSamePositionedLayers;
set => RaiseAndSetIfChanged(ref _mergeSamePositionedLayers, value);
}
public bool CropByROI
{
get => _cropByRoi;
set => RaiseAndSetIfChanged(ref _cropByRoi, value);
}
#endregion
#region Constructor
public OperationLayerExportHeatMap()
{ }
public OperationLayerExportHeatMap(FileFormat slicerFile) : base(slicerFile)
{
_flipDirection = SlicerFile.DisplayMirror;
}
public override void InitWithSlicerFile()
{
_filePath = SlicerFile.FileFullPath + ".heatmap.png";
}
#endregion
#region Methods
protected override bool ExecuteInternally(OperationProgress progress)
{
using var sumMat32 = EmguExtensions.InitMat(SlicerFile.Resolution, 1, DepthType.Cv32S);
var sumMat32Roi = GetRoiOrDefault(sumMat32);
using var mask = GetMask(sumMat32);
var layerRange = _mergeSamePositionedLayers
? SlicerFile.GetDistinctLayersByPositionZ(LayerIndexStart, LayerIndexEnd) .ToArray()
: GetSelectedLayerRange().ToArray();
progress.ItemCount = (uint)layerRange.Length;
/*Parallel.For(LayerIndexStart, LayerIndexEnd+1, CoreSettings.ParallelOptions, layerIndex =>
{
if (progress.Token.IsCancellationRequested) return;
using var mat = SlicerFile[layerIndex].LayerMat;
using var mat32 = new Mat();
mat.ConvertTo(mat32, DepthType.Cv32S);
var mat32Roi = GetRoiOrDefault(mat32);
lock (progress.Mutex)
{
CvInvoke.Add(sumMat32Roi, mat32Roi, sumMat32Roi, mask);
progress++;
}
});*/
Parallel.ForEach(layerRange, CoreSettings.GetParallelOptions(progress), layer =>
{
using var mat = _mergeSamePositionedLayers
? SlicerFile.GetMergedMatForSequentialPositionedLayers(layer.Index)
: layer.LayerMat;
using var mat32 = new Mat();
mat.ConvertTo(mat32, DepthType.Cv32S);
var mat32Roi = GetRoiOrDefault(mat32);
lock (progress.Mutex)
{
CvInvoke.Add(sumMat32Roi, mat32Roi, sumMat32Roi, mask);
progress++;
}
});
using var sumMat = EmguExtensions.InitMat(sumMat32.Size);
sumMat32.ConvertTo(sumMat, DepthType.Cv8U, 1.0 / layerRange.Length);
if (_flipDirection != FlipDirection.None)
{
CvInvoke.Flip(sumMat, sumMat, (FlipType)_flipDirection);
}
if (_rotateDirection != RotateDirection.None)
{
CvInvoke.Rotate(sumMat, sumMat, (RotateFlags)_rotateDirection);
}
if (_cropByRoi && HaveROI)
{
var sumMatRoi = GetRoiOrDefault(sumMat);
sumMatRoi.Save(_filePath);
}
else
{
sumMat.Save(_filePath);
}
return !progress.Token.IsCancellationRequested;
}
#endregion
#region Equality
private bool Equals(OperationLayerExportHeatMap other)
{
return _filePath == other._filePath && _rotateDirection == other._rotateDirection && _flipDirection == other._flipDirection && _mergeSamePositionedLayers == other._mergeSamePositionedLayers && _cropByRoi == other._cropByRoi;
}
public override bool Equals(object? obj)
{
return ReferenceEquals(this, obj) || obj is OperationLayerExportHeatMap other && Equals(other);
}
public override int GetHashCode()
{
return HashCode.Combine(_filePath, (int)_rotateDirection, (int)_flipDirection, _mergeSamePositionedLayers, _cropByRoi);
}
#endregion
}