mirror of
https://github.com/ShareX/ShareX.git
synced 2024-07-13 18:36:05 +12:00
Merge pull request #3826 from sylveon/master
Add user customizable gaussian blur
This commit is contained in:
commit
d544515559
|
@ -27,31 +27,36 @@ namespace ShareX.HelpersLib
|
||||||
{
|
{
|
||||||
public class ConvolutionMatrix
|
public class ConvolutionMatrix
|
||||||
{
|
{
|
||||||
public int Size { get; private set; }
|
private readonly double[,] matrix;
|
||||||
public int[,] Matrix { get; set; }
|
|
||||||
public int Factor { get; set; }
|
public int Width => matrix.GetLength(1);
|
||||||
public int Offset { get; set; }
|
public int Height => matrix.GetLength(0);
|
||||||
|
public byte Offset { get; set; }
|
||||||
|
|
||||||
public ConvolutionMatrix() : this(3)
|
public ConvolutionMatrix() : this(3)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConvolutionMatrix(int size)
|
public ConvolutionMatrix(int size) : this(size, size)
|
||||||
{
|
{
|
||||||
Size = size;
|
|
||||||
Matrix = new int[Size, Size];
|
|
||||||
Factor = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetAll(int value)
|
public ConvolutionMatrix(int height, int width)
|
||||||
{
|
{
|
||||||
for (int y = 0; y < Size; y++)
|
matrix = new double[height, width];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetAll(double value)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < Height; y++)
|
||||||
{
|
{
|
||||||
for (int x = 0; x < Size; x++)
|
for (int x = 0; x < Width; x++)
|
||||||
{
|
{
|
||||||
Matrix[x, y] = value;
|
matrix[y, x] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ref double this[int y, int x] => ref matrix[y, x];
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
#endregion License Information (GPL v3)
|
#endregion License Information (GPL v3)
|
||||||
|
|
||||||
|
// Adapted from https://stackoverflow.com/questions/33569396/correctly-implement-a-2-pass-gaussian-blur
|
||||||
// Filters: http://www.codeproject.com/Articles/2008/Image-Processing-for-Dummies-with-C-and-GDI-Part-2
|
// Filters: http://www.codeproject.com/Articles/2008/Image-Processing-for-Dummies-with-C-and-GDI-Part-2
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
@ -33,83 +34,57 @@ namespace ShareX.HelpersLib
|
||||||
{
|
{
|
||||||
public static class ConvolutionMatrixManager
|
public static class ConvolutionMatrixManager
|
||||||
{
|
{
|
||||||
public static Image Apply(this ConvolutionMatrix matrix, Image img)
|
public static Image Apply(this ConvolutionMatrix kernel, Image img)
|
||||||
{
|
{
|
||||||
int factor = Math.Max(matrix.Factor, 1);
|
|
||||||
|
|
||||||
Bitmap result = (Bitmap)img.Clone();
|
Bitmap result = (Bitmap)img.Clone();
|
||||||
|
|
||||||
using (UnsafeBitmap source = new UnsafeBitmap((Bitmap)img, true, ImageLockMode.ReadOnly))
|
using (UnsafeBitmap source = new UnsafeBitmap((Bitmap)img, true, ImageLockMode.ReadOnly))
|
||||||
using (UnsafeBitmap dest = new UnsafeBitmap(result, true, ImageLockMode.WriteOnly))
|
using (UnsafeBitmap dest = new UnsafeBitmap(result, true, ImageLockMode.WriteOnly))
|
||||||
{
|
{
|
||||||
int height = source.Height - 2;
|
int originX = (kernel.Width - 1) / 2;
|
||||||
int width = source.Width - 2;
|
int originY = (kernel.Height - 1) / 2;
|
||||||
ColorBgra[,] pixelColor = new ColorBgra[3, 3];
|
|
||||||
int pixel;
|
|
||||||
ColorBgra color = new ColorBgra();
|
|
||||||
|
|
||||||
for (int y = 0; y < height; y++)
|
for (int y = 0; y < source.Height; y++)
|
||||||
{
|
{
|
||||||
for (int x = 0; x < width; x++)
|
for (int x = 0; x < source.Width; x++)
|
||||||
{
|
{
|
||||||
pixelColor[0, 0] = source.GetPixel(x, y);
|
double r = 0.0;
|
||||||
pixelColor[0, 1] = source.GetPixel(x, y + 1);
|
double g = 0.0;
|
||||||
pixelColor[0, 2] = source.GetPixel(x, y + 2);
|
double b = 0.0;
|
||||||
pixelColor[1, 0] = source.GetPixel(x + 1, y);
|
|
||||||
pixelColor[1, 1] = source.GetPixel(x + 1, y + 1);
|
|
||||||
pixelColor[1, 2] = source.GetPixel(x + 1, y + 2);
|
|
||||||
pixelColor[2, 0] = source.GetPixel(x + 2, y);
|
|
||||||
pixelColor[2, 1] = source.GetPixel(x + 2, y + 1);
|
|
||||||
pixelColor[2, 2] = source.GetPixel(x + 2, y + 2);
|
|
||||||
|
|
||||||
pixel = (((pixelColor[0, 0].Blue * matrix.Matrix[0, 0]) +
|
// Apply each matrix multiplier to the color components for each pixel.
|
||||||
(pixelColor[1, 0].Blue * matrix.Matrix[1, 0]) +
|
for (int fy = 0; fy < kernel.Height; fy++)
|
||||||
(pixelColor[2, 0].Blue * matrix.Matrix[2, 0]) +
|
{
|
||||||
(pixelColor[0, 1].Blue * matrix.Matrix[0, 1]) +
|
int fyr = fy - originY;
|
||||||
(pixelColor[1, 1].Blue * matrix.Matrix[1, 1]) +
|
int offsetY = y + fyr;
|
||||||
(pixelColor[2, 1].Blue * matrix.Matrix[2, 1]) +
|
|
||||||
(pixelColor[0, 2].Blue * matrix.Matrix[0, 2]) +
|
|
||||||
(pixelColor[1, 2].Blue * matrix.Matrix[1, 2]) +
|
|
||||||
(pixelColor[2, 2].Blue * matrix.Matrix[2, 2])) / factor) + matrix.Offset;
|
|
||||||
|
|
||||||
if (pixel < 0) pixel = 0;
|
offsetY.Clamp(0, source.Height - 1);
|
||||||
else if (pixel > 255) pixel = 255;
|
|
||||||
|
|
||||||
color.Blue = (byte)pixel;
|
for (int fx = 0; fx < kernel.Width; fx++)
|
||||||
|
{
|
||||||
|
int fxr = fx - originX;
|
||||||
|
int offsetX = x + fxr;
|
||||||
|
|
||||||
pixel = (((pixelColor[0, 0].Green * matrix.Matrix[0, 0]) +
|
offsetX.Clamp(0, source.Width - 1);
|
||||||
(pixelColor[1, 0].Green * matrix.Matrix[1, 0]) +
|
|
||||||
(pixelColor[2, 0].Green * matrix.Matrix[2, 0]) +
|
|
||||||
(pixelColor[0, 1].Green * matrix.Matrix[0, 1]) +
|
|
||||||
(pixelColor[1, 1].Green * matrix.Matrix[1, 1]) +
|
|
||||||
(pixelColor[2, 1].Green * matrix.Matrix[2, 1]) +
|
|
||||||
(pixelColor[0, 2].Green * matrix.Matrix[0, 2]) +
|
|
||||||
(pixelColor[1, 2].Green * matrix.Matrix[1, 2]) +
|
|
||||||
(pixelColor[2, 2].Green * matrix.Matrix[2, 2])) / factor) + matrix.Offset;
|
|
||||||
|
|
||||||
if (pixel < 0) pixel = 0;
|
ColorBgra currentColor = source.GetPixel(offsetX, offsetY);
|
||||||
else if (pixel > 255) pixel = 255;
|
|
||||||
|
|
||||||
color.Green = (byte)pixel;
|
r += kernel[fy, fx] * currentColor.Red;
|
||||||
|
g += kernel[fy, fx] * currentColor.Green;
|
||||||
|
b += kernel[fy, fx] * currentColor.Blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pixel = (((pixelColor[0, 0].Red * matrix.Matrix[0, 0]) +
|
r += kernel.Offset;
|
||||||
(pixelColor[1, 0].Red * matrix.Matrix[1, 0]) +
|
r.Clamp(0, 255);
|
||||||
(pixelColor[2, 0].Red * matrix.Matrix[2, 0]) +
|
|
||||||
(pixelColor[0, 1].Red * matrix.Matrix[0, 1]) +
|
|
||||||
(pixelColor[1, 1].Red * matrix.Matrix[1, 1]) +
|
|
||||||
(pixelColor[2, 1].Red * matrix.Matrix[2, 1]) +
|
|
||||||
(pixelColor[0, 2].Red * matrix.Matrix[0, 2]) +
|
|
||||||
(pixelColor[1, 2].Red * matrix.Matrix[1, 2]) +
|
|
||||||
(pixelColor[2, 2].Red * matrix.Matrix[2, 2])) / factor) + matrix.Offset;
|
|
||||||
|
|
||||||
if (pixel < 0) pixel = 0;
|
g += kernel.Offset;
|
||||||
else if (pixel > 255) pixel = 255;
|
g.Clamp(0, 255);
|
||||||
|
|
||||||
color.Red = (byte)pixel;
|
b += kernel.Offset;
|
||||||
|
b.Clamp(0, 255);
|
||||||
|
|
||||||
color.Alpha = pixelColor[1, 1].Alpha;
|
dest.SetPixel(x, y, new ColorBgra((byte)b, (byte)g, (byte)r, source.GetPixel(x, y).Alpha));
|
||||||
|
|
||||||
dest.SetPixel(x + 1, y + 1, color);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,38 +95,67 @@ public static Image Apply(this ConvolutionMatrix matrix, Image img)
|
||||||
public static ConvolutionMatrix Smooth(int weight = 1)
|
public static ConvolutionMatrix Smooth(int weight = 1)
|
||||||
{
|
{
|
||||||
ConvolutionMatrix cm = new ConvolutionMatrix();
|
ConvolutionMatrix cm = new ConvolutionMatrix();
|
||||||
cm.SetAll(1);
|
double factor = weight + 8;
|
||||||
cm.Matrix[1, 1] = weight;
|
cm.SetAll(1 / factor);
|
||||||
cm.Factor = weight + 8;
|
cm[1, 1] = weight / factor;
|
||||||
return cm;
|
return cm;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ConvolutionMatrix GaussianBlur(int weight = 4)
|
private static double GaussianFunction(double x, double sigma)
|
||||||
{
|
{
|
||||||
ConvolutionMatrix cm = new ConvolutionMatrix();
|
double left = 1.0 / (Math.Sqrt(2 * Math.PI) * sigma);
|
||||||
cm.SetAll(1);
|
|
||||||
cm.Matrix[1, 1] = weight;
|
double exponentNumerator = -x * x;
|
||||||
cm.Matrix[1, 0] = cm.Matrix[0, 1] = cm.Matrix[2, 1] = cm.Matrix[1, 2] = 2;
|
double exponentDenominator = 2 * Math.Pow(sigma, 2);
|
||||||
cm.Factor = weight + 12;
|
double right = Math.Exp(exponentNumerator / exponentDenominator);
|
||||||
|
|
||||||
|
return left * right;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ConvolutionMatrix GaussianBlur(int height, int width, double sigma)
|
||||||
|
{
|
||||||
|
ConvolutionMatrix cm = new ConvolutionMatrix(height, width);
|
||||||
|
|
||||||
|
double sum = 0.0;
|
||||||
|
double midpointX = (width - 1) / 2.0;
|
||||||
|
double midpointY = (height - 1) / 2.0;
|
||||||
|
|
||||||
|
for (int y = 0; y < height; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
sum += cm[y, x] = GaussianFunction(x - midpointX, sigma) * GaussianFunction(y - midpointY, sigma);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalise kernel so that the sum of all weights equals 1
|
||||||
|
for (int y = 0; y < height; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
cm[y, x] /= sum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return cm;
|
return cm;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ConvolutionMatrix MeanRemoval(int weight = 9)
|
public static ConvolutionMatrix MeanRemoval(int weight = 9)
|
||||||
{
|
{
|
||||||
ConvolutionMatrix cm = new ConvolutionMatrix();
|
ConvolutionMatrix cm = new ConvolutionMatrix();
|
||||||
cm.SetAll(-1);
|
double factor = weight - 8;
|
||||||
cm.Matrix[1, 1] = weight;
|
cm.SetAll(-1 / factor);
|
||||||
cm.Factor = weight - 8;
|
cm[1, 1] = weight / factor;
|
||||||
return cm;
|
return cm;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ConvolutionMatrix Sharpen(int weight = 11)
|
public static ConvolutionMatrix Sharpen(int weight = 11)
|
||||||
{
|
{
|
||||||
ConvolutionMatrix cm = new ConvolutionMatrix();
|
ConvolutionMatrix cm = new ConvolutionMatrix();
|
||||||
|
double factor = weight - 8;
|
||||||
cm.SetAll(0);
|
cm.SetAll(0);
|
||||||
cm.Matrix[1, 1] = weight;
|
cm[1, 1] = weight / factor;
|
||||||
cm.Matrix[1, 0] = cm.Matrix[0, 1] = cm.Matrix[2, 1] = cm.Matrix[1, 2] = -2;
|
cm[1, 0] = cm[0, 1] = cm[2, 1] = cm[1, 2] = -2 / factor;
|
||||||
cm.Factor = weight - 8;
|
|
||||||
return cm;
|
return cm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,8 +163,8 @@ public static ConvolutionMatrix Emboss()
|
||||||
{
|
{
|
||||||
ConvolutionMatrix cm = new ConvolutionMatrix();
|
ConvolutionMatrix cm = new ConvolutionMatrix();
|
||||||
cm.SetAll(-1);
|
cm.SetAll(-1);
|
||||||
cm.Matrix[1, 1] = 4;
|
cm[1, 1] = 4;
|
||||||
cm.Matrix[1, 0] = cm.Matrix[0, 1] = cm.Matrix[2, 1] = cm.Matrix[1, 2] = 0;
|
cm[1, 0] = cm[0, 1] = cm[2, 1] = cm[1, 2] = 0;
|
||||||
cm.Offset = 127;
|
cm.Offset = 127;
|
||||||
return cm;
|
return cm;
|
||||||
}
|
}
|
||||||
|
@ -168,9 +172,9 @@ public static ConvolutionMatrix Emboss()
|
||||||
public static ConvolutionMatrix EdgeDetect()
|
public static ConvolutionMatrix EdgeDetect()
|
||||||
{
|
{
|
||||||
ConvolutionMatrix cm = new ConvolutionMatrix();
|
ConvolutionMatrix cm = new ConvolutionMatrix();
|
||||||
cm.Matrix[0, 0] = cm.Matrix[1, 0] = cm.Matrix[2, 0] = -1;
|
cm[0, 0] = cm[0, 1] = cm[0, 2] = -1;
|
||||||
cm.Matrix[0, 1] = cm.Matrix[1, 1] = cm.Matrix[2, 1] = 0;
|
cm[1, 0] = cm[1, 1] = cm[1, 2] = 0;
|
||||||
cm.Matrix[0, 2] = cm.Matrix[1, 2] = cm.Matrix[2, 2] = 1;
|
cm[2, 0] = cm[2, 1] = cm[2, 2] = 1;
|
||||||
cm.Offset = 127;
|
cm.Offset = 127;
|
||||||
return cm;
|
return cm;
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,5 +149,10 @@ public static bool IsEvenNumber(this int num)
|
||||||
{
|
{
|
||||||
return num % 2 == 0;
|
return num % 2 == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Clamp<T>(ref this T val, T min, T max) where T : struct, IComparable<T>
|
||||||
|
{
|
||||||
|
MathHelpers.Clamp(ref val, min, max);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -185,5 +185,23 @@ public static Vector2 Lerp(Vector2 pos1, Vector2 pos2, float amount)
|
||||||
float y = Lerp(pos1.Y, pos2.Y, amount);
|
float y = Lerp(pos1.Y, pos2.Y, amount);
|
||||||
return new Vector2(x, y);
|
return new Vector2(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Clamp<T>(ref T val, T min, T max) where T : IComparable<T>
|
||||||
|
{
|
||||||
|
if (val.CompareTo(min) < 0)
|
||||||
|
{
|
||||||
|
val = min;
|
||||||
|
}
|
||||||
|
else if (val.CompareTo(max) > 0)
|
||||||
|
{
|
||||||
|
val = max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T Clamp<T>(T val, T min, T max) where T : IComparable<T>
|
||||||
|
{
|
||||||
|
Clamp(ref val, min, max);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -33,6 +33,7 @@
|
||||||
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
||||||
<Prefer32Bit>false</Prefer32Bit>
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<LangVersion>7.2</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
<DebugType>none</DebugType>
|
<DebugType>none</DebugType>
|
||||||
|
@ -48,6 +49,7 @@
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
|
||||||
<DebugSymbols>false</DebugSymbols>
|
<DebugSymbols>false</DebugSymbols>
|
||||||
|
<LangVersion>7.2</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Steam|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Steam|AnyCPU'">
|
||||||
<OutputPath>bin\Steam\</OutputPath>
|
<OutputPath>bin\Steam\</OutputPath>
|
||||||
|
@ -59,6 +61,7 @@
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
<Prefer32Bit>false</Prefer32Bit>
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
<LangVersion>7.2</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'WindowsStore|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'WindowsStore|AnyCPU'">
|
||||||
<OutputPath>bin\WindowsStore\</OutputPath>
|
<OutputPath>bin\WindowsStore\</OutputPath>
|
||||||
|
@ -70,6 +73,7 @@
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
<Prefer32Bit>false</Prefer32Bit>
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
<LangVersion>7.2</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'WindowsStoreDebug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'WindowsStoreDebug|AnyCPU'">
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
@ -82,6 +86,7 @@
|
||||||
<ErrorReport>prompt</ErrorReport>
|
<ErrorReport>prompt</ErrorReport>
|
||||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
<Prefer32Bit>false</Prefer32Bit>
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
<LangVersion>7.2</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#endregion License Information (GPL v3)
|
#endregion License Information (GPL v3)
|
||||||
|
|
||||||
using ShareX.HelpersLib;
|
using ShareX.HelpersLib;
|
||||||
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
|
||||||
|
@ -32,11 +33,50 @@ namespace ShareX.ImageEffectsLib
|
||||||
[Description("Gaussian blur")]
|
[Description("Gaussian blur")]
|
||||||
internal class GaussianBlur : ImageEffect
|
internal class GaussianBlur : ImageEffect
|
||||||
{
|
{
|
||||||
|
private double sigma;
|
||||||
|
private int size;
|
||||||
|
|
||||||
|
[DefaultValue(0.7955555)]
|
||||||
|
public double Sigma
|
||||||
|
{
|
||||||
|
get => sigma;
|
||||||
|
set => sigma = Math.Max(value, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DefaultValue(3)]
|
||||||
|
public int Size
|
||||||
|
{
|
||||||
|
get => size;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
size = value.Min(1);
|
||||||
|
|
||||||
|
if (size.IsEvenNumber())
|
||||||
|
{
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GaussianBlur()
|
||||||
|
{
|
||||||
|
this.ApplyDefaultPropertyValues();
|
||||||
|
}
|
||||||
|
|
||||||
public override Image Apply(Image img)
|
public override Image Apply(Image img)
|
||||||
{
|
{
|
||||||
using (img)
|
ConvolutionMatrix kernelHoriz = ConvolutionMatrixManager.GaussianBlur(1, size, sigma);
|
||||||
|
|
||||||
|
ConvolutionMatrix kernelVert = new ConvolutionMatrix(size, 1);
|
||||||
|
for (int i = 0; i < size; i++)
|
||||||
{
|
{
|
||||||
return ConvolutionMatrixManager.GaussianBlur().Apply(img);
|
kernelVert[i, 0] = kernelHoriz[0, i];
|
||||||
|
}
|
||||||
|
|
||||||
|
using (img)
|
||||||
|
using (Image horizPass = kernelHoriz.Apply(img))
|
||||||
|
{
|
||||||
|
return kernelVert.Apply(horizPass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,11 +53,11 @@ internal class MatrixConvolution : ImageEffect
|
||||||
[DefaultValue(0)]
|
[DefaultValue(0)]
|
||||||
public int X2Y2 { get; set; }
|
public int X2Y2 { get; set; }
|
||||||
|
|
||||||
[DefaultValue(1)]
|
[DefaultValue(1.0)]
|
||||||
public int Factor { get; set; }
|
public double Factor { get; set; }
|
||||||
|
|
||||||
[DefaultValue(0)]
|
[DefaultValue(0)]
|
||||||
public int Offset { get; set; }
|
public byte Offset { get; set; }
|
||||||
|
|
||||||
public MatrixConvolution()
|
public MatrixConvolution()
|
||||||
{
|
{
|
||||||
|
@ -69,16 +69,15 @@ public override Image Apply(Image img)
|
||||||
using (img)
|
using (img)
|
||||||
{
|
{
|
||||||
ConvolutionMatrix cm = new ConvolutionMatrix();
|
ConvolutionMatrix cm = new ConvolutionMatrix();
|
||||||
cm.Matrix[0, 0] = X0Y0;
|
cm[0, 0] = X0Y0 / Factor;
|
||||||
cm.Matrix[1, 0] = X1Y0;
|
cm[0, 1] = X1Y0 / Factor;
|
||||||
cm.Matrix[2, 0] = X2Y0;
|
cm[0, 2] = X2Y0 / Factor;
|
||||||
cm.Matrix[0, 1] = X0Y1;
|
cm[1, 0] = X0Y1 / Factor;
|
||||||
cm.Matrix[1, 1] = X1Y1;
|
cm[1, 1] = X1Y1 / Factor;
|
||||||
cm.Matrix[2, 1] = X2Y1;
|
cm[1, 2] = X2Y1 / Factor;
|
||||||
cm.Matrix[0, 2] = X0Y2;
|
cm[2, 0] = X0Y2 / Factor;
|
||||||
cm.Matrix[1, 2] = X1Y2;
|
cm[2, 1] = X1Y2 / Factor;
|
||||||
cm.Matrix[2, 2] = X2Y2;
|
cm[2, 2] = X2Y2 / Factor;
|
||||||
cm.Factor = Factor;
|
|
||||||
cm.Offset = Offset;
|
cm.Offset = Offset;
|
||||||
return cm.Apply(img);
|
return cm.Apply(img);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue