Skip to content

Commit

Permalink
use double precision in KernelMap calculations
Browse files Browse the repository at this point in the history
  • Loading branch information
antonfirsov committed Nov 28, 2018
1 parent 28bc47c commit b745ffa
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,15 @@ internal ResizeKernel AlterLeftValue(int left)
{
return new ResizeKernel(left, this.bufferPtr, this.Length);
}

internal void Fill(Span<double> values)
{
DebugGuard.IsTrue(values.Length == this.Length, nameof(values), "ResizeKernel.Fill: values.Length != this.Length!");

for (int i = 0; i < this.Length; i++)
{
this.Values[i] = (float)values[i];
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ public PeriodicKernelMap(
IResampler sampler,
int sourceLength,
int destinationLength,
float ratio,
float scale,
double ratio,
double scale,
int radius,
int period,
int cornerInterval)
Expand Down Expand Up @@ -62,8 +62,8 @@ protected override void Initialize()
int bottomStartDest = this.DestinationLength - this.cornerInterval;
for (int i = startOfFirstRepeatedMosaic; i < bottomStartDest; i++)
{
float center = ((i + .5F) * this.ratio) - .5F;
int left = (int)MathF.Ceiling(center - this.radius);
double center = ((i + .5) * this.ratio) - .5;
int left = (int)Math.Ceiling(center - this.radius);
ResizeKernel kernel = this.kernels[i - this.period];
this.kernels[i] = kernel.AlterLeftValue(left);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// </summary>
internal partial class ResizeKernelMap : IDisposable
{
private readonly MemoryAllocator memoryAllocator;

private readonly IResampler sampler;

private readonly int sourceLength;

private readonly float ratio;
private readonly double ratio;

private readonly float scale;
private readonly double scale;

private readonly int radius;

Expand All @@ -39,10 +41,11 @@ private ResizeKernelMap(
int sourceLength,
int destinationLength,
int bufferHeight,
float ratio,
float scale,
double ratio,
double scale,
int radius)
{
this.memoryAllocator = memoryAllocator;
this.sampler = sampler;
this.ratio = ratio;
this.scale = scale;
Expand Down Expand Up @@ -95,19 +98,19 @@ public static ResizeKernelMap Calculate(
int sourceSize,
MemoryAllocator memoryAllocator)
{
float ratio = (float)sourceSize / destinationSize;
float scale = ratio;
double ratio = (double)sourceSize / destinationSize;
double scale = ratio;

if (scale < 1F)
{
scale = 1F;
}

int radius = (int)MathF.Ceiling(scale * sampler.Radius);
int radius = (int)Math.Ceiling(scale * sampler.Radius);
int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize;
float center0 = (ratio - 1) * 0.5f;
float firstNonNegativeLeftVal = (radius - center0 - 1) / ratio;
int cornerInterval = (int)MathF.Ceiling(firstNonNegativeLeftVal);
double center0 = (ratio - 1) * 0.5f;
double firstNonNegativeLeftVal = (radius - center0 - 1) / ratio;
int cornerInterval = (int)Math.Ceiling(firstNonNegativeLeftVal);

// corner case for cornerInteval:
if (firstNonNegativeLeftVal == cornerInterval)
Expand Down Expand Up @@ -159,45 +162,48 @@ protected virtual void Initialize()
/// </summary>
private ResizeKernel BuildKernel(int destRowIndex, int dataRowIndex)
{
float center = ((destRowIndex + .5F) * this.ratio) - .5F;
double center = ((destRowIndex + .5) * this.ratio) - .5;

// Keep inside bounds.
int left = (int)MathF.Ceiling(center - this.radius);
int left = (int)Math.Ceiling(center - this.radius);
if (left < 0)
{
left = 0;
}

int right = (int)MathF.Floor(center + this.radius);
int right = (int)Math.Floor(center + this.radius);
if (right > this.sourceLength - 1)
{
right = this.sourceLength - 1;
}

float sum = 0;

ResizeKernel kernel = this.CreateKernel(dataRowIndex, left, right);

ref float kernelBaseRef = ref MemoryMarshal.GetReference(kernel.Values);

for (int j = left; j <= right; j++)
using (IMemoryOwner<double> tempBuffer = this.memoryAllocator.Allocate<double>(kernel.Length))
{
float value = this.sampler.GetValue((j - center) / this.scale);
sum += value;
Span<double> kernelValues = tempBuffer.GetSpan();
double sum = 0;

// weights[j - left] = weight:
Unsafe.Add(ref kernelBaseRef, j - left) = value;
}
for (int j = left; j <= right; j++)
{
double value = this.sampler.GetValue((float)((j - center) / this.scale));
sum += value;

// Normalize, best to do it here rather than in the pixel loop later on.
if (sum > 0)
{
for (int w = 0; w < kernel.Length; w++)
kernelValues[j - left] = value;
}

// Normalize, best to do it here rather than in the pixel loop later on.
if (sum > 0)
{
// weights[w] = weights[w] / sum:
ref float kRef = ref Unsafe.Add(ref kernelBaseRef, w);
kRef /= sum;
for (int j = 0; j < kernel.Length; j++)
{
// weights[w] = weights[w] / sum:
ref double kRef = ref kernelValues[j];
kRef /= sum;
}
}

kernel.Fill(kernelValues);
}

return kernel;
Expand Down

0 comments on commit b745ffa

Please sign in to comment.