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())); }
protected override void Initialize() { // Build top corner data + one period of the mosaic data: int startOfFirstRepeatedMosaic = this.cornerInterval + this.period; for (int i = 0; i < startOfFirstRepeatedMosaic; i++) { ResizeKernel kernel = this.BuildKernel(i, i); this.kernels[i] = kernel; } // Copy the mosaics: int bottomStartDest = this.DestinationLength - this.cornerInterval; for (int i = startOfFirstRepeatedMosaic; i < bottomStartDest; i++) { double center = ((i + .5) * this.ratio) - .5; int left = (int)TolerantMath.Ceiling(center - this.radius); ResizeKernel kernel = this.kernels[i - this.period]; this.kernels[i] = kernel.AlterLeftValue(left); } // Build bottom corner data: int bottomStartData = this.cornerInterval + this.period; for (int i = 0; i < this.cornerInterval; i++) { ResizeKernel kernel = this.BuildKernel(bottomStartDest + i, bottomStartData + i); this.kernels[bottomStartDest + i] = kernel; } }
/// <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="ResizeKernelMap"/></returns> public static ResizeKernelMap Calculate( IResampler sampler, int destinationSize, int sourceSize, MemoryAllocator memoryAllocator) { double ratio = (double)sourceSize / destinationSize; double scale = ratio; if (scale < 1) { scale = 1; } int radius = (int)TolerantMath.Ceiling(scale * sampler.Radius); // 'ratio' is a rational number. // Multiplying it by LCM(sourceSize, destSize)/sourceSize will result in a whole number "again". // This value is determining the length of the periods in repeating kernel map rows. int period = ImageMaths.LeastCommonMultiple(sourceSize, destinationSize) / sourceSize; // the center position at i == 0: double center0 = (ratio - 1) * 0.5; double firstNonNegativeLeftVal = (radius - center0 - 1) / ratio; // The number of rows building a "stairway" at the top and the bottom of the kernel map // corresponding to the corners of the image. // If we do not normalize the kernel values, these rows also fit the periodic logic, // however, it's just simpler to calculate them separately. int cornerInterval = (int)TolerantMath.Ceiling(firstNonNegativeLeftVal); // If firstNonNegativeLeftVal was an integral value, we need firstNonNegativeLeftVal+1 // instead of Ceiling: if (TolerantMath.AreEqual(firstNonNegativeLeftVal, cornerInterval)) { cornerInterval++; } // If 'cornerInterval' is too big compared to 'period', we can't apply the periodic optimization. // If we don't have at least 2 periods, we go with the basic implementation: bool hasAtLeast2Periods = 2 * (cornerInterval + period) < destinationSize; ResizeKernelMap result = hasAtLeast2Periods ? new PeriodicKernelMap( memoryAllocator, sampler, sourceSize, destinationSize, ratio, scale, radius, period, cornerInterval) : new ResizeKernelMap( memoryAllocator, sampler, sourceSize, destinationSize, destinationSize, ratio, scale, radius); result.Initialize(); return(result); }