Switched to uniform noise offset, added ui.

Added switch to random offset as it smooths the diffusion service by
leveraging grey values.

Added UI, preserves void option duplicates the "model only" option but
is significantly faster as it avoid the calculation for void voxels.

Incorporated crypto random and using spans for array access based on PR feedback.
This commit is contained in:
Finn Neuik
2021-09-27 19:25:48 +01:00
parent 3db3853f16
commit eb590c3657
2 changed files with 97 additions and 29 deletions
@@ -10,7 +10,7 @@ using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
@@ -58,7 +58,10 @@ namespace UVtools.Core.Operations
private byte _patternGenBrightness = 128;
private byte _patternGenInfillThickness = 10;
private byte _patternGenInfillSpacing = 20;
private bool _preserveVoids = true;
private int _minNoiseOffset = -128;
private int _maxNoiseOffset = 128;
#endregion
@@ -97,7 +100,7 @@ namespace UVtools.Core.Operations
KeepRegion,
[Description("Discard Region: in the selected ROI or masks")]
DiscardRegion,
[Description("Corrode: randomly remove pixels, adds microtexture and diffuses layer lines (WIP)")]
[Description("Corrode: diffuse pixels using uniform random noise")]
Corrode
}
@@ -166,6 +169,10 @@ namespace UVtools.Core.Operations
{
sb.AppendLine("Can't divide by 0.");
}
else if (_operator == PixelArithmeticOperators.Corrode && _minNoiseOffset >= _maxNoiseOffset)
{
sb.AppendLine("Minimum noise offset must be less than the maximum offset.");
}
if (_applyMethod is PixelArithmeticApplyMethod.ModelWalls //or PixelArithmeticApplyMethod.ModelWallsMinimum
&& (
@@ -255,6 +262,7 @@ namespace UVtools.Core.Operations
RaisePropertyChanged(nameof(IsUsePatternVisible));
RaisePropertyChanged(nameof(ThresholdEnabled));
RaisePropertyChanged(nameof(IsApplyMethodEnabled));
RaisePropertyChanged(nameof(IsDiffusionSettingsVisible));
}
}
@@ -301,6 +309,27 @@ namespace UVtools.Core.Operations
set => RaiseAndSetIfChanged(ref _wallChamfer, value);
}
public bool IsDiffusionSettingsVisible => _operator is PixelArithmeticOperators.Corrode;
public bool PreserveVoids
{
get => _preserveVoids;
set => RaiseAndSetIfChanged(ref _preserveVoids, value);
}
public int NoiseMinOffset
{
get => _minNoiseOffset;
set => RaiseAndSetIfChanged(ref _minNoiseOffset, value);
}
public int NoiseMaxOffset
{
get => _maxNoiseOffset;
set => RaiseAndSetIfChanged(ref _maxNoiseOffset, value);
}
public byte Value
{
get => _value;
@@ -653,28 +682,18 @@ namespace UVtools.Core.Operations
break;
case PixelArithmeticOperators.Corrode:
{
byte[,] originalData = (byte[,])target.GetData(); // don't need for now, but needed for more subtle noise effects
byte[,] targetData = (byte[,])target.GetData();
var pixels = target.GetDataByteSpan();
var zeroMatEntry = new byte[] { 0 }; // add value to ui (or maybe replace by a dimming option)
var noiseThreshold = 280; // add value to ui, values > 255 delete white and increases corrosion intensity
var rand = new Random();
for (int i = original.Rows - 1; i >= 0; i--)
for (int i = pixels.Length - 1; i >= 0; i--)
{
for (int j = original.Cols - 1; j >= 0; j--)
if (!_preserveVoids || pixels[i] > 0)
{
if (originalData[i, j] > 0
&& rand.Next(noiseThreshold) >= originalData[i, j])
{
// target.SetByte(i, j, 0); not sure why this form (also when reading) isn't working
// so using direct byte copy to array instead, seems equivalent
Marshal.Copy(zeroMatEntry, 0, target.DataPointer + (i * target.Cols + j) * target.ElementSize, 1);
}
pixels[i] = (byte) Math.Clamp(RandomNumberGenerator.GetInt32(_minNoiseOffset, _maxNoiseOffset) + pixels[i], byte.MinValue, byte.MaxValue);
}
}
if (_applyMethod != PixelArithmeticApplyMethod.All) ApplyMask(originalRoi, target, applyMask);
break;
}
default:
@@ -1190,7 +1209,7 @@ namespace UVtools.Core.Operations
protected bool Equals(OperationPixelArithmetic other)
{
return _operator == other._operator && _applyMethod == other._applyMethod && _wallThicknessStart == other._wallThicknessStart && _wallThicknessEnd == other._wallThicknessEnd && _wallChamfer == other._wallChamfer && _value == other._value && _usePattern == other._usePattern && _thresholdType == other._thresholdType && _thresholdMaxValue == other._thresholdMaxValue && _patternAlternatePerLayersNumber == other._patternAlternatePerLayersNumber && _patternInvert == other._patternInvert && _patternText == other._patternText && _patternTextAlternate == other._patternTextAlternate && _patternGenMinBrightness == other._patternGenMinBrightness && _patternGenBrightness == other._patternGenBrightness && _patternGenInfillThickness == other._patternGenInfillThickness && _patternGenInfillSpacing == other._patternGenInfillSpacing;
return _operator == other._operator && _applyMethod == other._applyMethod && _wallThicknessStart == other._wallThicknessStart && _wallThicknessEnd == other._wallThicknessEnd && _wallChamfer == other._wallChamfer && _value == other._value && _usePattern == other._usePattern && _thresholdType == other._thresholdType && _thresholdMaxValue == other._thresholdMaxValue && _patternAlternatePerLayersNumber == other._patternAlternatePerLayersNumber && _patternInvert == other._patternInvert && _patternText == other._patternText && _patternTextAlternate == other._patternTextAlternate && _patternGenMinBrightness == other._patternGenMinBrightness && _patternGenBrightness == other._patternGenBrightness && _patternGenInfillThickness == other._patternGenInfillThickness && _patternGenInfillSpacing == other._patternGenInfillSpacing && _preserveVoids == other._preserveVoids && _minNoiseOffset == other._minNoiseOffset && _maxNoiseOffset == other._maxNoiseOffset;
}
public override bool Equals(object obj)
@@ -1221,6 +1240,9 @@ namespace UVtools.Core.Operations
hashCode.Add(_patternGenBrightness);
hashCode.Add(_patternGenInfillThickness);
hashCode.Add(_patternGenInfillSpacing);
hashCode.Add(_preserveVoids);
hashCode.Add(_minNoiseOffset);
hashCode.Add(_maxNoiseOffset);
return hashCode.ToHashCode();
}
@@ -6,7 +6,7 @@
x:Class="UVtools.WPF.Controls.Tools.ToolPixelArithmeticControl">
<Grid RowDefinitions="Auto,10,Auto">
<Grid RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto"
<Grid RowDefinitions="Auto,10,Auto,10,Auto,10,Auto,10,Auto, 10, Auto"
ColumnDefinitions="Auto,10,Auto,20,Auto,10,Auto,20,Auto,10,Auto">
<TextBlock Grid.Row="0" Grid.Column="0"
@@ -70,13 +70,59 @@
IsChecked="{Binding Operation.WallChamfer}"/>
</StackPanel>
<TextBlock Grid.Row="6" Grid.Column="0"
<TextBlock Grid.Row="6" Grid.Column="0"
VerticalAlignment="Center"
IsVisible="{Binding Operation.IsDiffusionSettingsVisible}"
Text="Diffusion:"/>
<StackPanel Grid.Row="6" Grid.Column="2" Grid.ColumnSpan="9"
IsVisible="{Binding Operation.IsDiffusionSettingsVisible}"
Spacing="10" Orientation="Horizontal">
<CheckBox
Margin="10,0,0,0"
Content="Preserve voids"
ToolTip.Tip="Preserve voids (black pixels) when applying diffusion."
IsChecked="{Binding Operation.PreserveVoids}"/>
<TextBlock
VerticalAlignment="Center"
Text="Noise range:"/>
<TextBlock
VerticalAlignment="Center"
Text="Min:"/>
<NumericUpDown
Minimum="-1000"
Maximum="1000"
Width="80"
Value="{Binding Operation.NoiseMinOffset}"
ToolTip.Tip="Minimum value of random noise offset."
IsEnabled="true"/>
<TextBlock
VerticalAlignment="Center"
Text="Max:"/>
<NumericUpDown
Minimum="-1000"
Maximum="1000"
Width="80"
Value="{Binding Operation.NoiseMaxOffset}"
ToolTip.Tip="Maximum value of random noise offset."
IsEnabled="true"/>
</StackPanel>
<TextBlock Grid.Row="8" Grid.Column="0"
VerticalAlignment="Center"
IsVisible="{Binding Operation.ValueEnabled}"
IsEnabled="{Binding Operation.ValueEnabled}"
Text="Brightness:"/>
<StackPanel Grid.Row="6" Grid.Column="2"
<StackPanel Grid.Row="8" Grid.Column="2"
VerticalAlignment="Center"
Orientation="Horizontal" Spacing="5"
IsVisible="{Binding Operation.ValueEnabled}"
@@ -101,28 +147,28 @@
</StackPanel>
<TextBlock Grid.Row="6" Grid.Column="4"
<TextBlock Grid.Row="8" Grid.Column="4"
VerticalAlignment="Center"
HorizontalAlignment="Right"
IsVisible="{Binding Operation.ThresholdEnabled}"
IsEnabled="{Binding Operation.ThresholdEnabled}"
Text="Max.:"/>
<NumericUpDown Grid.Row="6" Grid.Column="6"
<NumericUpDown Grid.Row="8" Grid.Column="6"
Minimum="0"
Maximum="255"
IsVisible="{Binding Operation.ThresholdEnabled}"
IsEnabled="{Binding Operation.ThresholdEnabled}"
Value="{Binding Operation.ThresholdMaxValue}"/>
<TextBlock Grid.Row="6" Grid.Column="8"
<TextBlock Grid.Row="8" Grid.Column="8"
VerticalAlignment="Center"
HorizontalAlignment="Right"
IsVisible="{Binding Operation.ThresholdEnabled}"
IsEnabled="{Binding Operation.ThresholdEnabled}"
Text="Threshold:"/>
<ComboBox Grid.Row="6" Grid.Column="10"
<ComboBox Grid.Row="8" Grid.Column="10"
Width="130"
IsVisible="{Binding Operation.ThresholdEnabled}"
IsEnabled="{Binding Operation.ThresholdEnabled}"
@@ -130,11 +176,11 @@
SelectedItem="{Binding Operation.ThresholdType, Converter={StaticResource FromValueDescriptionToEnumConverter}}"/>
<TextBlock Grid.Row="8" Grid.Column="0"
<TextBlock Grid.Row="10" Grid.Column="0"
VerticalAlignment="Center"
Text="Presets:"/>
<StackPanel Grid.Row="8" Grid.Column="2"
<StackPanel Grid.Row="10" Grid.Column="2"
Grid.ColumnSpan="9"
VerticalAlignment="Center"
Orientation="Horizontal" Spacing="5">