diff --git a/src/ImageSharp.Processing/Convolution/BoxBlur.cs b/src/ImageSharp.Processing/Convolution/BoxBlur.cs
index a68c2fa44d..6bdd68b9b6 100644
--- a/src/ImageSharp.Processing/Convolution/BoxBlur.cs
+++ b/src/ImageSharp.Processing/Convolution/BoxBlur.cs
@@ -7,7 +7,6 @@ namespace ImageSharp
{
using System;
- using Processing;
using Processing.Processors;
///
@@ -41,7 +40,7 @@ namespace ImageSharp
public static Image BoxBlur(this Image source, int radius, Rectangle rectangle)
where TColor : struct, IPackedPixel, IEquatable
{
- source.ApplyProcessor(new BoxBlurProcessor(), rectangle);
+ source.ApplyProcessor(new BoxBlurProcessor(radius), rectangle);
return source;
}
}
diff --git a/src/ImageSharp.Processing/Processors/Convolution/BoxBlurProcessor.cs b/src/ImageSharp.Processing/Processors/Convolution/BoxBlurProcessor.cs
index 272b3cc8b4..a9caea5559 100644
--- a/src/ImageSharp.Processing/Processors/Convolution/BoxBlurProcessor.cs
+++ b/src/ImageSharp.Processing/Processors/Convolution/BoxBlurProcessor.cs
@@ -35,12 +35,12 @@ namespace ImageSharp.Processing.Processors
///
/// Gets the horizontal gradient operator.
///
- public float[][] KernelX { get; }
+ public Fast2DArray KernelX { get; }
///
/// Gets the vertical gradient operator.
///
- public float[][] KernelY { get; }
+ public Fast2DArray KernelY { get; }
///
protected override void OnApply(ImageBase source, Rectangle sourceRectangle)
@@ -52,46 +52,42 @@ namespace ImageSharp.Processing.Processors
/// Create a 1 dimensional Box kernel.
///
/// Whether to calculate a horizontal kernel.
- /// The
- private float[][] CreateBoxKernel(bool horizontal)
+ /// The
+ private Fast2DArray CreateBoxKernel(bool horizontal)
{
int size = this.kernelSize;
- float[][] kernel = horizontal ? new float[1][] : new float[size][];
-
- if (horizontal)
- {
- kernel[0] = new float[size];
- }
-
- float sum = 0.0f;
+ Fast2DArray kernel = horizontal
+ ? new Fast2DArray(size, 1)
+ : new Fast2DArray(1, size);
+ float sum = 0F;
for (int i = 0; i < size; i++)
{
float x = 1;
sum += x;
if (horizontal)
{
- kernel[0][i] = x;
+ kernel[0, i] = x;
}
else
{
- kernel[i] = new[] { x };
+ kernel[i, 0] = x;
}
}
- // Normalise kernel so that the sum of all weights equals 1
+ // Normalize kernel so that the sum of all weights equals 1
if (horizontal)
{
for (int i = 0; i < size; i++)
{
- kernel[0][i] = kernel[0][i] / sum;
+ kernel[0, i] = kernel[0, i] / sum;
}
}
else
{
for (int i = 0; i < size; i++)
{
- kernel[i][0] = kernel[i][0] / sum;
+ kernel[i, 0] = kernel[i, 0] / sum;
}
}
diff --git a/src/ImageSharp.Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp.Processing/Processors/Convolution/Convolution2DProcessor.cs
index cdea43e854..71b71ba5d2 100644
--- a/src/ImageSharp.Processing/Processors/Convolution/Convolution2DProcessor.cs
+++ b/src/ImageSharp.Processing/Processors/Convolution/Convolution2DProcessor.cs
@@ -21,7 +21,7 @@ namespace ImageSharp.Processing.Processors
///
/// The horizontal gradient operator.
/// The vertical gradient operator.
- public Convolution2DProcessor(float[][] kernelX, float[][] kernelY)
+ public Convolution2DProcessor(Fast2DArray kernelX, Fast2DArray kernelY)
{
this.KernelX = kernelX;
this.KernelY = kernelY;
@@ -30,20 +30,20 @@ namespace ImageSharp.Processing.Processors
///
/// Gets the horizontal gradient operator.
///
- public float[][] KernelX { get; }
+ public Fast2DArray KernelX { get; }
///
/// Gets the vertical gradient operator.
///
- public float[][] KernelY { get; }
+ public Fast2DArray KernelY { get; }
///
protected override void OnApply(ImageBase source, Rectangle sourceRectangle)
{
- int kernelYHeight = this.KernelY.Length;
- int kernelYWidth = this.KernelY[0].Length;
- int kernelXHeight = this.KernelX.Length;
- int kernelXWidth = this.KernelX[0].Length;
+ int kernelYHeight = this.KernelY.Height;
+ int kernelYWidth = this.KernelY.Width;
+ int kernelXHeight = this.KernelX.Height;
+ int kernelXWidth = this.KernelX.Width;
int radiusY = kernelYHeight >> 1;
int radiusX = kernelXWidth >> 1;
@@ -89,22 +89,21 @@ namespace ImageSharp.Processing.Processors
offsetX = offsetX.Clamp(0, maxX);
Vector4 currentColor = sourcePixels[offsetX, offsetY].ToVector4();
- float r = currentColor.X;
- float g = currentColor.Y;
- float b = currentColor.Z;
if (fy < kernelXHeight)
{
- rX += this.KernelX[fy][fx] * r;
- gX += this.KernelX[fy][fx] * g;
- bX += this.KernelX[fy][fx] * b;
+ Vector4 kx = this.KernelX[fy, fx] * currentColor;
+ rX += kx.X;
+ gX += kx.Y;
+ bX += kx.Z;
}
if (fx < kernelYWidth)
{
- rY += this.KernelY[fy][fx] * r;
- gY += this.KernelY[fy][fx] * g;
- bY += this.KernelY[fy][fx] * b;
+ Vector4 ky = this.KernelY[fy, fx] * currentColor;
+ rY += ky.X;
+ gY += ky.Y;
+ bY += ky.Z;
}
}
}
diff --git a/src/ImageSharp.Processing/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp.Processing/Processors/Convolution/Convolution2PassProcessor.cs
index 71b8062617..495bfa5dba 100644
--- a/src/ImageSharp.Processing/Processors/Convolution/Convolution2PassProcessor.cs
+++ b/src/ImageSharp.Processing/Processors/Convolution/Convolution2PassProcessor.cs
@@ -14,14 +14,14 @@ namespace ImageSharp.Processing.Processors
///
/// The pixel format.
public class Convolution2PassProcessor : ImageProcessor
- where TColor : struct, IPackedPixel, IEquatable
+ where TColor : struct, IPackedPixel, IEquatable
{
///
/// Initializes a new instance of the class.
///
/// The horizontal gradient operator.
/// The vertical gradient operator.
- public Convolution2PassProcessor(float[][] kernelX, float[][] kernelY)
+ public Convolution2PassProcessor(Fast2DArray kernelX, Fast2DArray kernelY)
{
this.KernelX = kernelX;
this.KernelY = kernelY;
@@ -30,18 +30,16 @@ namespace ImageSharp.Processing.Processors
///
/// Gets the horizontal gradient operator.
///
- public float[][] KernelX { get; }
+ public Fast2DArray KernelX { get; }
///
/// Gets the vertical gradient operator.
///
- public float[][] KernelY { get; }
+ public Fast2DArray KernelY { get; }
///
protected override void OnApply(ImageBase source, Rectangle sourceRectangle)
{
- float[][] kernelX = this.KernelX;
- float[][] kernelY = this.KernelY;
int width = source.Width;
int height = source.Height;
@@ -50,8 +48,8 @@ namespace ImageSharp.Processing.Processors
using (PixelAccessor firstPassPixels = new PixelAccessor(width, height))
using (PixelAccessor sourcePixels = source.Lock())
{
- this.ApplyConvolution(width, height, firstPassPixels, sourcePixels, sourceRectangle, kernelX);
- this.ApplyConvolution(width, height, targetPixels, firstPassPixels, sourceRectangle, kernelY);
+ this.ApplyConvolution(firstPassPixels, sourcePixels, sourceRectangle, this.KernelX);
+ this.ApplyConvolution(targetPixels, firstPassPixels, sourceRectangle, this.KernelY);
}
source.SwapPixelsBuffers(targetPixels);
@@ -62,18 +60,16 @@ namespace ImageSharp.Processing.Processors
/// Applies the process to the specified portion of the specified at the specified location
/// and with the specified size.
///
- /// The image width.
- /// The image height.
/// The target pixels to apply the process to.
/// The source pixels. Cannot be null.
///
/// The structure that specifies the portion of the image object to draw.
///
/// The kernel operator.
- private void ApplyConvolution(int width, int height, PixelAccessor targetPixels, PixelAccessor sourcePixels, Rectangle sourceRectangle, float[][] kernel)
+ private void ApplyConvolution(PixelAccessor targetPixels, PixelAccessor sourcePixels, Rectangle sourceRectangle, Fast2DArray kernel)
{
- int kernelHeight = kernel.Length;
- int kernelWidth = kernel[0].Length;
+ int kernelHeight = kernel.Height;
+ int kernelWidth = kernel.Width;
int radiusY = kernelHeight >> 1;
int radiusX = kernelWidth >> 1;
@@ -85,40 +81,40 @@ namespace ImageSharp.Processing.Processors
int maxX = endX - 1;
Parallel.For(
- startY,
- endY,
- this.ParallelOptions,
- y =>
- {
- for (int x = startX; x < endX; x++)
+ startY,
+ endY,
+ this.ParallelOptions,
+ y =>
{
- Vector4 destination = default(Vector4);
-
- // Apply each matrix multiplier to the color components for each pixel.
- for (int fy = 0; fy < kernelHeight; fy++)
+ for (int x = startX; x < endX; x++)
{
- int fyr = fy - radiusY;
- int offsetY = y + fyr;
+ Vector4 destination = default(Vector4);
- offsetY = offsetY.Clamp(0, maxY);
-
- for (int fx = 0; fx < kernelWidth; fx++)
+ // Apply each matrix multiplier to the color components for each pixel.
+ for (int fy = 0; fy < kernelHeight; fy++)
{
- int fxr = fx - radiusX;
- int offsetX = x + fxr;
+ int fyr = fy - radiusY;
+ int offsetY = y + fyr;
+
+ offsetY = offsetY.Clamp(0, maxY);
- offsetX = offsetX.Clamp(0, maxX);
+ for (int fx = 0; fx < kernelWidth; fx++)
+ {
+ int fxr = fx - radiusX;
+ int offsetX = x + fxr;
- Vector4 currentColor = sourcePixels[offsetX, offsetY].ToVector4();
- destination += kernel[fy][fx] * currentColor;
+ offsetX = offsetX.Clamp(0, maxX);
+
+ Vector4 currentColor = sourcePixels[offsetX, offsetY].ToVector4();
+ destination += kernel[fy, fx] * currentColor;
+ }
}
- }
- TColor packed = default(TColor);
- packed.PackFromVector4(destination);
- targetPixels[x, y] = packed;
- }
- });
+ TColor packed = default(TColor);
+ packed.PackFromVector4(destination);
+ targetPixels[x, y] = packed;
+ }
+ });
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp.Processing/Processors/Convolution/ConvolutionProcessor.cs b/src/ImageSharp.Processing/Processors/Convolution/ConvolutionProcessor.cs
index aa49401926..46df9c6eea 100644
--- a/src/ImageSharp.Processing/Processors/Convolution/ConvolutionProcessor.cs
+++ b/src/ImageSharp.Processing/Processors/Convolution/ConvolutionProcessor.cs
@@ -14,13 +14,13 @@ namespace ImageSharp.Processing.Processors
///
/// The pixel format.
public class ConvolutionProcessor : ImageProcessor
- where TColor : struct, IPackedPixel, IEquatable
+ where TColor : struct, IPackedPixel, IEquatable
{
///
/// Initializes a new instance of the class.
///
/// The 2d gradient operator.
- public ConvolutionProcessor(float[][] kernelXY)
+ public ConvolutionProcessor(Fast2DArray kernelXY)
{
this.KernelXY = kernelXY;
}
@@ -28,13 +28,12 @@ namespace ImageSharp.Processing.Processors
///
/// Gets the 2d gradient operator.
///
- public virtual float[][] KernelXY { get; }
+ public Fast2DArray KernelXY { get; }
///
protected override void OnApply(ImageBase source, Rectangle sourceRectangle)
{
- float[][] kernelX = this.KernelXY;
- int kernelLength = kernelX.GetLength(0);
+ int kernelLength = this.KernelXY.Height;
int radius = kernelLength >> 1;
int startY = sourceRectangle.Y;
@@ -56,9 +55,9 @@ namespace ImageSharp.Processing.Processors
{
for (int x = startX; x < endX; x++)
{
- float rX = 0;
- float gX = 0;
- float bX = 0;
+ float red = 0;
+ float green = 0;
+ float blue = 0;
// Apply each matrix multiplier to the color components for each pixel.
for (int fy = 0; fy < kernelLength; fy++)
@@ -76,20 +75,14 @@ namespace ImageSharp.Processing.Processors
offsetX = offsetX.Clamp(0, maxX);
Vector4 currentColor = sourcePixels[offsetX, offsetY].ToVector4();
- float r = currentColor.X;
- float g = currentColor.Y;
- float b = currentColor.Z;
+ currentColor *= this.KernelXY[fy, fx];
- rX += kernelX[fy][fx] * r;
- gX += kernelX[fy][fx] * g;
- bX += kernelX[fy][fx] * b;
+ red += currentColor.X;
+ green += currentColor.Y;
+ blue += currentColor.Z;
}
}
- float red = rX;
- float green = gX;
- float blue = bX;
-
TColor packed = default(TColor);
packed.PackFromVector4(new Vector4(red, green, blue, sourcePixels[x, y].ToVector4().W));
targetPixels[x, y] = packed;
diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs
index 6ee5d0f96a..f86940adef 100644
--- a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs
+++ b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs
@@ -14,15 +14,26 @@ namespace ImageSharp.Processing.Processors
public abstract class EdgeDetector2DProcessor : ImageProcessor, IEdgeDetectorProcessor
where TColor : struct, IPackedPixel, IEquatable
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The horizontal gradient operator.
+ /// The vertical gradient operator.
+ protected EdgeDetector2DProcessor(Fast2DArray kernelX, Fast2DArray kernelY)
+ {
+ this.KernelX = kernelX;
+ this.KernelY = kernelY;
+ }
+
///
/// Gets the horizontal gradient operator.
///
- public abstract float[][] KernelX { get; }
+ public Fast2DArray KernelX { get; }
///
/// Gets the vertical gradient operator.
///
- public abstract float[][] KernelY { get; }
+ public Fast2DArray KernelY { get; }
///
public bool Grayscale { get; set; }
diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs
index 1a88dbe345..58967cb5b1 100644
--- a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs
+++ b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs
@@ -19,50 +19,59 @@ namespace ImageSharp.Processing.Processors
///
/// Gets the North gradient operator
///
- public abstract float[][] North { get; }
+ public abstract Fast2DArray North { get; }
///
/// Gets the NorthWest gradient operator
///
- public abstract float[][] NorthWest { get; }
+ public abstract Fast2DArray NorthWest { get; }
///
/// Gets the West gradient operator
///
- public abstract float[][] West { get; }
+ public abstract Fast2DArray West { get; }
///
/// Gets the SouthWest gradient operator
///
- public abstract float[][] SouthWest { get; }
+ public abstract Fast2DArray SouthWest { get; }
///
/// Gets the South gradient operator
///
- public abstract float[][] South { get; }
+ public abstract Fast2DArray South { get; }
///
/// Gets the SouthEast gradient operator
///
- public abstract float[][] SouthEast { get; }
+ public abstract Fast2DArray SouthEast { get; }
///
/// Gets the East gradient operator
///
- public abstract float[][] East { get; }
+ public abstract Fast2DArray East { get; }
///
/// Gets the NorthEast gradient operator
///
- public abstract float[][] NorthEast { get; }
+ public abstract Fast2DArray NorthEast { get; }
///
public bool Grayscale { get; set; }
+ ///
+ protected override void BeforeApply(ImageBase source, Rectangle sourceRectangle)
+ {
+ if (this.Grayscale)
+ {
+ new GrayscaleBt709Processor().Apply(source, sourceRectangle);
+ }
+ }
+
///
protected override void OnApply(ImageBase source, Rectangle sourceRectangle)
{
- float[][][] kernels = { this.North, this.NorthWest, this.West, this.SouthWest, this.South, this.SouthEast, this.East, this.NorthEast };
+ Fast2DArray[] kernels = { this.North, this.NorthWest, this.West, this.SouthWest, this.South, this.SouthEast, this.East, this.NorthEast };
int startY = sourceRectangle.Y;
int endY = sourceRectangle.Bottom;
@@ -132,14 +141,5 @@ namespace ImageSharp.Processing.Processors
}
}
}
-
- ///
- protected override void BeforeApply(ImageBase source, Rectangle sourceRectangle)
- {
- if (this.Grayscale)
- {
- new GrayscaleBt709Processor().Apply(source, sourceRectangle);
- }
- }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs
index 1033111fcb..cd2b91f167 100644
--- a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs
+++ b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs
@@ -14,19 +14,22 @@ namespace ImageSharp.Processing.Processors
public abstract class EdgeDetectorProcessor : ImageProcessor, IEdgeDetectorProcessor
where TColor : struct, IPackedPixel, IEquatable
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The 2d gradient operator.
+ protected EdgeDetectorProcessor(Fast2DArray kernelXY)
+ {
+ this.KernelXY = kernelXY;
+ }
+
///
public bool Grayscale { get; set; }
///
/// Gets the 2d gradient operator.
///
- public abstract float[][] KernelXY { get; }
-
- ///
- protected override void OnApply(ImageBase source, Rectangle sourceRectangle)
- {
- new ConvolutionProcessor(this.KernelXY).Apply(source, sourceRectangle);
- }
+ public Fast2DArray KernelXY { get; }
///
protected override void BeforeApply(ImageBase source, Rectangle sourceRectangle)
@@ -36,5 +39,11 @@ namespace ImageSharp.Processing.Processors
new GrayscaleBt709Processor().Apply(source, sourceRectangle);
}
}
+
+ ///
+ protected override void OnApply(ImageBase source, Rectangle sourceRectangle)
+ {
+ new ConvolutionProcessor(this.KernelXY).Apply(source, sourceRectangle);
+ }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs
index f628ea1b94..bda3c9317a 100644
--- a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs
+++ b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs
@@ -20,27 +20,31 @@ namespace ImageSharp.Processing.Processors
///
/// The horizontal gradient operator.
///
- private static readonly float[][] KayyaliX =
- {
- new float[] { 6, 0, -6 },
- new float[] { 0, 0, 0 },
- new float[] { -6, 0, 6 }
- };
+ private static readonly Fast2DArray KayyaliX =
+ new float[,]
+ {
+ { 6, 0, -6 },
+ { 0, 0, 0 },
+ { -6, 0, 6 }
+ };
///
/// The vertical gradient operator.
///
- private static readonly float[][] KayyaliY =
- {
- new float[] { -6, 0, 6 },
- new float[] { 0, 0, 0 },
- new float[] { 6, 0, -6 }
- };
-
- ///
- public override float[][] KernelX => KayyaliX;
+ private static readonly Fast2DArray KayyaliY =
+ new float[,]
+ {
+ { -6, 0, 6 },
+ { 0, 0, 0 },
+ { 6, 0, -6 }
+ };
- ///
- public override float[][] KernelY => KayyaliY;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public KayyaliProcessor()
+ : base(KayyaliX, KayyaliY)
+ {
+ }
}
}
diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/KirschProcessor.cs b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/KirschProcessor.cs
index 3f7e0a00ee..4a555137eb 100644
--- a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/KirschProcessor.cs
+++ b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/KirschProcessor.cs
@@ -2,6 +2,7 @@
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
//
+
namespace ImageSharp.Processing.Processors
{
using System;
@@ -19,105 +20,113 @@ namespace ImageSharp.Processing.Processors
///
/// The North gradient operator
///
- private static readonly float[][] KirschNorth =
- {
- new float[] { 5, 5, 5 },
- new float[] { -3, 0, -3 },
- new float[] { -3, -3, -3 }
- };
+ private static readonly Fast2DArray KirschNorth =
+ new float[,]
+ {
+ { 5, 5, 5 },
+ { -3, 0, -3 },
+ { -3, -3, -3 }
+ };
///
/// The NorthWest gradient operator
///
- private static readonly float[][] KirschNorthWest =
- {
- new float[] { 5, 5, -3 },
- new float[] { 5, 0, -3 },
- new float[] { -3, -3, -3 }
- };
+ private static readonly Fast2DArray KirschNorthWest =
+ new float[,]
+ {
+ { 5, 5, -3 },
+ { 5, 0, -3 },
+ { -3, -3, -3 }
+ };
///
/// The West gradient operator
///
- private static readonly float[][] KirschWest =
- {
- new float[] { 5, -3, -3 },
- new float[] { 5, 0, -3 },
- new float[] { 5, -3, -3 }
- };
+ private static readonly Fast2DArray KirschWest =
+ new float[,]
+ {
+ { 5, -3, -3 },
+ { 5, 0, -3 },
+ { 5, -3, -3 }
+ };
///
/// The SouthWest gradient operator
///
- private static readonly float[][] KirschSouthWest =
- {
- new float[] { -3, -3, -3 },
- new float[] { 5, 0, -3 },
- new float[] { 5, 5, -3 }
- };
+ private static readonly Fast2DArray KirschSouthWest =
+ new float[,]
+ {
+ { -3, -3, -3 },
+ { 5, 0, -3 },
+ { 5, 5, -3 }
+ };
///
/// The South gradient operator
///
- private static readonly float[][] KirschSouth =
- {
- new float[] { -3, -3, -3 },
- new float[] { -3, 0, -3 },
- new float[] { 5, 5, 5 }
- };
+ private static readonly Fast2DArray KirschSouth =
+ new float[,]
+ {
+ { -3, -3, -3 },
+ { -3, 0, -3 },
+ { 5, 5, 5 }
+ };
///
/// The SouthEast gradient operator
///
- private static readonly float[][] KirschSouthEast =
- {
- new float[] { -3, -3, -3 },
- new float[] { -3, 0, 5 },
- new float[] { -3, 5, 5 }
- };
+ private static readonly Fast2DArray KirschSouthEast =
+ new float[,]
+ {
+ { -3, -3, -3 },
+ { -3, 0, 5 },
+ { -3, 5, 5 }
+ };
///
/// The East gradient operator
///
- private static readonly float[][] KirschEast =
- {
- new float[] { -3, -3, 5 },
- new float[] { -3, 0, 5 },
- new float[] { -3, -3, 5 }
- };
+ private static readonly Fast2DArray KirschEast =
+ new float[,]
+ {
+ { -3, -3, 5 },
+ { -3, 0, 5 },
+ { -3, -3, 5 }
+ };
///
/// The NorthEast gradient operator
///
- private static readonly float[][] KirschNorthEast =
- {
- new float[] { -3, 5, 5 },
- new float[] { -3, 0, 5 },
- new float[] { -3, -3, -3 }
- };
+ private static readonly Fast2DArray KirschNorthEast =
+ new float[,]
+ {
+ { -3, 5, 5 },
+ { -3, 0, 5 },
+ { -3, -3, -3 }
+ };
///
- public override float[][] North => KirschNorth;
+ public override Fast2DArray North => KirschNorth;
///
- public override float[][] NorthWest => KirschNorthWest;
+ public override Fast2DArray NorthWest => KirschNorthWest;
///
- public override float[][] West => KirschWest;
+ public override Fast2DArray West => KirschWest;
///
- public override float[][] SouthWest => KirschSouthWest;
+ public override Fast2DArray SouthWest => KirschSouthWest;
///
- public override float[][] South => KirschSouth;
+ public override Fast2DArray South => KirschSouth;
///
- public override float[][] SouthEast => KirschSouthEast;
+ public override Fast2DArray SouthEast => KirschSouthEast;
///
- public override float[][] East => KirschEast;
+ public override Fast2DArray East => KirschEast;
///
- public override float[][] NorthEast => KirschNorthEast;
+ public override Fast2DArray NorthEast => KirschNorthEast;
}
}
\ No newline at end of file
diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs
index b19c5c7737..74fcfcad55 100644
--- a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs
+++ b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs
@@ -20,14 +20,20 @@ namespace ImageSharp.Processing.Processors
///
/// The 2d gradient operator.
///
- private static readonly float[][] Laplacian3X3XY = new float[][]
- {
- new float[] { -1, -1, -1 },
- new float[] { -1, 8, -1 },
- new float[] { -1, -1, -1 }
- };
+ private static readonly Fast2DArray Laplacian3X3XY =
+ new float[,]
+ {
+ { -1, -1, -1 },
+ { -1, 8, -1 },
+ { -1, -1, -1 }
+ };
- ///
- public override float[][] KernelXY => Laplacian3X3XY;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public Laplacian3X3Processor()
+ : base(Laplacian3X3XY)
+ {
+ }
}
}
diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs
index efa6c28c56..c00831a694 100644
--- a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs
+++ b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs
@@ -20,16 +20,22 @@ namespace ImageSharp.Processing.Processors
///
/// The 2d gradient operator.
///
- private static readonly float[][] Laplacian5X5XY =
- {
- new float[] { -1, -1, -1, -1, -1 },
- new float[] { -1, -1, -1, -1, -1 },
- new float[] { -1, -1, 24, -1, -1 },
- new float[] { -1, -1, -1, -1, -1 },
- new float[] { -1, -1, -1, -1, -1 }
- };
+ private static readonly Fast2DArray Laplacian5X5XY =
+ new float[,]
+ {
+ { -1, -1, -1, -1, -1 },
+ { -1, -1, -1, -1, -1 },
+ { -1, -1, 24, -1, -1 },
+ { -1, -1, -1, -1, -1 },
+ { -1, -1, -1, -1, -1 }
+ };
- ///
- public override float[][] KernelXY => Laplacian5X5XY;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public Laplacian5X5Processor()
+ : base(Laplacian5X5XY)
+ {
+ }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs
index 595ca6a4b0..8ee01047b2 100644
--- a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs
+++ b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs
@@ -20,16 +20,22 @@ namespace ImageSharp.Processing.Processors
///
/// The 2d gradient operator.
///
- private static readonly float[][] LaplacianOfGaussianXY =
- {
- new float[] { 0, 0, -1, 0, 0 },
- new float[] { 0, -1, -2, -1, 0 },
- new float[] { -1, -2, 16, -2, -1 },
- new float[] { 0, -1, -2, -1, 0 },
- new float[] { 0, 0, -1, 0, 0 }
- };
+ private static readonly Fast2DArray LaplacianOfGaussianXY =
+ new float[,]
+ {
+ { 0, 0, -1, 0, 0 },
+ { 0, -1, -2, -1, 0 },
+ { -1, -2, 16, -2, -1 },
+ { 0, -1, -2, -1, 0 },
+ { 0, 0, -1, 0, 0 }
+ };
- ///
- public override float[][] KernelXY => LaplacianOfGaussianXY;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public LaplacianOfGaussianProcessor()
+ : base(LaplacianOfGaussianXY)
+ {
+ }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/PrewittProcessor.cs b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/PrewittProcessor.cs
index 5c48722ef8..cf213e7240 100644
--- a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/PrewittProcessor.cs
+++ b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/PrewittProcessor.cs
@@ -20,27 +20,31 @@ namespace ImageSharp.Processing.Processors
///
/// The horizontal gradient operator.
///
- private static readonly float[][] PrewittX =
- {
- new float[] { -1, 0, 1 },
- new float[] { -1, 0, 1 },
- new float[] { -1, 0, 1 }
- };
+ private static readonly Fast2DArray PrewittX =
+ new float[,]
+ {
+ { -1, 0, 1 },
+ { -1, 0, 1 },
+ { -1, 0, 1 }
+ };
///
/// The vertical gradient operator.
///
- private static readonly float[][] PrewittY =
- {
- new float[] { 1, 1, 1 },
- new float[] { 0, 0, 0 },
- new float[] { -1, -1, -1 }
- };
-
- ///
- public override float[][] KernelX => PrewittX;
+ private static readonly Fast2DArray PrewittY =
+ new float[,]
+ {
+ { 1, 1, 1 },
+ { 0, 0, 0 },
+ { -1, -1, -1 }
+ };
- ///
- public override float[][] KernelY => PrewittY;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public PrewittProcessor()
+ : base(PrewittX, PrewittY)
+ {
+ }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs
index c64ee8abeb..de1f279ea1 100644
--- a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs
+++ b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs
@@ -20,25 +20,29 @@ namespace ImageSharp.Processing.Processors
///
/// The horizontal gradient operator.
///
- private static readonly float[][] RobertsCrossX =
- {
- new float[] { 1, 0 },
- new float[] { 0, -1 }
- };
+ private static readonly Fast2DArray RobertsCrossX =
+ new float[,]
+ {
+ { 1, 0 },
+ { 0, -1 }
+ };
///
/// The vertical gradient operator.
///
- private static readonly float[][] RobertsCrossY =
- {
- new float[] { 0, 1 },
- new float[] { -1, 0 }
- };
-
- ///
- public override float[][] KernelX => RobertsCrossX;
+ private static readonly Fast2DArray RobertsCrossY =
+ new float[,]
+ {
+ { 0, 1 },
+ { -1, 0 }
+ };
- ///
- public override float[][] KernelY => RobertsCrossY;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public RobertsCrossProcessor()
+ : base(RobertsCrossX, RobertsCrossY)
+ {
+ }
}
}
diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/RobinsonProcessor.cs b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/RobinsonProcessor.cs
index 4e61707c45..13d7a3f498 100644
--- a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/RobinsonProcessor.cs
+++ b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/RobinsonProcessor.cs
@@ -2,6 +2,7 @@
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
//
+
namespace ImageSharp.Processing.Processors
{
using System;
@@ -19,105 +20,113 @@ namespace ImageSharp.Processing.Processors
///
/// The North gradient operator
///
- private static readonly float[][] RobinsonNorth =
- {
- new float[] { 1, 2, 1 },
- new float[] { 0, 0, 0 },
- new float[] { -1, -2, -1 }
- };
+ private static readonly Fast2DArray RobinsonNorth =
+ new float[,]
+ {
+ { 1, 2, 1 },
+ { 0, 0, 0 },
+ { -1, -2, -1 }
+ };
///
/// The NorthWest gradient operator
///
- private static readonly float[][] RobinsonNorthWest =
- {
- new float[] { 2, 1, 0 },
- new float[] { 1, 0, -1 },
- new float[] { 0, -1, -2 }
- };
+ private static readonly Fast2DArray RobinsonNorthWest =
+ new float[,]
+ {
+ { 2, 1, 0 },
+ { 1, 0, -1 },
+ { 0, -1, -2 }
+ };
///
/// The West gradient operator
///
- private static readonly float[][] RobinsonWest =
- {
- new float[] { 1, 0, -1 },
- new float[] { 2, 0, -2 },
- new float[] { 1, 0, -1 }
- };
+ private static readonly Fast2DArray RobinsonWest =
+ new float[,]
+ {
+ { 1, 0, -1 },
+ { 2, 0, -2 },
+ { 1, 0, -1 }
+ };
///
/// The SouthWest gradient operator
///
- private static readonly float[][] RobinsonSouthWest =
- {
- new float[] { 0, -1, -2 },
- new float[] { 1, 0, -1 },
- new float[] { 2, 1, 0 }
- };
+ private static readonly Fast2DArray RobinsonSouthWest =
+ new float[,]
+ {
+ { 0, -1, -2 },
+ { 1, 0, -1 },
+ { 2, 1, 0 }
+ };
///
/// The South gradient operator
///
- private static readonly float[][] RobinsonSouth =
- {
- new float[] { -1, -2, -1 },
- new float[] { 0, 0, 0 },
- new float[] { 1, 2, 1 }
- };
+ private static readonly Fast2DArray RobinsonSouth =
+ new float[,]
+ {
+ { -1, -2, -1 },
+ { 0, 0, 0 },
+ { 1, 2, 1 }
+ };
///
/// The SouthEast gradient operator
///
- private static readonly float[][] RobinsonSouthEast =
- {
- new float[] { -2, -1, 0 },
- new float[] { -1, 0, 1 },
- new float[] { 0, 1, 2 }
- };
+ private static readonly Fast2DArray RobinsonSouthEast =
+ new float[,]
+ {
+ { -2, -1, 0 },
+ { -1, 0, 1 },
+ { 0, 1, 2 }
+ };
///
/// The East gradient operator
///
- private static readonly float[][] RobinsonEast =
- {
- new float[] { -1, 0, 1 },
- new float[] { -2, 0, 2 },
- new float[] { -1, 0, 1 }
- };
+ private static readonly Fast2DArray RobinsonEast =
+ new float[,]
+ {
+ { -1, 0, 1 },
+ { -2, 0, 2 },
+ { -1, 0, 1 }
+ };
///
/// The NorthEast gradient operator
///
- private static readonly float[][] RobinsonNorthEast =
- {
- new float[] { 0, 1, 2 },
- new float[] { -1, 0, 1 },
- new float[] { -2, -1, 0 }
- };
+ private static readonly Fast2DArray RobinsonNorthEast =
+ new float[,]
+ {
+ { 0, 1, 2 },
+ { -1, 0, 1 },
+ { -2, -1, 0 }
+ };
///
- public override float[][] North => RobinsonNorth;
+ public override Fast2DArray North => RobinsonNorth;
///
- public override float[][] NorthWest => RobinsonNorthWest;
+ public override Fast2DArray NorthWest => RobinsonNorthWest;
///
- public override float[][] West => RobinsonWest;
+ public override Fast2DArray West => RobinsonWest;
///
- public override float[][] SouthWest => RobinsonSouthWest;
+ public override Fast2DArray SouthWest => RobinsonSouthWest;
///
- public override float[][] South => RobinsonSouth;
+ public override Fast2DArray South => RobinsonSouth;
///
- public override float[][] SouthEast => RobinsonSouthEast;
+ public override Fast2DArray SouthEast => RobinsonSouthEast;
///
- public override float[][] East => RobinsonEast;
+ public override Fast2DArray East => RobinsonEast;
///
- public override float[][] NorthEast => RobinsonNorthEast;
+ public override Fast2DArray NorthEast => RobinsonNorthEast;
}
}
\ No newline at end of file
diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/ScharrProcessor.cs b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/ScharrProcessor.cs
index de2a185f86..11cb91b0d9 100644
--- a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/ScharrProcessor.cs
+++ b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/ScharrProcessor.cs
@@ -20,27 +20,31 @@ namespace ImageSharp.Processing.Processors
///
/// The horizontal gradient operator.
///
- private static readonly float[][] ScharrX = new float[3][]
- {
- new float[] { -3, 0, 3 },
- new float[] { -10, 0, 10 },
- new float[] { -3, 0, 3 }
- };
+ private static readonly Fast2DArray ScharrX =
+ new float[,]
+ {
+ { -3, 0, 3 },
+ { -10, 0, 10 },
+ { -3, 0, 3 }
+ };
///
/// The vertical gradient operator.
///
- private static readonly float[][] ScharrY = new float[3][]
- {
- new float[] { 3, 10, 3 },
- new float[] { 0, 0, 0 },
- new float[] { -3, -10, -3 }
- };
-
- ///
- public override float[][] KernelX => ScharrX;
+ private static readonly Fast2DArray ScharrY =
+ new float[,]
+ {
+ { 3, 10, 3 },
+ { 0, 0, 0 },
+ { -3, -10, -3 }
+ };
- ///
- public override float[][] KernelY => ScharrY;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ScharrProcessor()
+ : base(ScharrX, ScharrY)
+ {
+ }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/SobelProcessor.cs b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/SobelProcessor.cs
index 328c903dc7..347a19dab6 100644
--- a/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/SobelProcessor.cs
+++ b/src/ImageSharp.Processing/Processors/Convolution/EdgeDetection/SobelProcessor.cs
@@ -20,27 +20,31 @@ namespace ImageSharp.Processing.Processors
///
/// The horizontal gradient operator.
///
- private static readonly float[][] SobelX =
- {
- new float[] { -1, 0, 1 },
- new float[] { -2, 0, 2 },
- new float[] { -1, 0, 1 }
- };
+ private static readonly Fast2DArray SobelX =
+ new float[,]
+ {
+ { -1, 0, 1 },
+ { -2, 0, 2 },
+ { -1, 0, 1 }
+ };
///
/// The vertical gradient operator.
///
- private static readonly float[][] SobelY =
- {
- new float[] { -1, -2, -1 },
- new float[] { 0, 0, 0 },
- new float[] { 1, 2, 1 }
- };
-
- ///
- public override float[][] KernelX => SobelX;
+ private static readonly Fast2DArray SobelY =
+ new float[,]
+ {
+ { -1, -2, -1 },
+ { 0, 0, 0 },
+ { 1, 2, 1 }
+ };
- ///
- public override float[][] KernelY => SobelY;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public SobelProcessor()
+ : base(SobelX, SobelY)
+ {
+ }
}
}
diff --git a/src/ImageSharp.Processing/Processors/Convolution/GaussianBlurProcessor.cs b/src/ImageSharp.Processing/Processors/Convolution/GaussianBlurProcessor.cs
index 7cd3bbe9c5..87dde5b475 100644
--- a/src/ImageSharp.Processing/Processors/Convolution/GaussianBlurProcessor.cs
+++ b/src/ImageSharp.Processing/Processors/Convolution/GaussianBlurProcessor.cs
@@ -71,12 +71,12 @@ namespace ImageSharp.Processing.Processors
///
/// Gets the horizontal gradient operator.
///
- public float[][] KernelX { get; }
+ public Fast2DArray KernelX { get; }
///
/// Gets the vertical gradient operator.
///
- public float[][] KernelY { get; }
+ public Fast2DArray KernelY { get; }
///
protected override void OnApply(ImageBase source, Rectangle sourceRectangle)
@@ -88,21 +88,18 @@ namespace ImageSharp.Processing.Processors
/// Create a 1 dimensional Gaussian kernel using the Gaussian G(x) function
///
/// Whether to calculate a horizontal kernel.
- /// The
- private float[][] CreateGaussianKernel(bool horizontal)
+ /// The
+ private Fast2DArray CreateGaussianKernel(bool horizontal)
{
int size = this.kernelSize;
float weight = this.sigma;
- float[][] kernel = horizontal ? new float[1][] : new float[size][];
+ Fast2DArray kernel = horizontal
+ ? new Fast2DArray(size, 1)
+ : new Fast2DArray(1, size);
- if (horizontal)
- {
- kernel[0] = new float[size];
- }
-
- float sum = 0.0f;
+ float sum = 0F;
+ float midpoint = (size - 1) / 2F;
- float midpoint = (size - 1) / 2f;
for (int i = 0; i < size; i++)
{
float x = i - midpoint;
@@ -110,27 +107,27 @@ namespace ImageSharp.Processing.Processors
sum += gx;
if (horizontal)
{
- kernel[0][i] = gx;
+ kernel[0, i] = gx;
}
else
{
- kernel[i] = new[] { gx };
+ kernel[i, 0] = gx;
}
}
- // Normalise kernel so that the sum of all weights equals 1
+ // Normalize kernel so that the sum of all weights equals 1
if (horizontal)
{
for (int i = 0; i < size; i++)
{
- kernel[0][i] = kernel[0][i] / sum;
+ kernel[0, i] = kernel[0, i] / sum;
}
}
else
{
for (int i = 0; i < size; i++)
{
- kernel[i][0] = kernel[i][0] / sum;
+ kernel[i, 0] = kernel[i, 0] / sum;
}
}
diff --git a/src/ImageSharp.Processing/Processors/Convolution/GaussianSharpenProcessor.cs b/src/ImageSharp.Processing/Processors/Convolution/GaussianSharpenProcessor.cs
index d0654dd77b..5cf8cdf541 100644
--- a/src/ImageSharp.Processing/Processors/Convolution/GaussianSharpenProcessor.cs
+++ b/src/ImageSharp.Processing/Processors/Convolution/GaussianSharpenProcessor.cs
@@ -73,12 +73,12 @@ namespace ImageSharp.Processing.Processors
///
/// Gets the horizontal gradient operator.
///
- public float[][] KernelX { get; }
+ public Fast2DArray KernelX { get; }
///
/// Gets the vertical gradient operator.
///
- public float[][] KernelY { get; }
+ public Fast2DArray KernelY { get; }
///
protected override void OnApply(ImageBase source, Rectangle sourceRectangle)
@@ -90,17 +90,14 @@ namespace ImageSharp.Processing.Processors
/// Create a 1 dimensional Gaussian kernel using the Gaussian G(x) function
///
/// Whether to calculate a horizontal kernel.
- /// The
- private float[][] CreateGaussianKernel(bool horizontal)
+ /// The
+ private Fast2DArray CreateGaussianKernel(bool horizontal)
{
int size = this.kernelSize;
float weight = this.sigma;
- float[][] kernel = horizontal ? new float[1][] : new float[size][];
-
- if (horizontal)
- {
- kernel[0] = new float[size];
- }
+ Fast2DArray kernel = horizontal
+ ? new Fast2DArray(size, 1)
+ : new Fast2DArray(1, size);
float sum = 0;
@@ -112,11 +109,11 @@ namespace ImageSharp.Processing.Processors
sum += gx;
if (horizontal)
{
- kernel[0][i] = gx;
+ kernel[0, i] = gx;
}
else
{
- kernel[i] = new[] { gx };
+ kernel[i, 0] = gx;
}
}
@@ -130,12 +127,12 @@ namespace ImageSharp.Processing.Processors
if (i == midpointRounded)
{
// Calculate central value
- kernel[0][i] = (2f * sum) - kernel[0][i];
+ kernel[0, i] = (2F * sum) - kernel[0, i];
}
else
{
// invert value
- kernel[0][i] = -kernel[0][i];
+ kernel[0, i] = -kernel[0, i];
}
}
}
@@ -146,12 +143,12 @@ namespace ImageSharp.Processing.Processors
if (i == midpointRounded)
{
// Calculate central value
- kernel[i][0] = (2 * sum) - kernel[i][0];
+ kernel[i, 0] = (2 * sum) - kernel[i, 0];
}
else
{
// invert value
- kernel[i][0] = -kernel[i][0];
+ kernel[i, 0] = -kernel[i, 0];
}
}
}
@@ -161,14 +158,14 @@ namespace ImageSharp.Processing.Processors
{
for (int i = 0; i < size; i++)
{
- kernel[0][i] = kernel[0][i] / sum;
+ kernel[0, i] = kernel[0, i] / sum;
}
}
else
{
for (int i = 0; i < size; i++)
{
- kernel[i][0] = kernel[i][0] / sum;
+ kernel[i, 0] = kernel[i, 0] / sum;
}
}
diff --git a/src/ImageSharp/Common/Helpers/Fast2DArray{T}.cs b/src/ImageSharp/Common/Helpers/Fast2DArray{T}.cs
index 26ec816ce3..09cb0fec23 100644
--- a/src/ImageSharp/Common/Helpers/Fast2DArray{T}.cs
+++ b/src/ImageSharp/Common/Helpers/Fast2DArray{T}.cs
@@ -30,6 +30,22 @@ namespace ImageSharp
///
public int Height;
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The width.
+ /// The height.
+ public Fast2DArray(int width, int height)
+ {
+ this.Height = height;
+ this.Width = width;
+
+ Guard.MustBeGreaterThan(width, 0, nameof(width));
+ Guard.MustBeGreaterThan(height, 0, nameof(height));
+
+ this.Data = new T[this.Width * this.Height];
+ }
+
///
/// Initializes a new instance of the struct.
///
@@ -77,6 +93,19 @@ namespace ImageSharp
}
}
+ ///
+ /// Performs an implicit conversion from a 2D array to a .
+ ///
+ /// The source array.
+ ///
+ /// The represenation on the source data.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static implicit operator Fast2DArray(T[,] data)
+ {
+ return new Fast2DArray(data);
+ }
+
///
/// Checks the coordinates to ensure they are within bounds.
///
diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs
index fc94c689f0..5720d82186 100644
--- a/src/ImageSharp/Common/Helpers/ImageMaths.cs
+++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs
@@ -37,6 +37,7 @@ namespace ImageSharp
///
/// The
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetBitsNeededForColorDepth(int colors)
{
return (int)Math.Ceiling(Math.Log(colors, 2));
@@ -48,6 +49,7 @@ namespace ImageSharp
/// The x provided to G(x).
/// The spread of the blur.
/// The Gaussian G(x)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Gaussian(float x, float sigma)
{
const float Numerator = 1.0f;
@@ -72,6 +74,7 @@ namespace ImageSharp
///
/// The .
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float GetBcValue(float x, float b, float c)
{
float temp;
@@ -104,6 +107,7 @@ namespace ImageSharp
///
/// The .
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float SinC(float x)
{
if (Math.Abs(x) > Constants.Epsilon)
@@ -122,6 +126,7 @@ namespace ImageSharp
///
/// The representing the degree as radians.
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float DegreesToRadians(float degrees)
{
return degrees * (float)(Math.PI / 180);
@@ -139,6 +144,7 @@ namespace ImageSharp
///
/// The bounding .
///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Rectangle GetBoundingRectangle(Point topLeft, Point bottomRight)
{
return new Rectangle(topLeft.X, topLeft.Y, bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y);
diff --git a/src/ImageSharp/Dithering/ErrorDiffusion/Atkinson.cs b/src/ImageSharp/Dithering/ErrorDiffusion/Atkinson.cs
index 1fa6852c22..b94b872552 100644
--- a/src/ImageSharp/Dithering/ErrorDiffusion/Atkinson.cs
+++ b/src/ImageSharp/Dithering/ErrorDiffusion/Atkinson.cs
@@ -15,12 +15,12 @@ namespace ImageSharp.Dithering
/// The diffusion matrix
///
private static readonly Fast2DArray AtkinsonMatrix =
- new Fast2DArray(new float[,]
+ new float[,]
{
{ 0, 0, 1, 1 },
{ 1, 1, 1, 0 },
{ 0, 1, 0, 0 }
- });
+ };
///
/// Initializes a new instance of the class.
diff --git a/src/ImageSharp/Dithering/ErrorDiffusion/Burks.cs b/src/ImageSharp/Dithering/ErrorDiffusion/Burks.cs
index a4adcb0a49..894b6e236e 100644
--- a/src/ImageSharp/Dithering/ErrorDiffusion/Burks.cs
+++ b/src/ImageSharp/Dithering/ErrorDiffusion/Burks.cs
@@ -15,11 +15,11 @@ namespace ImageSharp.Dithering
/// The diffusion matrix
///
private static readonly Fast2DArray BurksMatrix =
- new Fast2DArray(new float[,]
+ new float[,]
{
{ 0, 0, 0, 8, 4 },
{ 2, 4, 8, 4, 2 }
- });
+ };
///
/// Initializes a new instance of the class.
diff --git a/src/ImageSharp/Dithering/ErrorDiffusion/FloydSteinberg.cs b/src/ImageSharp/Dithering/ErrorDiffusion/FloydSteinberg.cs
index 7b67d2dd12..f7a93667fe 100644
--- a/src/ImageSharp/Dithering/ErrorDiffusion/FloydSteinberg.cs
+++ b/src/ImageSharp/Dithering/ErrorDiffusion/FloydSteinberg.cs
@@ -15,11 +15,11 @@ namespace ImageSharp.Dithering
/// The diffusion matrix
///
private static readonly Fast2DArray FloydSteinbergMatrix =
- new Fast2DArray(new float[,]
+ new float[,]
{
{ 0, 0, 7 },
{ 3, 5, 1 }
- });
+ };
///
/// Initializes a new instance of the class.
diff --git a/src/ImageSharp/Dithering/ErrorDiffusion/JarvisJudiceNinke.cs b/src/ImageSharp/Dithering/ErrorDiffusion/JarvisJudiceNinke.cs
index 32f38fbc85..60fef81216 100644
--- a/src/ImageSharp/Dithering/ErrorDiffusion/JarvisJudiceNinke.cs
+++ b/src/ImageSharp/Dithering/ErrorDiffusion/JarvisJudiceNinke.cs
@@ -15,12 +15,12 @@ namespace ImageSharp.Dithering
/// The diffusion matrix
///
private static readonly Fast2DArray JarvisJudiceNinkeMatrix =
- new Fast2DArray(new float[,]
+ new float[,]
{
{ 0, 0, 0, 7, 5 },
{ 3, 5, 7, 5, 3 },
{ 1, 3, 5, 3, 1 }
- });
+ };
///
/// Initializes a new instance of the class.
diff --git a/src/ImageSharp/Dithering/ErrorDiffusion/Sierra2.cs b/src/ImageSharp/Dithering/ErrorDiffusion/Sierra2.cs
index 47b14944e2..4325438e08 100644
--- a/src/ImageSharp/Dithering/ErrorDiffusion/Sierra2.cs
+++ b/src/ImageSharp/Dithering/ErrorDiffusion/Sierra2.cs
@@ -15,11 +15,11 @@ namespace ImageSharp.Dithering
/// The diffusion matrix
///
private static readonly Fast2DArray Sierra2Matrix =
- new Fast2DArray(new float[,]
+ new float[,]
{
{ 0, 0, 0, 4, 3 },
{ 1, 2, 3, 2, 1 }
- });
+ };
///
/// Initializes a new instance of the class.
diff --git a/src/ImageSharp/Dithering/ErrorDiffusion/Sierra3.cs b/src/ImageSharp/Dithering/ErrorDiffusion/Sierra3.cs
index ae33954cfd..25ea70d0a6 100644
--- a/src/ImageSharp/Dithering/ErrorDiffusion/Sierra3.cs
+++ b/src/ImageSharp/Dithering/ErrorDiffusion/Sierra3.cs
@@ -15,12 +15,12 @@ namespace ImageSharp.Dithering
/// The diffusion matrix
///
private static readonly Fast2DArray Sierra3Matrix =
- new Fast2DArray(new float[,]
+ new float[,]
{
{ 0, 0, 0, 5, 3 },
{ 2, 4, 5, 4, 2 },
{ 0, 2, 3, 2, 0 }
- });
+ };
///
/// Initializes a new instance of the class.
diff --git a/src/ImageSharp/Dithering/ErrorDiffusion/SierraLite.cs b/src/ImageSharp/Dithering/ErrorDiffusion/SierraLite.cs
index 8a1e178165..c7b1d214f1 100644
--- a/src/ImageSharp/Dithering/ErrorDiffusion/SierraLite.cs
+++ b/src/ImageSharp/Dithering/ErrorDiffusion/SierraLite.cs
@@ -15,11 +15,11 @@ namespace ImageSharp.Dithering
/// The diffusion matrix
///
private static readonly Fast2DArray SierraLiteMatrix =
- new Fast2DArray(new float[,]
+ new float[,]
{
{ 0, 0, 2 },
{ 1, 1, 0 }
- });
+ };
///
/// Initializes a new instance of the class.
diff --git a/src/ImageSharp/Dithering/ErrorDiffusion/Stucki.cs b/src/ImageSharp/Dithering/ErrorDiffusion/Stucki.cs
index b5d22b2592..93258c3508 100644
--- a/src/ImageSharp/Dithering/ErrorDiffusion/Stucki.cs
+++ b/src/ImageSharp/Dithering/ErrorDiffusion/Stucki.cs
@@ -15,12 +15,12 @@ namespace ImageSharp.Dithering
/// The diffusion matrix
///
private static readonly Fast2DArray StuckiMatrix =
- new Fast2DArray(new float[,]
+ new float[,]
{
{ 0, 0, 0, 8, 4 },
{ 2, 4, 8, 4, 2 },
{ 1, 2, 4, 2, 1 }
- });
+ };
///
/// Initializes a new instance of the class.
diff --git a/src/ImageSharp/Dithering/Ordered/Bayer.cs b/src/ImageSharp/Dithering/Ordered/Bayer.cs
index 3d3d900233..ff56196c59 100644
--- a/src/ImageSharp/Dithering/Ordered/Bayer.cs
+++ b/src/ImageSharp/Dithering/Ordered/Bayer.cs
@@ -18,13 +18,13 @@ namespace ImageSharp.Dithering.Ordered
/// This is calculated by multiplying each value in the original matrix by 16 and subtracting 1
///
private static readonly Fast2DArray ThresholdMatrix =
- new Fast2DArray(new byte[,]
+ new byte[,]
{
{ 15, 143, 47, 175 },
{ 207, 79, 239, 111 },
{ 63, 191, 31, 159 },
{ 255, 127, 223, 95 }
- });
+ };
///
public Fast2DArray Matrix { get; } = ThresholdMatrix;
diff --git a/src/ImageSharp/Dithering/Ordered/Ordered.cs b/src/ImageSharp/Dithering/Ordered/Ordered.cs
index bb1f21060d..86c325cd1f 100644
--- a/src/ImageSharp/Dithering/Ordered/Ordered.cs
+++ b/src/ImageSharp/Dithering/Ordered/Ordered.cs
@@ -18,13 +18,13 @@ namespace ImageSharp.Dithering.Ordered
/// This is calculated by multiplying each value in the original matrix by 16
///
private static readonly Fast2DArray ThresholdMatrix =
- new Fast2DArray(new byte[,]
+ new byte[,]
{
{ 0, 128, 32, 160 },
{ 192, 64, 224, 96 },
{ 48, 176, 16, 144 },
{ 240, 112, 208, 80 }
- });
+ };
///
public Fast2DArray Matrix { get; } = ThresholdMatrix;
diff --git a/tests/ImageSharp.Benchmarks/General/Array2D.cs b/tests/ImageSharp.Benchmarks/General/Array2D.cs
index a01ba77adc..fce92e9be5 100644
--- a/tests/ImageSharp.Benchmarks/General/Array2D.cs
+++ b/tests/ImageSharp.Benchmarks/General/Array2D.cs
@@ -5,25 +5,31 @@
namespace ImageSharp.Benchmarks.General
{
+ using System;
+
using BenchmarkDotNet.Attributes;
public class Array2D
{
- private float[,] data;
+ private float[] flatArray;
+
+ private float[,] array2D;
private float[][] jaggedData;
private Fast2DArray fastData;
-
- [Params(10, 100, 1000, 10000)]
+
+ [Params(4, 16, 128)]
public int Count { get; set; }
- public int Index { get; set; }
+ public int Min { get; private set; }
+ public int Max { get; private set; }
[Setup]
public void SetUp()
{
- this.data = new float[this.Count, this.Count];
+ this.flatArray = new float[this.Count * this.Count];
+ this.array2D = new float[this.Count, this.Count];
this.jaggedData = new float[this.Count][];
for (int i = 0; i < this.Count; i++)
@@ -31,27 +37,72 @@ namespace ImageSharp.Benchmarks.General
this.jaggedData[i] = new float[this.Count];
}
- this.fastData = new Fast2DArray(this.data);
+ this.fastData = new Fast2DArray(this.array2D);
- this.Index = this.Count / 2;
+ this.Min = this.Count / 2 - 10;
+ this.Min = Math.Max(0, this.Min);
+ this.Max = this.Min + Math.Min(10, this.Count);
+ }
+
+ [Benchmark(Description = "Emulated 2D array access using flat array")]
+ public float FlatArrayIndex()
+ {
+ float[] a = this.flatArray;
+ float s = 0;
+ int count = this.Count;
+ for (int i = this.Min; i < this.Max; i++)
+ {
+ for (int j = this.Min; j < this.Max; j++)
+ {
+ s += a[count * i + j];
+ }
+ }
+ return s;
}
[Benchmark(Baseline = true, Description = "Array access using 2D array")]
- public float ArrayIndex()
+ public float Array2DIndex()
{
- return this.data[this.Index, this.Index];
+ float s = 0;
+ float[,] a = this.array2D;
+ for (int i = this.Min; i < this.Max; i++)
+ {
+ for (int j = this.Min; j < this.Max; j++)
+ {
+ s += a[i, j];
+ }
+ }
+ return s;
}
[Benchmark(Description = "Array access using a jagged array")]
public float ArrayJaggedIndex()
{
- return this.jaggedData[this.Index][this.Index];
+ float s = 0;
+ float[][] a = this.jaggedData;
+ for (int i = this.Min; i < this.Max; i++)
+ {
+ for (int j = this.Min; j < this.Max; j++)
+ {
+ s += a[i][j];
+ }
+ }
+ return s;
}
[Benchmark(Description = "Array access using Fast2DArray")]
public float ArrayFastIndex()
{
- return this.fastData[this.Index, this.Index];
+ float s = 0;
+ Fast2DArray a = this.fastData;
+ for (int i = this.Min; i < this.Max; i++)
+ {
+ for (int j = this.Min; j < this.Max; j++)
+ {
+ s += a[i, j];
+ }
+ }
+ return s;
}
}
}
diff --git a/tests/ImageSharp.Tests/Common/Fast2DArrayTests.cs b/tests/ImageSharp.Tests/Common/Fast2DArrayTests.cs
index 903ea6f8d9..7db7a4820b 100644
--- a/tests/ImageSharp.Tests/Common/Fast2DArrayTests.cs
+++ b/tests/ImageSharp.Tests/Common/Fast2DArrayTests.cs
@@ -21,9 +21,27 @@ namespace ImageSharp.Tests.Common
public void Fast2DArrayThrowsOnNullInitializer()
{
Assert.Throws(() =>
- {
- Fast2DArray fast = new Fast2DArray(null);
- });
+ {
+ Fast2DArray fast = new Fast2DArray(null);
+ });
+ }
+
+ [Fact]
+ public void Fast2DArrayThrowsOnEmptyZeroWidth()
+ {
+ Assert.Throws(() =>
+ {
+ Fast2DArray fast = new Fast2DArray(0, 10);
+ });
+ }
+
+ [Fact]
+ public void Fast2DArrayThrowsOnEmptyZeroHeight()
+ {
+ Assert.Throws(() =>
+ {
+ Fast2DArray fast = new Fast2DArray(10, 0);
+ });
}
[Fact]
@@ -46,7 +64,7 @@ namespace ImageSharp.Tests.Common
[Fact]
public void Fast2DArrayGetReturnsCorrectResults()
{
- Fast2DArray fast = new Fast2DArray(FloydSteinbergMatrix);
+ Fast2DArray fast = FloydSteinbergMatrix;
for (int row = 0; row < fast.Height; row++)
{
@@ -60,7 +78,7 @@ namespace ImageSharp.Tests.Common
[Fact]
public void Fast2DArrayGetSetReturnsCorrectResults()
{
- Fast2DArray fast = new Fast2DArray(new float[4, 4]);
+ Fast2DArray fast = new Fast2DArray(4, 4);
const float Val = 5F;
fast[3, 3] = Val;