|
|
|
@ -13,7 +13,7 @@ namespace ImageSharp.Processors |
|
|
|
/// </summary>
|
|
|
|
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|
|
|
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>
|
|
|
|
public class Convolution2PassProcessor<TColor, TPacked> : ImageSamplingProcessor<TColor, TPacked> |
|
|
|
public class Convolution2PassProcessor<TColor, TPacked> : ImageFilteringProcessor<TColor, TPacked> |
|
|
|
where TColor : struct, IPackedPixel<TPacked> |
|
|
|
where TPacked : struct |
|
|
|
{ |
|
|
|
@ -39,29 +39,37 @@ namespace ImageSharp.Processors |
|
|
|
public float[][] KernelY { get; } |
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
|
public override void Apply(ImageBase<TColor, TPacked> target, ImageBase<TColor, TPacked> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) |
|
|
|
protected override void Apply(ImageBase<TColor, TPacked> source, Rectangle sourceRectangle, int startY, int endY) |
|
|
|
{ |
|
|
|
float[][] kernelX = this.KernelX; |
|
|
|
float[][] kernelY = this.KernelY; |
|
|
|
int width = source.Width; |
|
|
|
int height = source.Height; |
|
|
|
|
|
|
|
ImageBase<TColor, TPacked> firstPass = new Image<TColor, TPacked>(source.Width, source.Height); |
|
|
|
this.ApplyConvolution(firstPass, source, sourceRectangle, startY, endY, kernelX); |
|
|
|
this.ApplyConvolution(target, firstPass, sourceRectangle, startY, endY, kernelY); |
|
|
|
TColor[] target = new TColor[width * height]; |
|
|
|
TColor[] firstPass = new TColor[width * height]; |
|
|
|
|
|
|
|
this.ApplyConvolution(width, height, firstPass, source.Pixels, sourceRectangle, startY, endY, kernelX); |
|
|
|
this.ApplyConvolution(width, height, target, firstPass, sourceRectangle, startY, endY, kernelY); |
|
|
|
|
|
|
|
source.SetPixels(width, height, target); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Applies the process to the specified portion of the specified <see cref="ImageBase{TColor, TPacked}"/> at the specified location
|
|
|
|
/// and with the specified size.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="target">Target image to apply the process to.</param>
|
|
|
|
/// <param name="source">The source image. Cannot be null.</param>
|
|
|
|
/// <param name="width">The image width.</param>
|
|
|
|
/// <param name="height">The image height.</param>
|
|
|
|
/// <param name="target">The target pixels to apply the process to.</param>
|
|
|
|
/// <param name="source">The source pixels. Cannot be null.</param>
|
|
|
|
/// <param name="sourceRectangle">
|
|
|
|
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
|
|
|
|
/// </param>
|
|
|
|
/// <param name="startY">The index of the row within the source image to start processing.</param>
|
|
|
|
/// <param name="endY">The index of the row within the source image to end processing.</param>
|
|
|
|
/// <param name="kernel">The kernel operator.</param>
|
|
|
|
private void ApplyConvolution(ImageBase<TColor, TPacked> target, ImageBase<TColor, TPacked> source, Rectangle sourceRectangle, int startY, int endY, float[][] kernel) |
|
|
|
private void ApplyConvolution(int width, int height, TColor[] target, TColor[] source, Rectangle sourceRectangle, int startY, int endY, float[][] kernel) |
|
|
|
{ |
|
|
|
int kernelHeight = kernel.Length; |
|
|
|
int kernelWidth = kernel[0].Length; |
|
|
|
@ -74,8 +82,8 @@ namespace ImageSharp.Processors |
|
|
|
int maxY = sourceBottom - 1; |
|
|
|
int maxX = endX - 1; |
|
|
|
|
|
|
|
using (PixelAccessor<TColor, TPacked> sourcePixels = source.Lock()) |
|
|
|
using (PixelAccessor<TColor, TPacked> targetPixels = target.Lock()) |
|
|
|
using (PixelAccessor<TColor, TPacked> sourcePixels = source.Lock<TColor, TPacked>(width, height)) |
|
|
|
using (PixelAccessor<TColor, TPacked> targetPixels = target.Lock<TColor, TPacked>(width, height)) |
|
|
|
{ |
|
|
|
Parallel.For( |
|
|
|
startY, |