Beispiel #1
0
            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()));
            }
Beispiel #2
0
            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);
        }