/// <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 override void AfterImageApply(Image <TPixel> source, Image <TPixel> destination, Rectangle sourceRectangle) { base.AfterImageApply(source, destination, sourceRectangle); // TODO: An exception in the processing chain can leave these buffers undisposed. We should consider making image processors IDisposable! this.horizontalKernelMap?.Dispose(); this.horizontalKernelMap = null; this.verticalKernelMap?.Dispose(); this.verticalKernelMap = null; }
/// <inheritdoc/> protected override void BeforeImageApply(Image <TPixel> source, Image <TPixel> destination, Rectangle sourceRectangle) { if (!(this.Sampler is NearestNeighborResampler)) { // Since all image frame dimensions have to be the same we can calculate this for all frames. MemoryAllocator memoryAllocator = source.GetMemoryAllocator(); this.horizontalKernelMap = KernelMap.Calculate( this.Sampler, this.ResizeRectangle.Width, sourceRectangle.Width, memoryAllocator); this.verticalKernelMap = KernelMap.Calculate( this.Sampler, this.ResizeRectangle.Height, sourceRectangle.Height, memoryAllocator); } }