Browse Source

Remove conditionals from loop and enforce equal matrice dimensions.

af/merge-core
James Jackson-South 7 years ago
parent
commit
ba93355937
  1. 35
      src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs
  2. 8
      src/ImageSharp/Primitives/DenseMatrix{T}.cs
  3. 1
      src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs
  4. 6
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor.cs
  5. 2
      tests/ImageSharp.Tests/Primitives/DenseMatrixTests.cs

35
src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs

@ -42,6 +42,7 @@ namespace SixLabors.ImageSharp
int matrixWidth = matrix.Columns;
int radiusY = matrixHeight >> 1;
int radiusX = matrixWidth >> 1;
int sourceOffsetColumnBase = column + offsetColumn;
for (int y = 0; y < matrixHeight; y++)
{
@ -50,11 +51,11 @@ namespace SixLabors.ImageSharp
for (int x = 0; x < matrixWidth; x++)
{
int offsetX = (column + offsetColumn + x - radiusX).Clamp(offsetColumn, maxColumn);
int offsetX = (sourceOffsetColumnBase + x - radiusX).Clamp(offsetColumn, maxColumn);
var currentColor = sourceRowSpan[offsetX].ToVector4();
Vector4Utils.Premultiply(ref currentColor);
currentColor *= matrix[y, x];
vector += currentColor;
vector += matrix[y, x] * currentColor;
}
}
@ -91,33 +92,25 @@ namespace SixLabors.ImageSharp
{
Vector4 vectorY = default;
Vector4 vectorX = default;
int matrixYHeight = matrixY.Rows;
int matrixYWidth = matrixY.Columns;
int matrixXHeight = matrixX.Rows;
int matrixXWidth = matrixX.Columns;
int radiusY = matrixYHeight >> 1;
int radiusX = matrixXWidth >> 1;
int matrixHeight = matrixY.Rows;
int matrixWidth = matrixY.Columns;
int radiusY = matrixHeight >> 1;
int radiusX = matrixWidth >> 1;
int sourceOffsetColumnBase = column + offsetColumn;
for (int y = 0; y < matrixYHeight; y++)
for (int y = 0; y < matrixHeight; y++)
{
int offsetY = (row + y - radiusY).Clamp(0, maxRow);
Span<TPixel> sourceRowSpan = sourcePixels.GetRowSpan(offsetY);
for (int x = 0; x < matrixXWidth; x++)
for (int x = 0; x < matrixWidth; x++)
{
int offsetX = (column + offsetColumn + x - radiusX).Clamp(offsetColumn, maxColumn);
int offsetX = (sourceOffsetColumnBase + x - radiusX).Clamp(offsetColumn, maxColumn);
var currentColor = sourceRowSpan[offsetX].ToVector4();
Vector4Utils.Premultiply(ref currentColor);
if (y < matrixXHeight)
{
vectorX += matrixX[y, x] * currentColor;
}
if (x < matrixYWidth)
{
vectorY += matrixY[y, x] * currentColor;
}
vectorX += matrixX[y, x] * currentColor;
vectorY += matrixY[y, x] * currentColor;
}
}

8
src/ImageSharp/Primitives/DenseMatrix{T}.cs

@ -4,6 +4,7 @@
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Primitives
{
@ -31,6 +32,11 @@ namespace SixLabors.ImageSharp.Primitives
/// </summary>
public readonly int Rows;
/// <summary>
/// Gets the size of the dense matrix.
/// </summary>
public readonly Size Size;
/// <summary>
/// Gets the number of items in the array.
/// </summary>
@ -57,6 +63,7 @@ namespace SixLabors.ImageSharp.Primitives
this.Rows = rows;
this.Columns = columns;
this.Size = new Size(columns, rows);
this.Count = columns * rows;
this.Data = new T[this.Columns * this.Rows];
}
@ -76,6 +83,7 @@ namespace SixLabors.ImageSharp.Primitives
this.Rows = rows;
this.Columns = columns;
this.Size = new Size(columns, rows);
this.Count = this.Columns * this.Rows;
this.Data = new T[this.Columns * this.Rows];

1
src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs

@ -25,6 +25,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <param name="kernelY">The vertical gradient operator.</param>
public Convolution2DProcessor(DenseMatrix<float> kernelX, DenseMatrix<float> kernelY)
{
Guard.IsTrue(kernelX.Size.Equals(kernelY.Size), $"{nameof(kernelX)} {nameof(kernelY)}", "Kernel sizes must be the same.");
this.KernelX = kernelX;
this.KernelY = kernelY;
}

6
src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor.cs

@ -23,6 +23,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
protected EdgeDetector2DProcessor(DenseMatrix<float> kernelX, DenseMatrix<float> kernelY, bool grayscale)
{
Guard.IsTrue(kernelX.Size.Equals(kernelY.Size), $"{nameof(kernelX)} {nameof(kernelY)}", "Kernel sizes must be the same.");
this.KernelX = kernelX;
this.KernelY = kernelY;
this.Grayscale = grayscale;
@ -42,10 +43,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
public bool Grayscale { get; set; }
/// <inheritdoc />
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
new Convolution2DProcessor<TPixel>(this.KernelX, this.KernelY).Apply(source, sourceRectangle, configuration);
}
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration) => new Convolution2DProcessor<TPixel>(this.KernelX, this.KernelY).Apply(source, sourceRectangle, configuration);
/// <inheritdoc/>
protected override void BeforeFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)

2
tests/ImageSharp.Tests/Primitives/DenseMatrixTests.cs

@ -3,6 +3,7 @@
using System;
using SixLabors.ImageSharp.Primitives;
using SixLabors.Primitives;
using Xunit;
namespace SixLabors.ImageSharp.Tests.Primitives
@ -59,6 +60,7 @@ namespace SixLabors.ImageSharp.Tests.Primitives
Assert.True(dense.Rows == FloydSteinbergMatrix.GetLength(0));
Assert.Equal(3, dense.Columns);
Assert.Equal(2, dense.Rows);
Assert.Equal(new Size(3, 2), dense.Size);
}
[Fact]

Loading…
Cancel
Save