Browse Source

MosaicKernelMap works!

af/merge-core
Anton Firszov 7 years ago
parent
commit
3e64863fba
  1. 9
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs
  2. 32
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs
  3. 26
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs
  4. 16
      tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs

9
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs

@ -6,14 +6,12 @@ using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{
/// <summary>
/// Points to a collection of of weights allocated in <see cref="ResizeKernelMap"/>.
/// </summary>
internal unsafe struct ResizeKernel
internal readonly unsafe struct ResizeKernel
{
private readonly float* bufferPtr;
@ -73,5 +71,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
return result;
}
internal ResizeKernel AlterLeftValue(int left)
{
return new ResizeKernel(left, this.bufferPtr, this.Length);
}
}
}

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

@ -1,5 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms
@ -42,9 +45,36 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.period = period;
}
internal override string Info => base.Info + $"|period:{this.period}|cornerInterval:{this.cornerInterval}";
protected override void Initialize()
{
base.Initialize();
// Build top corner data + one period of the mosaic data:
int startOfFirstRepeatedMosaic = this.cornerInterval + this.period;
for (int i = 0; i < startOfFirstRepeatedMosaic; i++)
{
ResizeKernel kernel = this.BuildKernel(i, i);
this.kernels[i] = kernel;
}
// Copy the mosaics:
int bottomStartDest = this.DestinationSize - this.cornerInterval;
for (int i = startOfFirstRepeatedMosaic; i < bottomStartDest; i++)
{
float center = ((i + .5F) * this.ratio) - .5F;
int left = (int)MathF.Ceiling(center - this.radius);
ResizeKernel kernel = this.kernels[i - this.period];
this.kernels[i] = kernel.AlterLeftValue(left);
}
// Build bottom corner data:
int bottomStartData = this.cornerInterval + this.period;
for (int i = 0; i < this.cornerInterval; i++)
{
ResizeKernel kernel = this.BuildKernel(bottomStartDest + i, bottomStartData + i);
this.kernels[bottomStartDest + i] = kernel;
}
}
}
}

26
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs

@ -57,6 +57,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
public int DestinationSize { get; }
internal virtual string Info =>
$"radius:{this.radius}|sourceSize:{this.sourceSize}|destinationSize:{this.DestinationSize}|ratio:{this.ratio}|scale:{this.scale}";
/// <summary>
/// Disposes <see cref="ResizeKernelMap"/> instance releasing it's backing buffer.
/// </summary>
@ -97,11 +100,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
int radius = (int)MathF.Ceiling(scale * sampler.Radius);
int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize;
float center0 = (ratio - 1) * 0.5f;
int cornerInterval = (int)MathF.Ceiling((radius - center0 - 1) / ratio);
float firstNonNegativeLeftVal = (radius - center0 - 1) / ratio;
int cornerInterval = (int)MathF.Ceiling(firstNonNegativeLeftVal);
bool useMosaic = 2 * (cornerInterval + period) < destinationSize;
// corner case for cornerInteval:
if (firstNonNegativeLeftVal == cornerInterval)
{
cornerInterval++;
}
useMosaic = false;
bool useMosaic = 2 * (cornerInterval + period) < destinationSize;
ResizeKernelMap result = useMosaic
? new MosaicKernelMap(
@ -131,14 +139,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
protected virtual void Initialize()
{
for (int destRowIndex = 0; destRowIndex < this.DestinationSize; destRowIndex++)
for (int i = 0; i < this.DestinationSize; i++)
{
ResizeKernel kernel = this.BuildKernelRow(destRowIndex, destRowIndex);
this.kernels[destRowIndex] = kernel;
ResizeKernel kernel = this.BuildKernel(i, i);
this.kernels[i] = kernel;
}
}
private ResizeKernel BuildKernelRow(int destRowIndex, int dataRowIndex)
private ResizeKernel BuildKernel(int destRowIndex, int dataRowIndex)
{
float center = ((destRowIndex + .5F) * this.ratio) - .5F;
@ -157,7 +165,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
float sum = 0;
ResizeKernel kernel = this.GetKernel(dataRowIndex, left, right);
ResizeKernel kernel = this.CreateKernel(dataRowIndex, left, right);
ref float kernelBaseRef = ref MemoryMarshal.GetReference(kernel.Values);
@ -188,7 +196,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// Returns a <see cref="ResizeKernel"/> referencing values of <see cref="data"/>
/// at row <paramref name="dataRowIndex"/>.
/// </summary>
private unsafe ResizeKernel GetKernel(int dataRowIndex, int left, int right)
private unsafe ResizeKernel CreateKernel(int dataRowIndex, int left, int right)
{
int length = right - left + 1;

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

@ -48,6 +48,11 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
{ nameof(KnownResamplers.Lanczos3), 5, 25 },
{ nameof(KnownResamplers.Lanczos3), 5, 50 },
{ nameof(KnownResamplers.Lanczos3), 25, 5 },
{ nameof(KnownResamplers.Lanczos3), 50, 5 },
{ nameof(KnownResamplers.Lanczos3), 49, 5 },
{ nameof(KnownResamplers.Lanczos3), 31, 5 },
{ nameof(KnownResamplers.Lanczos8), 500, 200 },
{ nameof(KnownResamplers.Lanczos8), 100, 10 },
{ nameof(KnownResamplers.Lanczos8), 100, 80 },
@ -75,8 +80,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
var kernelMap = ResizeKernelMap.Calculate(resampler, destSize, srcSize, Configuration.Default.MemoryAllocator);
#if DEBUG
this.Output.WriteLine($"Expected KernelMap:\n{PrintKernelMap(referenceMap)}\n");
this.Output.WriteLine($"Actual KernelMap:\n{PrintKernelMap(kernelMap)}\n");
// this.Output.WriteLine($"Reference KernelMap:\n{PrintKernelMap(referenceMap)}\n");
#endif
for (int i = 0; i < kernelMap.DestinationSize; i++)
@ -92,7 +97,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
Assert.Equal(expectedValues.Length, actualValues.Length);
var comparer = new ApproximateFloatComparer(1e-6f);
var comparer = new ApproximateFloatComparer(1e-4f);
for (int x = 0; x < expectedValues.Length; x++)
{
@ -116,12 +121,17 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
{
var bld = new StringBuilder();
if (kernelMap is ResizeKernelMap actualMap)
{
bld.AppendLine(actualMap.Info);
}
int destinationSize = getDestinationSize(kernelMap);
for (int i = 0; i < destinationSize; i++)
{
ReferenceKernel kernel = getKernel(kernelMap, i);
bld.Append($"({kernel.Left:D3}) || ");
bld.Append($"[{i:D3}] (L{kernel.Left:D3}) || ");
Span<float> span = kernel.Values;
for (int j = 0; j < kernel.Length; j++)

Loading…
Cancel
Save