public static void TriangleWindowOscillatesCorrectly(float x, float expected) { IResampler sampler = KnownResamplers.Triangle; float result = sampler.GetValue(x); Assert.Equal(result, expected); }
/// <summary> /// Computes the weights to apply at each pixel when resizing. /// </summary> /// <param name="sampler">The <see cref="IResampler"/></param> /// <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( IResampler sampler, int destinationSize, int sourceSize, MemoryAllocator memoryAllocator) { float ratio = (float)sourceSize / destinationSize; float scale = ratio; if (scale < 1F) { scale = 1F; } float radius = MathF.Ceiling(scale * sampler.Radius); var result = new KernelMap(memoryAllocator, destinationSize, radius); for (int i = 0; i < destinationSize; i++) { float center = ((i + .5F) * ratio) - .5F; // Keep inside bounds. int left = (int)MathF.Ceiling(center - radius); if (left < 0) { left = 0; } int right = (int)MathF.Floor(center + radius); if (right > sourceSize - 1) { right = sourceSize - 1; } float sum = 0; ResizeKernel ws = result.CreateKernel(i, left, right); result.Kernels[i] = ws; ref float weightsBaseRef = ref ws.GetStartReference(); for (int j = left; j <= right; j++) { float weight = sampler.GetValue((j - center) / scale); sum += weight; // weights[j - left] = weight: Unsafe.Add(ref weightsBaseRef, j - left) = weight; } // Normalize, best to do it here rather than in the pixel loop later on. if (sum > 0) { for (int w = 0; w < ws.Length; w++) { // weights[w] = weights[w] / sum: ref float wRef = ref Unsafe.Add(ref weightsBaseRef, w); wRef /= sum; } }
protected static void CalculateWeightsDown(int min, int max, int sourceMin, int sourceMax, float point, IResampler sampler, float scale, ref float weightsRef, int length) { float sum = 0; // Downsampling weights requires more edge sampling plus normalization of the weights for (int x = 0, i = min; i <= max; i++, x++) { int index = i; if (index < sourceMin) { index = sourceMin; } if (index > sourceMax) { index = sourceMax; } float weight = sampler.GetValue((index - point) / scale); sum += weight; Unsafe.Add(ref weightsRef, x) = weight; } if (sum > 0) { for (int i = 0; i < length; i++) { ref float wRef = ref Unsafe.Add(ref weightsRef, i); wRef = wRef / sum; } }
public static ReferenceKernelMap Calculate(IResampler sampler, int destinationSize, int sourceSize, bool normalize = true) { double ratio = (double)sourceSize / destinationSize; double scale = ratio; if (scale < 1F) { scale = 1F; } TolerantMath tolerantMath = TolerantMath.Default; double radius = tolerantMath.Ceiling(scale * sampler.Radius); var result = new List <ReferenceKernel>(); for (int i = 0; i < destinationSize; i++) { double center = ((i + .5) * ratio) - .5; // Keep inside bounds. int left = (int)tolerantMath.Ceiling(center - radius); if (left < 0) { left = 0; } int right = (int)tolerantMath.Floor(center + radius); if (right > sourceSize - 1) { right = sourceSize - 1; } double sum = 0; double[] values = new double[right - left + 1]; for (int j = left; j <= right; j++) { double weight = sampler.GetValue((float)((j - center) / scale)); sum += weight; values[j - left] = weight; } if (sum > 0 && normalize) { for (int w = 0; w < values.Length; w++) { values[w] /= sum; } } float[] floatVals = values.Select(v => (float)v).ToArray(); result.Add(new ReferenceKernel(left, floatVals)); } return(new ReferenceKernelMap(result.ToArray())); }
/// <summary> /// Computes the weights to apply at each pixel when resizing. /// </summary> /// <param name="destinationSize">The destination section size.</param> /// <param name="sourceSize">The source section size.</param> /// <returns> /// The <see cref="T:Weights[]"/>. /// </returns> protected Weights[] PrecomputeWeights(int destinationSize, int sourceSize) { float ratio = (float)sourceSize / destinationSize; float scale = ratio; if (scale < 1F) { scale = 1F; } IResampler sampler = this.Sampler; float radius = (float)Math.Ceiling(scale * sampler.Radius); Weights[] result = new Weights[destinationSize]; for (int i = 0; i < destinationSize; i++) { float center = ((i + .5F) * ratio) - .5F; // Keep inside bounds. int left = (int)Math.Ceiling(center - radius); if (left < 0) { left = 0; } int right = (int)Math.Floor(center + radius); if (right > sourceSize - 1) { right = sourceSize - 1; } float sum = 0; result[i] = new Weights(); Weight[] weights = new Weight[right - left + 1]; for (int j = left; j <= right; j++) { float weight = sampler.GetValue((j - center) / scale); sum += weight; weights[j - left] = new Weight(j, weight); } // Normalise, best to do it here rather than in the pixel loop later on. if (sum > 0) { for (int w = 0; w < weights.Length; w++) { weights[w].Value = weights[w].Value / sum; } } result[i].Values = weights; } return(result); }
/// <summary> /// Computes the weights to apply at each pixel when resizing. /// </summary> /// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations</param> /// <param name="destinationSize">The destination size</param> /// <param name="sourceSize">The source size</param> /// <returns>The <see cref="WeightsBuffer"/></returns> // TODO: Made internal to simplify experimenting with weights data. Make it private when finished figuring out how to optimize all the stuff! internal WeightsBuffer PrecomputeWeights(MemoryManager memoryManager, int destinationSize, int sourceSize) { float ratio = (float)sourceSize / destinationSize; float scale = ratio; if (scale < 1F) { scale = 1F; } IResampler sampler = this.Sampler; float radius = MathF.Ceiling(scale * sampler.Radius); var result = new WeightsBuffer(memoryManager, sourceSize, destinationSize); for (int i = 0; i < destinationSize; i++) { float center = ((i + .5F) * ratio) - .5F; // Keep inside bounds. int left = (int)Math.Ceiling(center - radius); if (left < 0) { left = 0; } int right = (int)Math.Floor(center + radius); if (right > sourceSize - 1) { right = sourceSize - 1; } float sum = 0; WeightsWindow ws = result.GetWeightsWindow(i, left, right); result.Weights[i] = ws; ref float weightsBaseRef = ref ws.GetStartReference(); for (int j = left; j <= right; j++) { float weight = sampler.GetValue((j - center) / scale); sum += weight; // weights[j - left] = weight: Unsafe.Add(ref weightsBaseRef, j - left) = weight; } // Normalize, best to do it here rather than in the pixel loop later on. if (sum > 0) { for (int w = 0; w < ws.Length; w++) { // weights[w] = weights[w] / sum: ref float wRef = ref Unsafe.Add(ref weightsBaseRef, w); wRef = wRef / sum; } }
/// <summary> /// Computes the weights to apply at each pixel when resizing. /// </summary> /// <param name="destinationSize">The destination size</param> /// <param name="sourceSize">The source size</param> /// <returns>The <see cref="WeightsBuffer"/></returns> // TODO: Made internal to simplify experimenting with weights data. Make it protected again when finished figuring out how to optimize all the stuff! internal unsafe WeightsBuffer PrecomputeWeights(int destinationSize, int sourceSize) { float ratio = (float)sourceSize / destinationSize; float scale = ratio; if (scale < 1F) { scale = 1F; } IResampler sampler = this.Sampler; float radius = MathF.Ceiling(scale * sampler.Radius); WeightsBuffer result = new WeightsBuffer(sourceSize, destinationSize); for (int i = 0; i < destinationSize; i++) { float center = ((i + .5F) * ratio) - .5F; // Keep inside bounds. int left = (int)Math.Ceiling(center - radius); if (left < 0) { left = 0; } int right = (int)Math.Floor(center + radius); if (right > sourceSize - 1) { right = sourceSize - 1; } float sum = 0; WeightsWindow ws = result.GetWeightsWindow(i, left, right); result.Weights[i] = ws; float *weights = ws.Ptr; for (int j = left; j <= right; j++) { float weight = sampler.GetValue((j - center) / scale); sum += weight; weights[j - left] = weight; } // Normalise, best to do it here rather than in the pixel loop later on. if (sum > 0) { for (int w = 0; w < ws.Length; w++) { weights[w] = weights[w] / sum; } } } return(result); }