Browse Source

preparations for implementing MosaicKernelMap

af/merge-core
Anton Firszov 8 years ago
parent
commit
72a6a7e321
  1. 12
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernel.cs
  2. 5
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.MosaicKernelMap.cs
  3. 131
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs
  4. 2
      tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.ReferenceKernelMap.cs
  5. 2
      tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs

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

@ -41,9 +41,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <summary>
/// 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() => new Span<float>(this.bufferPtr, this.Length);
/// <value>The <see cref="Span{T}"/>
/// </value>
public Span<float> Values
{
[MethodImpl(InliningOptions.ShortMethod)]
get => 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.
@ -53,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 Convolve(Span<Vector4> rowSpan)
{
ref float horizontalValues = ref MemoryMarshal.GetReference(this.GetValues());
ref float horizontalValues = ref Unsafe.AsRef<float>(this.bufferPtr);
int left = this.Left;
ref Vector4 vecPtr = ref Unsafe.Add(ref MemoryMarshal.GetReference(rowSpan), left);

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

@ -41,6 +41,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
this.cornerInterval = cornerInterval;
this.period = period;
}
protected override void Initialize()
{
base.Initialize();
}
}
}
}

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

@ -67,7 +67,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
}
/// <summary>
/// Returns a <see cref="ResizeKernel"/> for an index value between 0 and destinationSize - 1.
/// Returns a <see cref="ResizeKernel"/> for an index value between 0 and DestinationSize - 1.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public ref ResizeKernel GetKernel(int destIdx) => ref this.kernels[destIdx];
@ -101,93 +101,104 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
bool useMosaic = 2 * (cornerInterval + period) < destinationSize;
useMosaic = false;
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();
? new MosaicKernelMap(
memoryAllocator,
sampler,
sourceSize,
destinationSize,
ratio,
scale,
radius,
period,
cornerInterval)
: new ResizeKernelMap(
memoryAllocator,
sampler,
sourceSize,
destinationSize,
destinationSize,
ratio,
scale,
radius);
result.Initialize();
return result;
}
protected virtual void Init()
protected virtual void Initialize()
{
for (int i = 0; i < this.DestinationSize; i++)
for (int destRowIndex = 0; destRowIndex < this.DestinationSize; destRowIndex++)
{
float center = ((i + .5F) * this.ratio) - .5F;
ResizeKernel kernel = this.BuildKernelRow(destRowIndex, destRowIndex);
this.kernels[destRowIndex] = kernel;
}
}
// Keep inside bounds.
int left = (int)MathF.Ceiling(center - this.radius);
if (left < 0)
{
left = 0;
}
private ResizeKernel BuildKernelRow(int destRowIndex, int dataRowIndex)
{
float center = ((destRowIndex + .5F) * this.ratio) - .5F;
int right = (int)MathF.Floor(center + this.radius);
if (right > this.sourceSize - 1)
{
right = this.sourceSize - 1;
}
// Keep inside bounds.
int left = (int)MathF.Ceiling(center - this.radius);
if (left < 0)
{
left = 0;
}
float sum = 0;
int right = (int)MathF.Floor(center + this.radius);
if (right > this.sourceSize - 1)
{
right = this.sourceSize - 1;
}
ResizeKernel kernel = this.CreateKernel(i, left, right);
this.kernels[i] = kernel;
float sum = 0;
ref float kernelBaseRef = ref MemoryMarshal.GetReference(kernel.GetValues());
ResizeKernel kernel = this.GetKernel(dataRowIndex, left, right);
for (int j = left; j <= right; j++)
{
float value = this.sampler.GetValue((j - center) / this.scale);
sum += value;
ref float kernelBaseRef = ref MemoryMarshal.GetReference(kernel.Values);
// weights[j - left] = weight:
Unsafe.Add(ref kernelBaseRef, j - left) = value;
}
for (int j = left; j <= right; j++)
{
float value = this.sampler.GetValue((j - center) / this.scale);
sum += value;
// Normalize, best to do it here rather than in the pixel loop later on.
if (sum > 0)
// weights[j - left] = weight:
Unsafe.Add(ref kernelBaseRef, j - left) = 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++)
{
for (int w = 0; w < kernel.Length; w++)
{
// weights[w] = weights[w] / sum:
ref float kRef = ref Unsafe.Add(ref kernelBaseRef, w);
kRef /= sum;
}
// weights[w] = weights[w] / sum:
ref float kRef = ref Unsafe.Add(ref kernelBaseRef, w);
kRef /= sum;
}
}
return kernel;
}
/// <summary>
/// Slices a weights value at the given positions.
/// Returns a <see cref="ResizeKernel"/> referencing values of <see cref="data"/>
/// at row <paramref name="dataRowIndex"/>.
/// </summary>
private unsafe ResizeKernel CreateKernel(int destIdx, int left, int rightIdx)
private unsafe ResizeKernel GetKernel(int dataRowIndex, int left, int right)
{
int length = rightIdx - left + 1;
int length = right - left + 1;
if (length > this.data.Width)
{
throw new InvalidOperationException($"Error in KernelMap.CreateKernel({destIdx},{left},{rightIdx}): left > this.data.Width");
throw new InvalidOperationException(
$"Error in KernelMap.CreateKernel({dataRowIndex},{left},{right}): left > this.data.Width");
}
Span<float> rowSpan = this.data.GetRowSpan(destIdx);
Span<float> rowSpan = this.data.GetRowSpan(dataRowIndex);
ref float rowReference = ref MemoryMarshal.GetReference(rowSpan);
float* rowPtr = (float*)Unsafe.AsPointer(ref rowReference);

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

@ -97,7 +97,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
public static implicit operator ReferenceKernel(ResizeKernel orig)
{
return new ReferenceKernel(orig.Left, orig.GetValues().ToArray());
return new ReferenceKernel(orig.Left, orig.Values.ToArray());
}
}
}

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

@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
Assert.Equal(referenceKernel.Length, kernel.Length);
Assert.Equal(referenceKernel.Left, kernel.Left);
float[] expectedValues = referenceKernel.Values;
Span<float> actualValues = kernel.GetValues();
Span<float> actualValues = kernel.Values;
Assert.Equal(expectedValues.Length, actualValues.Length);

Loading…
Cancel
Save