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> /// <summary>
/// Gets the span representing the portion of the <see cref="ResizeKernelMap"/> that this window covers /// Gets the span representing the portion of the <see cref="ResizeKernelMap"/> that this window covers
/// </summary> /// </summary>
/// <returns>The <see cref="Span{T}"/></returns> /// <value>The <see cref="Span{T}"/>
[MethodImpl(InliningOptions.ShortMethod)] /// </value>
public Span<float> GetValues() => new Span<float>(this.bufferPtr, this.Length); public Span<float> Values
{
[MethodImpl(InliningOptions.ShortMethod)]
get => new Span<float>(this.bufferPtr, this.Length);
}
/// <summary> /// <summary>
/// Computes the sum of vectors in 'rowSpan' weighted by weight values, pointed by this <see cref="ResizeKernel"/> instance. /// 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)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 Convolve(Span<Vector4> rowSpan) 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; int left = this.Left;
ref Vector4 vecPtr = ref Unsafe.Add(ref MemoryMarshal.GetReference(rowSpan), 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.cornerInterval = cornerInterval;
this.period = period; 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> /// <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> /// </summary>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public ref ResizeKernel GetKernel(int destIdx) => ref this.kernels[destIdx]; 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; bool useMosaic = 2 * (cornerInterval + period) < destinationSize;
useMosaic = false;
ResizeKernelMap result = useMosaic ResizeKernelMap result = useMosaic
? new ResizeKernelMap( ? new MosaicKernelMap(
memoryAllocator, memoryAllocator,
sampler, sampler,
sourceSize, sourceSize,
destinationSize, destinationSize,
destinationSize, ratio,
ratio, scale,
scale, radius,
radius) period,
: new MosaicKernelMap( cornerInterval)
memoryAllocator, : new ResizeKernelMap(
sampler, memoryAllocator,
sourceSize, sampler,
destinationSize, sourceSize,
ratio, destinationSize,
scale, destinationSize,
radius, ratio,
period, scale,
cornerInterval); radius);
result.Init(); result.Initialize();
return result; 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. private ResizeKernel BuildKernelRow(int destRowIndex, int dataRowIndex)
int left = (int)MathF.Ceiling(center - this.radius); {
if (left < 0) float center = ((destRowIndex + .5F) * this.ratio) - .5F;
{
left = 0;
}
int right = (int)MathF.Floor(center + this.radius); // Keep inside bounds.
if (right > this.sourceSize - 1) int left = (int)MathF.Ceiling(center - this.radius);
{ if (left < 0)
right = this.sourceSize - 1; {
} 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); float sum = 0;
this.kernels[i] = kernel;
ref float kernelBaseRef = ref MemoryMarshal.GetReference(kernel.GetValues()); ResizeKernel kernel = this.GetKernel(dataRowIndex, left, right);
for (int j = left; j <= right; j++) ref float kernelBaseRef = ref MemoryMarshal.GetReference(kernel.Values);
{
float value = this.sampler.GetValue((j - center) / this.scale);
sum += value;
// weights[j - left] = weight: for (int j = left; j <= right; j++)
Unsafe.Add(ref kernelBaseRef, j - left) = value; {
} 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. // weights[j - left] = weight:
if (sum > 0) 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);
// weights[w] = weights[w] / sum: kRef /= sum;
ref float kRef = ref Unsafe.Add(ref kernelBaseRef, w);
kRef /= sum;
}
} }
} }
return kernel;
} }
/// <summary> /// <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> /// </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) 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); ref float rowReference = ref MemoryMarshal.GetReference(rowSpan);
float* rowPtr = (float*)Unsafe.AsPointer(ref rowReference); 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) 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.Length, kernel.Length);
Assert.Equal(referenceKernel.Left, kernel.Left); Assert.Equal(referenceKernel.Left, kernel.Left);
float[] expectedValues = referenceKernel.Values; float[] expectedValues = referenceKernel.Values;
Span<float> actualValues = kernel.GetValues(); Span<float> actualValues = kernel.Values;
Assert.Equal(expectedValues.Length, actualValues.Length); Assert.Equal(expectedValues.Length, actualValues.Length);

Loading…
Cancel
Save