Browse Source

Resize experiments.

Former-commit-id: 9d1f60a253be59b797be35618a0159dd6ca3b13b
Former-commit-id: c36b547bcc7372a0961397c20fdcdb6fee96070d
Former-commit-id: 4e5618575a0a923629e85880dd75f358d8bfe6eb
af/merge-core
James Jackson-South 10 years ago
parent
commit
cdaa7b99ec
  1. 181
      src/ImageProcessorCore/Samplers/Resampler.cs
  2. 23
      src/ImageProcessorCore/Samplers/Resize.cs
  3. 2
      tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs

181
src/ImageProcessorCore/Samplers/Resampler.cs

@ -11,6 +11,8 @@ namespace ImageProcessorCore.Samplers
/// <summary>
/// Provides methods that allow the resampling of images using various algorithms.
/// <see href="http://www.realtimerendering.com/resources/GraphicsGems/category.html#Image Processing_link"/>
/// <see href="http://www.realtimerendering.com/resources/GraphicsGems/gemsiii/filter_rcg.c"/>
/// </summary>
public abstract class Resampler : ImageSampler
{
@ -52,74 +54,171 @@ namespace ImageProcessorCore.Samplers
/// </returns>
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<Weight> builder = new List<Weight>();
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<Weight> builder = new List<Weight>();
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<Weight> builder = new List<Weight>();
// 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;
//}
/// <summary>
/// Represents the weight to be added to a scaled pixel.
/// </summary>

23
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);

2
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);
}

Loading…
Cancel
Save