Ejemplo n.º 1
0
        public static void TriangleWindowOscillatesCorrectly(float x, float expected)
        {
            IResampler sampler = KnownResamplers.Triangle;
            float      result  = sampler.GetValue(x);

            Assert.Equal(result, expected);
        }
Ejemplo n.º 2
0
        /// <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;
                    }
                }
Ejemplo n.º 3
0
        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;
                }
            }
Ejemplo n.º 4
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()));
            }
Ejemplo n.º 5
0
        /// <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);
        }
Ejemplo n.º 6
0
        /// <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);
        }