Browse Source

Resize now 10% faster

Former-commit-id: 8d123c508edef580da7e7226d9dc94b42e0261c2
Former-commit-id: 3fb2cf0b1318711665772efbd37a1e05ea8c39bd
Former-commit-id: 89e4d4123421180721162e5159406483c574bbb2
pull/1/head
James Jackson-South 10 years ago
parent
commit
562bb03b43
  1. 100
      src/ImageProcessorCore/Samplers/Processors/CompandingResizeProcessor.cs
  2. 100
      src/ImageProcessorCore/Samplers/Processors/ResizeProcessor.cs
  3. 37
      tests/ImageProcessorCore.Tests/Processors/Samplers/ResizeTests.cs

100
src/ImageProcessorCore/Samplers/Processors/CompandingResizeProcessor.cs

@ -5,6 +5,7 @@
namespace ImageProcessorCore.Processors
{
using System;
using System.Numerics;
using System.Threading.Tasks;
@ -50,7 +51,11 @@ namespace ImageProcessorCore.Processors
int targetBottom = target.Bounds.Bottom;
int startX = targetRectangle.X;
int endX = targetRectangle.Right;
bool compand = this.Compand;
int minX = Math.Max(targetX, startX);
int maxX = Math.Min(targetRight, endX);
int minY = Math.Max(targetY, startY);
int maxY = Math.Min(targetBottom, endY);
if (this.Sampler is NearestNeighborResampler)
{
@ -62,27 +67,21 @@ namespace ImageProcessorCore.Processors
using (IPixelAccessor<T, TP> targetPixels = target.Lock())
{
Parallel.For(
startY,
endY,
minY,
maxY,
this.ParallelOptions,
y =>
{
if (targetY <= y && y < targetBottom)
// Y coordinates of source points
int originY = (int)((y - startY) * heightFactor);
for (int x = minX; x < maxX; x++)
{
// Y coordinates of source points
int originY = (int)((y - startY) * heightFactor);
for (int x = startX; x < endX; x++)
{
if (targetX <= x && x < targetRight)
{
// X coordinates of source points
targetPixels[x, y] = sourcePixels[(int)((x - startX) * widthFactor), originY];
}
}
this.OnRowProcessed();
// X coordinates of source points
targetPixels[x, y] = sourcePixels[(int)((x - startX) * widthFactor), originY];
}
this.OnRowProcessed();
});
}
@ -99,62 +98,61 @@ namespace ImageProcessorCore.Processors
using (IPixelAccessor<T, TP> firstPassPixels = firstPass.Lock())
using (IPixelAccessor<T, TP> targetPixels = target.Lock())
{
minX = Math.Max(0, startX);
maxX = Math.Min(width, endX);
minY = Math.Max(0, startY);
maxY = Math.Min(height, endY);
Parallel.For(
0,
sourceHeight,
this.ParallelOptions,
y =>
{
for (int x = startX; x < endX; x++)
for (int x = minX; x < maxX; x++)
{
if (x >= 0 && x < width)
{
// Ensure offsets are normalised for cropping and padding.
Weight[] horizontalValues = this.HorizontalWeights[x - startX].Values;
// Destination color components
Vector4 destination = Vector4.Zero;
// Ensure offsets are normalised for cropping and padding.
Weight[] horizontalValues = this.HorizontalWeights[x - startX].Values;
for (int i = 0; i < horizontalValues.Length; i++)
{
Weight xw = horizontalValues[i];
destination += sourcePixels[xw.Index, y].ToVector4().Expand() * xw.Value;
}
// Destination color components
Vector4 destination = Vector4.Zero;
T d = default(T);
d.PackVector(destination.Compress());
firstPassPixels[x, y] = d;
for (int i = 0; i < horizontalValues.Length; i++)
{
Weight xw = horizontalValues[i];
destination += sourcePixels[xw.Index, y].ToVector4().Expand() * xw.Value;
}
T d = default(T);
d.PackVector(destination.Compress());
firstPassPixels[x, y] = d;
}
});
// Now process the rows.
Parallel.For(
startY,
endY,
minY,
maxY,
this.ParallelOptions,
y =>
{
if (y >= 0 && y < height)
// Ensure offsets are normalised for cropping and padding.
Weight[] verticalValues = this.VerticalWeights[y - startY].Values;
for (int x = 0; x < width; x++)
{
// Ensure offsets are normalised for cropping and padding.
Weight[] verticalValues = this.VerticalWeights[y - startY].Values;
// Destination color components
Vector4 destination = Vector4.Zero;
for (int x = 0; x < width; x++)
for (int i = 0; i < verticalValues.Length; i++)
{
// Destination color components
Vector4 destination = Vector4.Zero;
for (int i = 0; i < verticalValues.Length; i++)
{
Weight yw = verticalValues[i];
destination += firstPassPixels[x, yw.Index].ToVector4().Expand() * yw.Value;
}
T d = default(T);
d.PackVector(destination.Compress());
targetPixels[x, y] = d;
Weight yw = verticalValues[i];
destination += firstPassPixels[x, yw.Index].ToVector4().Expand() * yw.Value;
}
T d = default(T);
d.PackVector(destination.Compress());
targetPixels[x, y] = d;
}
this.OnRowProcessed();

100
src/ImageProcessorCore/Samplers/Processors/ResizeProcessor.cs

@ -5,6 +5,7 @@
namespace ImageProcessorCore.Processors
{
using System;
using System.Numerics;
using System.Threading.Tasks;
@ -50,6 +51,11 @@ namespace ImageProcessorCore.Processors
int startX = targetRectangle.X;
int endX = targetRectangle.Right;
int minX = Math.Max(targetX, startX);
int maxX = Math.Min(targetRight, endX);
int minY = Math.Max(targetY, startY);
int maxY = Math.Min(targetBottom, endY);
if (this.Sampler is NearestNeighborResampler)
{
// Scaling factors
@ -60,27 +66,21 @@ namespace ImageProcessorCore.Processors
using (IPixelAccessor<T, TP> targetPixels = target.Lock())
{
Parallel.For(
startY,
endY,
minY,
maxY,
this.ParallelOptions,
y =>
{
if (targetY <= y && y < targetBottom)
// Y coordinates of source points
int originY = (int)((y - startY) * heightFactor);
for (int x = minX; x < maxX; x++)
{
// Y coordinates of source points
int originY = (int)((y - startY) * heightFactor);
for (int x = startX; x < endX; x++)
{
if (targetX <= x && x < targetRight)
{
// X coordinates of source points
targetPixels[x, y] = sourcePixels[(int)((x - startX) * widthFactor), originY];
}
}
this.OnRowProcessed();
// X coordinates of source points
targetPixels[x, y] = sourcePixels[(int)((x - startX) * widthFactor), originY];
}
this.OnRowProcessed();
});
}
@ -97,67 +97,65 @@ namespace ImageProcessorCore.Processors
using (IPixelAccessor<T, TP> firstPassPixels = firstPass.Lock())
using (IPixelAccessor<T, TP> targetPixels = target.Lock())
{
minX = Math.Max(0, startX);
maxX = Math.Min(width, endX);
minY = Math.Max(0, startY);
maxY = Math.Min(height, endY);
Parallel.For(
0,
sourceHeight,
this.ParallelOptions,
y =>
{
for (int x = startX; x < endX; x++)
for (int x = minX; x < maxX; x++)
{
if (x >= 0 && x < width)
{
// Ensure offsets are normalised for cropping and padding.
Weight[] horizontalValues = this.HorizontalWeights[x - startX].Values;
// Destination color components
Vector4 destination = Vector4.Zero;
// Ensure offsets are normalised for cropping and padding.
Weight[] horizontalValues = this.HorizontalWeights[x - startX].Values;
for (int i = 0; i < horizontalValues.Length; i++)
{
Weight xw = horizontalValues[i];
destination += sourcePixels[xw.Index, y].ToVector4() * xw.Value;
}
// Destination color components
Vector4 destination = Vector4.Zero;
T d = default(T);
d.PackVector(destination);
firstPassPixels[x, y] = d;
for (int i = 0; i < horizontalValues.Length; i++)
{
Weight xw = horizontalValues[i];
destination += sourcePixels[xw.Index, y].ToVector4() * xw.Value;
}
T d = default(T);
d.PackVector(destination);
firstPassPixels[x, y] = d;
}
});
// Now process the rows.
Parallel.For(
startY,
endY,
minY,
maxY,
this.ParallelOptions,
y =>
{
if (y >= 0 && y < height)
// Ensure offsets are normalised for cropping and padding.
Weight[] verticalValues = this.VerticalWeights[y - startY].Values;
for (int x = 0; x < width; x++)
{
// Ensure offsets are normalised for cropping and padding.
Weight[] verticalValues = this.VerticalWeights[y - startY].Values;
// Destination color components
Vector4 destination = Vector4.Zero;
for (int x = 0; x < width; x++)
for (int i = 0; i < verticalValues.Length; i++)
{
// Destination color components
Vector4 destination = Vector4.Zero;
for (int i = 0; i < verticalValues.Length; i++)
{
Weight yw = verticalValues[i];
destination += firstPassPixels[x, yw.Index].ToVector4() * yw.Value;
}
T d = default(T);
d.PackVector(destination);
targetPixels[x, y] = d;
Weight yw = verticalValues[i];
destination += firstPassPixels[x, yw.Index].ToVector4() * yw.Value;
}
T d = default(T);
d.PackVector(destination);
targetPixels[x, y] = d;
}
this.OnRowProcessed();
});
}
}
}

37
tests/ImageProcessorCore.Tests/Processors/Samplers/ResizeTests.cs

@ -115,9 +115,9 @@ namespace ImageProcessorCore.Tests
[Theory]
[MemberData("ReSamplers")]
public void ImageShouldResizeWithCropMode(string name, IResampler sampler)
public void ImageShouldResizeWithCropWidthMode(string name, IResampler sampler)
{
name = name + "-Crop";
name = name + "-CropWidth";
if (!Directory.Exists(path))
{
@ -146,6 +146,39 @@ namespace ImageProcessorCore.Tests
}
}
[Theory]
[MemberData("ReSamplers")]
public void ImageShouldResizeWithCropHeightMode(string name, IResampler sampler)
{
name = name + "-CropHeight";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
foreach (string file in Files)
{
using (FileStream stream = File.OpenRead(file))
{
string filename = Path.GetFileNameWithoutExtension(file) + "-" + name + Path.GetExtension(file);
Image image = new Image(stream);
using (FileStream output = File.OpenWrite($"{path}/{filename}"))
{
ResizeOptions options = new ResizeOptions()
{
Sampler = sampler,
Size = new Size(image.Width, image.Height / 2)
};
image.Resize(options, this.ProgressUpdate)
.Save(output);
}
}
}
}
[Theory]
[MemberData("ReSamplers")]
public void ImageShouldResizeWithPadMode(string name, IResampler sampler)

Loading…
Cancel
Save