Browse Source

rename KernelMap to ResizeKernelMap, introduce MosaicKernelMap, move source code

af/merge-core
Anton Firszov 7 years ago
parent
commit
ca61df8e64
  1. 3
      src/ImageSharp/Common/Helpers/ImageMaths.cs
  2. 4
      src/ImageSharp/ImageSharp.csproj.DotSettings
  3. 0
      src/ImageSharp/Processing/Processors/Transforms/Resamplers/BicubicResampler.cs
  4. 0
      src/ImageSharp/Processing/Processors/Transforms/Resamplers/BoxResampler.cs
  5. 0
      src/ImageSharp/Processing/Processors/Transforms/Resamplers/CatmullRomResampler.cs
  6. 0
      src/ImageSharp/Processing/Processors/Transforms/Resamplers/HermiteResampler.cs
  7. 0
      src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos2Resampler.cs
  8. 0
      src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos3Resampler.cs
  9. 0
      src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos5Resampler.cs
  10. 0
      src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos8Resampler.cs
  11. 0
      src/ImageSharp/Processing/Processors/Transforms/Resamplers/MitchellNetravaliResampler.cs
  12. 0
      src/ImageSharp/Processing/Processors/Transforms/Resamplers/NearestNeighborResampler.cs
  13. 0
      src/ImageSharp/Processing/Processors/Transforms/Resamplers/RobidouxResampler.cs
  14. 0
      src/ImageSharp/Processing/Processors/Transforms/Resamplers/RobidouxSharpResampler.cs
  15. 0
      src/ImageSharp/Processing/Processors/Transforms/Resamplers/SplineResampler.cs
  16. 0
      src/ImageSharp/Processing/Processors/Transforms/Resamplers/TriangleResampler.cs
  17. 0
      src/ImageSharp/Processing/Processors/Transforms/Resamplers/WelchResampler.cs
  18. 22
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs
  19. 46
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs
  20. 70
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs
  21. 8
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs
  22. 2
      tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs
  23. 4
      tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs
  24. 1
      tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs

3
src/ImageSharp/Common/Helpers/ImageMaths.cs

@ -5,6 +5,7 @@ using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Transforms;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp
@ -98,7 +99,7 @@ namespace SixLabors.ImageSharp
/// <summary>
/// Determine the Least Common Multiple (LCM) of two numbers.
/// TODO: This method might be useful for building a more compact <see cref="Processing.Processors.Transforms.KernelMap"/>
/// TODO: This method might be useful for building a more compact <see cref="ResizeKernelMap"/>
/// </summary>
public static int LeastCommonMultiple(int a, int b)
{

4
src/ImageSharp/ImageSharp.csproj.DotSettings

@ -5,4 +5,6 @@
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=pixelformats_005Cpackedpixels/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=pixelformats_005Cpixelimplementations/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=pixelformats_005Cpixeltypes/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=pixelformats_005Cutils/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=pixelformats_005Cutils/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=processing_005Cprocessors_005Ctransforms_005Cresamplers/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=processing_005Cprocessors_005Ctransforms_005Cresize/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

0
src/ImageSharp/Processing/Processors/Transforms/BicubicResampler.cs → src/ImageSharp/Processing/Processors/Transforms/Resamplers/BicubicResampler.cs

0
src/ImageSharp/Processing/Processors/Transforms/BoxResampler.cs → src/ImageSharp/Processing/Processors/Transforms/Resamplers/BoxResampler.cs

0
src/ImageSharp/Processing/Processors/Transforms/CatmullRomResampler.cs → src/ImageSharp/Processing/Processors/Transforms/Resamplers/CatmullRomResampler.cs

0
src/ImageSharp/Processing/Processors/Transforms/HermiteResampler.cs → src/ImageSharp/Processing/Processors/Transforms/Resamplers/HermiteResampler.cs

0
src/ImageSharp/Processing/Processors/Transforms/Lanczos2Resampler.cs → src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos2Resampler.cs

0
src/ImageSharp/Processing/Processors/Transforms/Lanczos3Resampler.cs → src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos3Resampler.cs

0
src/ImageSharp/Processing/Processors/Transforms/Lanczos5Resampler.cs → src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos5Resampler.cs

0
src/ImageSharp/Processing/Processors/Transforms/Lanczos8Resampler.cs → src/ImageSharp/Processing/Processors/Transforms/Resamplers/Lanczos8Resampler.cs

0
src/ImageSharp/Processing/Processors/Transforms/MitchellNetravaliResampler.cs → src/ImageSharp/Processing/Processors/Transforms/Resamplers/MitchellNetravaliResampler.cs

0
src/ImageSharp/Processing/Processors/Transforms/NearestNeighborResampler.cs → src/ImageSharp/Processing/Processors/Transforms/Resamplers/NearestNeighborResampler.cs

0
src/ImageSharp/Processing/Processors/Transforms/RobidouxResampler.cs → src/ImageSharp/Processing/Processors/Transforms/Resamplers/RobidouxResampler.cs

0
src/ImageSharp/Processing/Processors/Transforms/RobidouxSharpResampler.cs → src/ImageSharp/Processing/Processors/Transforms/Resamplers/RobidouxSharpResampler.cs

0
src/ImageSharp/Processing/Processors/Transforms/SplineResampler.cs → src/ImageSharp/Processing/Processors/Transforms/Resamplers/SplineResampler.cs

0
src/ImageSharp/Processing/Processors/Transforms/TriangleResampler.cs → src/ImageSharp/Processing/Processors/Transforms/Resamplers/TriangleResampler.cs

0
src/ImageSharp/Processing/Processors/Transforms/WelchResampler.cs → src/ImageSharp/Processing/Processors/Transforms/Resamplers/WelchResampler.cs

22
src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs → src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs

@ -11,18 +11,21 @@ using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{
/// <summary>
/// Points to a collection of of weights allocated in <see cref="KernelMap"/>.
/// Points to a collection of of weights allocated in <see cref="ResizeKernelMap"/>.
/// </summary>
internal struct ResizeKernel
internal unsafe struct ResizeKernel
{
private readonly float* bufferPtr;
/// <summary>
/// Initializes a new instance of the <see cref="ResizeKernel"/> struct.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
internal ResizeKernel(int left, Memory<float> bufferSlice)
internal ResizeKernel(int left, float* bufferPtr, int length)
{
this.Left = left;
this.BufferSlice = bufferSlice;
this.bufferPtr = bufferPtr;
this.Length = length;
}
/// <summary>
@ -30,22 +33,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// </summary>
public int Left { get; }
/// <summary>
/// Gets the slice of the buffer containing the weights values.
/// </summary>
public Memory<float> BufferSlice { get; }
/// <summary>
/// Gets the the length of the kernel
/// </summary>
public int Length => this.BufferSlice.Length;
public int Length { get; }
/// <summary>
/// Gets the span representing the portion of the <see cref="KernelMap"/> that this window covers
/// Gets the span representing the portion of the <see cref="ResizeKernelMap"/> that this window covers
/// </summary>
/// <returns>The <see cref="Span{T}"/></returns>
[MethodImpl(InliningOptions.ShortMethod)]
public Span<float> GetValues() => this.BufferSlice.Span;
public Span<float> GetValues() => new Span<float>(this.bufferPtr, this.Length);
/// <summary>
/// Computes the sum of vectors in 'rowSpan' weighted by weight values, pointed by this <see cref="ResizeKernel"/> instance.

46
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs

@ -0,0 +1,46 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{
/// <content>
/// Contains <see cref="MosaicKernelMap"/>
/// </content>
internal partial class ResizeKernelMap
{
/// <summary>
/// Memory-optimized <see cref="ResizeKernelMap"/> where repeating rows are stored only once.
/// </summary>
private sealed class MosaicKernelMap : ResizeKernelMap
{
private readonly int period;
private readonly int cornerInterval;
public MosaicKernelMap(
MemoryAllocator memoryAllocator,
IResampler sampler,
int sourceSize,
int destinationSize,
float ratio,
float scale,
int radius,
int period,
int cornerInterval)
: base(
memoryAllocator,
sampler,
sourceSize,
destinationSize,
(cornerInterval * 2) + period,
ratio,
scale,
radius)
{
this.cornerInterval = cornerInterval;
this.period = period;
}
}
}
}

70
src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs → src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -11,9 +12,10 @@ using SixLabors.Memory;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{
/// <summary>
/// Holds the <see cref="ResizeKernel"/> values in an optimized contigous memory region.
/// Provides <see cref="ResizeKernel"/> values from an optimized,
/// contigous memory region.
/// </summary>
internal class KernelMap : IDisposable
internal partial class ResizeKernelMap : IDisposable
{
private readonly IResampler sampler;
@ -25,11 +27,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly int radius;
private readonly MemoryHandle pinHandle;
private readonly Buffer2D<float> data;
private readonly ResizeKernel[] kernels;
private KernelMap(
private ResizeKernelMap(
MemoryAllocator memoryAllocator,
IResampler sampler,
int sourceSize,
@ -47,16 +51,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.DestinationSize = destinationSize;
int maxWidth = (radius * 2) + 1;
this.data = memoryAllocator.Allocate2D<float>(maxWidth, bufferHeight, AllocationOptions.Clean);
this.pinHandle = this.data.Memory.Pin();
this.kernels = new ResizeKernel[destinationSize];
}
public int DestinationSize { get; }
/// <summary>
/// Disposes <see cref="KernelMap"/> instance releasing it's backing buffer.
/// Disposes <see cref="ResizeKernelMap"/> instance releasing it's backing buffer.
/// </summary>
public void Dispose()
{
this.pinHandle.Dispose();
this.data.Dispose();
}
@ -73,8 +79,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <param name="destinationSize">The destination size</param>
/// <param name="sourceSize">The source size</param>
/// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations</param>
/// <returns>The <see cref="KernelMap"/></returns>
public static KernelMap Calculate(
/// <returns>The <see cref="ResizeKernelMap"/></returns>
public static ResizeKernelMap Calculate(
IResampler sampler,
int destinationSize,
int sourceSize,
@ -88,25 +94,40 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
scale = 1F;
}
int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize;
int radius = (int)MathF.Ceiling(scale * sampler.Radius);
var result = new KernelMap(
memoryAllocator,
sampler,
sourceSize,
destinationSize,
destinationSize,
ratio,
scale,
radius);
result.BasicInit();
int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize;
float center0 = (ratio - 1) * 0.5f;
int cornerInterval = (int)MathF.Ceiling((radius - center0 - 1) / ratio);
bool useMosaic = 2 * (cornerInterval + period) < destinationSize;
ResizeKernelMap result = useMosaic
? new ResizeKernelMap(
memoryAllocator,
sampler,
sourceSize,
destinationSize,
destinationSize,
ratio,
scale,
radius)
: new MosaicKernelMap(
memoryAllocator,
sampler,
sourceSize,
destinationSize,
ratio,
scale,
radius,
period,
cornerInterval);
result.Init();
return result;
}
private void BasicInit()
protected virtual void Init()
{
for (int i = 0; i < this.DestinationSize; i++)
{
@ -157,7 +178,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <summary>
/// Slices a weights value at the given positions.
/// </summary>
private ResizeKernel CreateKernel(int destIdx, int left, int rightIdx)
private unsafe ResizeKernel CreateKernel(int destIdx, int left, int rightIdx)
{
int length = rightIdx - left + 1;
@ -166,10 +187,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
throw new InvalidOperationException($"Error in KernelMap.CreateKernel({destIdx},{left},{rightIdx}): left > this.data.Width");
}
int flatStartIndex = destIdx * this.data.Width;
Span<float> rowSpan = this.data.GetRowSpan(destIdx);
Memory<float> bufferSlice = this.data.Memory.Slice(flatStartIndex, length);
return new ResizeKernel(left, bufferSlice);
ref float rowReference = ref MemoryMarshal.GetReference(rowSpan);
float* rowPtr = (float*)Unsafe.AsPointer(ref rowReference);
return new ResizeKernel(left, rowPtr, length);
}
}
}

8
src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs → src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs

@ -27,8 +27,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
where TPixel : struct, IPixel<TPixel>
{
// The following fields are not immutable but are optionally created on demand.
private KernelMap horizontalKernelMap;
private KernelMap verticalKernelMap;
private ResizeKernelMap horizontalKernelMap;
private ResizeKernelMap verticalKernelMap;
/// <summary>
/// Initializes a new instance of the <see cref="ResizeProcessor{TPixel}"/> class.
@ -165,13 +165,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{
// Since all image frame dimensions have to be the same we can calculate this for all frames.
MemoryAllocator memoryAllocator = source.GetMemoryAllocator();
this.horizontalKernelMap = KernelMap.Calculate(
this.horizontalKernelMap = ResizeKernelMap.Calculate(
this.Sampler,
this.ResizeRectangle.Width,
sourceRectangle.Width,
memoryAllocator);
this.verticalKernelMap = KernelMap.Calculate(
this.verticalKernelMap = ResizeKernelMap.Calculate(
this.Sampler,
this.ResizeRectangle.Height,
sourceRectangle.Height,

2
tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs

@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
public partial class KernelMapTests
{
/// <summary>
/// Simplified reference implementation for <see cref="KernelMap"/> functionality.
/// Simplified reference implementation for <see cref="ResizeKernelMap"/> functionality.
/// </summary>
internal class ReferenceKernelMap
{

4
tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs

@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
IResampler resampler = TestUtils.GetResampler(resamplerName);
var referenceMap = ReferenceKernelMap.Calculate(resampler, destSize, srcSize);
var kernelMap = KernelMap.Calculate(resampler, destSize, srcSize, Configuration.Default.MemoryAllocator);
var kernelMap = ResizeKernelMap.Calculate(resampler, destSize, srcSize, Configuration.Default.MemoryAllocator);
#if DEBUG
this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n");
@ -103,7 +103,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
}
}
private static string PrintKernelMap(KernelMap kernelMap) =>
private static string PrintKernelMap(ResizeKernelMap kernelMap) =>
PrintKernelMap(kernelMap, km => km.DestinationSize, (km, i) => km.GetKernel(i));
private static string PrintKernelMap(ReferenceKernelMap kernelMap) =>

1
tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs

@ -58,6 +58,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
}
}
// TODO: Merge with the previous theory + add test images
[Theory]
[WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.Bicubic), 1)]
[WithTestPatternImages(100, 100, PixelTypes.Rgba32, nameof(KnownResamplers.Bicubic), 10)]

Loading…
Cancel
Save