Browse Source

Remove conditionals from loop and enforce equal matrice dimensions.

af/merge-core
James Jackson-South 8 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 matrixWidth = matrix.Columns;
int radiusY = matrixHeight >> 1; int radiusY = matrixHeight >> 1;
int radiusX = matrixWidth >> 1; int radiusX = matrixWidth >> 1;
int sourceOffsetColumnBase = column + offsetColumn;
for (int y = 0; y < matrixHeight; y++) for (int y = 0; y < matrixHeight; y++)
{ {
@ -50,11 +51,11 @@ namespace SixLabors.ImageSharp
for (int x = 0; x < matrixWidth; 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(); var currentColor = sourceRowSpan[offsetX].ToVector4();
Vector4Utils.Premultiply(ref currentColor); 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 vectorY = default;
Vector4 vectorX = default; Vector4 vectorX = default;
int matrixYHeight = matrixY.Rows; int matrixHeight = matrixY.Rows;
int matrixYWidth = matrixY.Columns; int matrixWidth = matrixY.Columns;
int matrixXHeight = matrixX.Rows; int radiusY = matrixHeight >> 1;
int matrixXWidth = matrixX.Columns; int radiusX = matrixWidth >> 1;
int radiusY = matrixYHeight >> 1; int sourceOffsetColumnBase = column + offsetColumn;
int radiusX = matrixXWidth >> 1;
for (int y = 0; y < matrixYHeight; y++) for (int y = 0; y < matrixHeight; y++)
{ {
int offsetY = (row + y - radiusY).Clamp(0, maxRow); int offsetY = (row + y - radiusY).Clamp(0, maxRow);
Span<TPixel> sourceRowSpan = sourcePixels.GetRowSpan(offsetY); 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(); var currentColor = sourceRowSpan[offsetX].ToVector4();
Vector4Utils.Premultiply(ref currentColor); Vector4Utils.Premultiply(ref currentColor);
if (y < matrixXHeight) vectorX += matrixX[y, x] * currentColor;
{ vectorY += matrixY[y, x] * currentColor;
vectorX += matrixX[y, x] * currentColor;
}
if (x < matrixYWidth)
{
vectorY += matrixY[y, x] * currentColor;
}
} }
} }

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

@ -4,6 +4,7 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Primitives namespace SixLabors.ImageSharp.Primitives
{ {
@ -31,6 +32,11 @@ namespace SixLabors.ImageSharp.Primitives
/// </summary> /// </summary>
public readonly int Rows; public readonly int Rows;
/// <summary>
/// Gets the size of the dense matrix.
/// </summary>
public readonly Size Size;
/// <summary> /// <summary>
/// Gets the number of items in the array. /// Gets the number of items in the array.
/// </summary> /// </summary>
@ -57,6 +63,7 @@ namespace SixLabors.ImageSharp.Primitives
this.Rows = rows; this.Rows = rows;
this.Columns = columns; this.Columns = columns;
this.Size = new Size(columns, rows);
this.Count = columns * rows; this.Count = columns * rows;
this.Data = new T[this.Columns * this.Rows]; this.Data = new T[this.Columns * this.Rows];
} }
@ -76,6 +83,7 @@ namespace SixLabors.ImageSharp.Primitives
this.Rows = rows; this.Rows = rows;
this.Columns = columns; this.Columns = columns;
this.Size = new Size(columns, rows);
this.Count = this.Columns * this.Rows; this.Count = this.Columns * this.Rows;
this.Data = new T[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> /// <param name="kernelY">The vertical gradient operator.</param>
public Convolution2DProcessor(DenseMatrix<float> kernelX, DenseMatrix<float> kernelY) 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.KernelX = kernelX;
this.KernelY = kernelY; 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> /// <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) 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.KernelX = kernelX;
this.KernelY = kernelY; this.KernelY = kernelY;
this.Grayscale = grayscale; this.Grayscale = grayscale;
@ -42,10 +43,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
public bool Grayscale { get; set; } public bool Grayscale { get; set; }
/// <inheritdoc /> /// <inheritdoc />
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration) protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration) => new Convolution2DProcessor<TPixel>(this.KernelX, this.KernelY).Apply(source, sourceRectangle, configuration);
{
new Convolution2DProcessor<TPixel>(this.KernelX, this.KernelY).Apply(source, sourceRectangle, configuration);
}
/// <inheritdoc/> /// <inheritdoc/>
protected override void BeforeFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration) 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 System;
using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Primitives;
using SixLabors.Primitives;
using Xunit; using Xunit;
namespace SixLabors.ImageSharp.Tests.Primitives namespace SixLabors.ImageSharp.Tests.Primitives
@ -59,6 +60,7 @@ namespace SixLabors.ImageSharp.Tests.Primitives
Assert.True(dense.Rows == FloydSteinbergMatrix.GetLength(0)); Assert.True(dense.Rows == FloydSteinbergMatrix.GetLength(0));
Assert.Equal(3, dense.Columns); Assert.Equal(3, dense.Columns);
Assert.Equal(2, dense.Rows); Assert.Equal(2, dense.Rows);
Assert.Equal(new Size(3, 2), dense.Size);
} }
[Fact] [Fact]

Loading…
Cancel
Save