diff --git a/src/ImageProcessorCore/Samplers/Resampler.cs b/src/ImageProcessorCore/Samplers/Resampler.cs index 4b7239af4..0554b18e0 100644 --- a/src/ImageProcessorCore/Samplers/Resampler.cs +++ b/src/ImageProcessorCore/Samplers/Resampler.cs @@ -11,6 +11,8 @@ namespace ImageProcessorCore.Samplers /// /// Provides methods that allow the resampling of images using various algorithms. + /// + /// /// public abstract class Resampler : ImageSampler { @@ -52,74 +54,171 @@ namespace ImageProcessorCore.Samplers /// protected Weights[] PrecomputeWeights(int destinationSize, int sourceSize) { + float xscale = destinationSize / (float)sourceSize; + float width; IResampler sampler = this.Sampler; - float ratio = sourceSize / (float)destinationSize; - float scale = ratio; + float fwidth = sampler.Radius; + float fscale; + double left; + double right; + double weight = 0; + int n = 0; + int k; - // When shrinking, broaden the effective kernel support so that we still + Weights[] result = new Weights[destinationSize]; + + // When expanding, broaden the effective kernel support so that we still // visit every source pixel. - if (scale < 1) + if (xscale < 0) { - scale = 1; - } + width = sampler.Radius / xscale; + fscale = 1 / xscale; - float scaledRadius = (float)Math.Ceiling(scale * sampler.Radius); - Weights[] result = new Weights[destinationSize]; - - // Make the weights slices, one source for each column or row. - Parallel.For( - 0, - destinationSize, - i => + // Make the weights slices, one source for each column or row. + for (int i = 0; i < destinationSize; i++) { - float center = ((i + .5f) * ratio) - 0.5f; - int start = (int)Math.Ceiling(center - scaledRadius); - - if (start < 0) - { - start = 0; - } - - int end = (int)Math.Floor(center + scaledRadius); - - if (end > sourceSize) + float centre = i / xscale; + left = Math.Ceiling(centre - width); + right = Math.Floor(centre + width); + float sum = 0; + result[i] = new Weights(); + List builder = new List(); + for (double j = left; j <= right; j++) { - end = sourceSize; - - if (end < start) + weight = centre - j; + weight = sampler.GetValue((float)weight / fscale) / fscale; + if (j < 0) + { + n = (int)-j; + } + else if (j >= sourceSize) + { + n = (int)((sourceSize - j) + sourceSize - 1); + } + else { - end = start; + n = (int)j; } + + sum++; + builder.Add(new Weight(n, (float)weight)); } + result[i].Values = builder.ToArray(); + result[i].Sum = sum; + } + } + else + { + // Make the weights slices, one source for each column or row. + for (int i = 0; i < destinationSize; i++) + { + float centre = i / xscale; + left = Math.Ceiling(centre - fwidth); + right = Math.Floor(centre + fwidth); float sum = 0; result[i] = new Weights(); List builder = new List(); - for (int a = start; a < end; a++) + for (double j = left; j <= right; j++) { - float w = sampler.GetValue((a - center) / scale); - - if (w < 0 || w > 0) + weight = centre - j; + weight = sampler.GetValue((float)weight); + if (j < 0) { - sum += w; - builder.Add(new Weight(a, w)); + n = (int)-j; + } + else if (j >= sourceSize) + { + n = (int)((sourceSize - j) + sourceSize - 1); + } + else + { + n = (int)j; } - } - // Normalise the values - if (sum > 0 || sum < 0) - { - builder.ForEach(w => w.Value /= sum); + sum++; + builder.Add(new Weight(n, (float)weight)); } result[i].Values = builder.ToArray(); result[i].Sum = sum; - }); + } + } return result; } + //protected Weights[] PrecomputeWeights(int destinationSize, int sourceSize) + //{ + // IResampler sampler = this.Sampler; + // float ratio = sourceSize / (float)destinationSize; + // float scale = ratio; + + // // When shrinking, broaden the effective kernel support so that we still + // // visit every source pixel. + // if (scale < 1) + // { + // scale = 1; + // } + + // float scaledRadius = (float)Math.Ceiling(scale * sampler.Radius); + // Weights[] result = new Weights[destinationSize]; + + // // Make the weights slices, one source for each column or row. + // Parallel.For( + // 0, + // destinationSize, + // i => + // { + // float center = ((i + .5f) * ratio) - 0.5f; + // int start = (int)Math.Ceiling(center - scaledRadius); + + // if (start < 0) + // { + // start = 0; + // } + + // int end = (int)Math.Floor(center + scaledRadius); + + // if (end > sourceSize) + // { + // end = sourceSize; + + // if (end < start) + // { + // end = start; + // } + // } + + // float sum = 0; + // result[i] = new Weights(); + + // List builder = new List(); + // for (int a = start; a < end; a++) + // { + // float w = sampler.GetValue((a - center) / scale); + + // if (w < 0 || w > 0) + // { + // sum += w; + // builder.Add(new Weight(a, w)); + // } + // } + + // // Normalise the values + // if (sum > 0 || sum < 0) + // { + // builder.ForEach(w => w.Value /= sum); + // } + + // result[i].Values = builder.ToArray(); + // result[i].Sum = sum; + // }); + + // return result; + //} + /// /// Represents the weight to be added to a scaled pixel. /// diff --git a/src/ImageProcessorCore/Samplers/Resize.cs b/src/ImageProcessorCore/Samplers/Resize.cs index ce4d513ac..dc6a92f5e 100644 --- a/src/ImageProcessorCore/Samplers/Resize.cs +++ b/src/ImageProcessorCore/Samplers/Resize.cs @@ -100,18 +100,27 @@ namespace ImageProcessorCore.Samplers { for (int x = startX; x < endX; x++) { + float sum = this.HorizontalWeights[x].Sum; Weight[] horizontalValues = this.HorizontalWeights[x].Values; // Destination color components Color destination = new Color(); - foreach (Weight xw in horizontalValues) + for (int i = 0; i < sum; i++) { + Weight xw = horizontalValues[i]; int originX = xw.Index; Color sourceColor = compand ? Color.Expand(source[originX, y]) : source[originX, y]; destination += sourceColor * xw.Value; } + //foreach (Weight xw in horizontalValues) + //{ + // int originX = xw.Index; + // Color sourceColor = compand ? Color.Expand(source[originX, y]) : source[originX, y]; + // destination += sourceColor * xw.Value; + //} + if (compand) { destination = Color.Compress(destination); @@ -129,6 +138,7 @@ namespace ImageProcessorCore.Samplers { if (y >= targetY && y < targetBottom) { + float sum = this.VerticalWeights[y].Sum; Weight[] verticalValues = this.VerticalWeights[y].Values; for (int x = startX; x < endX; x++) @@ -136,14 +146,23 @@ namespace ImageProcessorCore.Samplers // Destination color components Color destination = new Color(); - foreach (Weight yw in verticalValues) + for (int i = 0; i < sum; i++) { + Weight yw = verticalValues[i]; int originY = yw.Index; int originX = x; Color sourceColor = compand ? Color.Expand(this.firstPass[originX, originY]) : this.firstPass[originX, originY]; destination += sourceColor * yw.Value; } + //foreach (Weight yw in verticalValues) + //{ + // int originY = yw.Index; + // int originX = x; + // Color sourceColor = compand ? Color.Expand(this.firstPass[originX, originY]) : this.firstPass[originX, originY]; + // destination += sourceColor * yw.Value; + //} + if (compand) { destination = Color.Compress(destination); diff --git a/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs b/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs index 925d1340b..c419ae560 100644 --- a/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs +++ b/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs @@ -92,7 +92,7 @@ string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file); using (FileStream output = File.OpenWrite($"TestOutput/Resize/{filename}")) { - image.Resize(image.Width / 2, image.Height / 2, sampler, false, this.ProgressUpdate) + image.Resize(image.Width * 2, image.Height * 2, sampler, false, this.ProgressUpdate) .Save(output); }