Browse Source

Use tensor addition for histogram offsets

pull/3161/head
James Jackson-South 3 weeks ago
parent
commit
49d20566a3
  1. 12
      src/ImageSharp/Common/Helpers/TensorPrimitives.cs
  2. 1
      src/ImageSharp/Formats/Png/Filters/IPngFilterOperator.cs
  3. 1
      src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogram.cs
  4. 6
      src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor{TPixel}.cs
  5. 27
      tests/ImageSharp.Tests/Common/TensorPrimitivesTests.cs

12
src/ImageSharp/Common/Helpers/TensorPrimitives.cs

@ -137,6 +137,18 @@ internal static class TensorPrimitives_
where T : IAdditionOperators<T, T, T>, IAdditiveIdentity<T, T>
=> InvokeSpanSpanIntoSpan<T, AddOperator<T>>(x, y, destination);
/// <summary>
/// Computes the element-wise sum of the values in <paramref name="x"/> and the scalar <paramref name="y"/>.
/// </summary>
/// <typeparam name="T">The element type.</typeparam>
/// <param name="x">The first addends.</param>
/// <param name="y">The scalar second addend.</param>
/// <param name="destination">The destination for the sums.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Add<T>(ReadOnlySpan<T> x, T y, Span<T> destination)
where T : IAdditionOperators<T, T, T>, IAdditiveIdentity<T, T>
=> InvokeSpanScalarIntoSpan<T, AddOperator<T>>(x, y, destination);
/// <summary>
/// Computes the element-wise result of dividing the values in <paramref name="x"/> by <paramref name="y"/>.
/// </summary>

1
src/ImageSharp/Formats/Png/Filters/IPngFilterOperator.cs

@ -3,6 +3,7 @@
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.Arm;
using System.Runtime.Intrinsics.X86;
using SixLabors.ImageSharp.Common.Helpers;

1
src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogram.cs

@ -533,7 +533,6 @@ internal abstract unsafe class Vp8LHistogram
return cost;
}
}
internal sealed unsafe class OwnedVp8LHistogram : Vp8LHistogram, IDisposable

6
src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor{TPixel}.cs

@ -4,6 +4,7 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Common.Helpers;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Normalization;
@ -115,10 +116,7 @@ internal abstract class HistogramEqualizationProcessor<TPixel> : ImageProcessor<
int addToEachBin = sumOverClip > 0 ? (int)MathF.Floor(sumOverClip / this.luminanceLevelsFloat) : 0;
if (addToEachBin > 0)
{
for (nuint i = 0; i < (uint)histogram.Length; i++)
{
Unsafe.Add(ref histogramBase, i) += addToEachBin;
}
TensorPrimitives_.Add(histogram, addToEachBin, histogram);
}
int residual = sumOverClip - (addToEachBin * this.LuminanceLevels);

27
tests/ImageSharp.Tests/Common/TensorPrimitivesTests.cs

@ -90,6 +90,33 @@ public class TensorPrimitivesTests
Assert.Equal(expected, x);
}
/// <summary>
/// Verifies that scalar integer addition produces identical results for separate and in-place destinations.
/// </summary>
/// <param name="length">The input length.</param>
[Theory]
[MemberData(nameof(SpanLengths))]
public void AddScalarInt32MatchesScalarFormula(int length)
{
int[] source = new int[length];
int[] expected = new int[length];
const int addend = 17;
for (int i = 0; i < length; i++)
{
source[i] = (i * 37) - 200;
expected[i] = source[i] + addend;
}
int[] destination = new int[length];
TensorPrimitives_.Add(source, addend, destination);
Assert.Equal(expected, destination);
int[] inPlace = (int[])source.Clone();
TensorPrimitives_.Add(inPlace, addend, inPlace);
Assert.Equal(expected, inPlace);
}
/// <summary>
/// Verifies that integer clamping produces identical results for separate and in-place destinations.
/// </summary>

Loading…
Cancel
Save