From ba93355937eaab8d3cc2cda97d59776161770a67 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 12 Oct 2018 22:21:23 +0100 Subject: [PATCH] Remove conditionals from loop and enforce equal matrice dimensions. --- .../Common/Helpers/DenseMatrixUtils.cs | 35 ++++++++----------- src/ImageSharp/Primitives/DenseMatrix{T}.cs | 8 +++++ .../Convolution/Convolution2DProcessor.cs | 1 + .../Convolution/EdgeDetector2DProcessor.cs | 6 ++-- .../Primitives/DenseMatrixTests.cs | 2 ++ 5 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs b/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs index 0755ae8a1..2e700c9d6 100644 --- a/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs +++ b/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 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; } } diff --git a/src/ImageSharp/Primitives/DenseMatrix{T}.cs b/src/ImageSharp/Primitives/DenseMatrix{T}.cs index 2a4b9dc07..7cfa98ec1 100644 --- a/src/ImageSharp/Primitives/DenseMatrix{T}.cs +++ b/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 /// public readonly int Rows; + /// + /// Gets the size of the dense matrix. + /// + public readonly Size Size; + /// /// Gets the number of items in the array. /// @@ -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]; diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs index 1ecf9b759..0669a1247 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs @@ -25,6 +25,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// The vertical gradient operator. public Convolution2DProcessor(DenseMatrix kernelX, DenseMatrix kernelY) { + Guard.IsTrue(kernelX.Size.Equals(kernelY.Size), $"{nameof(kernelX)} {nameof(kernelY)}", "Kernel sizes must be the same."); this.KernelX = kernelX; this.KernelY = kernelY; } diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor.cs index dd43d3e15..892771649 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor.cs @@ -23,6 +23,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// Whether to convert the image to grayscale before performing edge detection. protected EdgeDetector2DProcessor(DenseMatrix kernelX, DenseMatrix 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; } /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) - { - new Convolution2DProcessor(this.KernelX, this.KernelY).Apply(source, sourceRectangle, configuration); - } + protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) => new Convolution2DProcessor(this.KernelX, this.KernelY).Apply(source, sourceRectangle, configuration); /// protected override void BeforeFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) diff --git a/tests/ImageSharp.Tests/Primitives/DenseMatrixTests.cs b/tests/ImageSharp.Tests/Primitives/DenseMatrixTests.cs index 7d161d35f..fa4862293 100644 --- a/tests/ImageSharp.Tests/Primitives/DenseMatrixTests.cs +++ b/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]