Browse Source

Refactor EdgeDetectorCompassProcessor<TPixel>

pull/1108/head
Sergio Pedri 6 years ago
parent
commit
58418b43cc
  1. 155
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs

155
src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs

@ -65,77 +65,112 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
int minY = Math.Max(0, startY); int minY = Math.Max(0, startY);
int maxY = Math.Min(source.Height, endY); int maxY = Math.Min(source.Height, endY);
// we need a clean copy for each pass to start from // We need a clean copy for each pass to start from
using (ImageFrame<TPixel> cleanCopy = source.Clone()) using ImageFrame<TPixel> cleanCopy = source.Clone();
using (var processor = new ConvolutionProcessor<TPixel>(this.Configuration, kernels[0], true, this.Source, this.SourceRectangle))
{ {
using (var processor = new ConvolutionProcessor<TPixel>(this.Configuration, kernels[0], true, this.Source, this.SourceRectangle)) processor.Apply(source);
{ }
processor.Apply(source);
}
if (kernels.Length == 1) if (kernels.Length == 1)
{ {
return; return;
} }
int shiftY = startY; int shiftY = startY;
int shiftX = startX; int shiftX = startX;
// Reset offset if necessary. // Reset offset if necessary
if (minX > 0) if (minX > 0)
{ {
shiftX = 0; shiftX = 0;
} }
if (minY > 0) if (minY > 0)
{
shiftY = 0;
}
// Additional runs
for (int i = 1; i < kernels.Length; i++)
{
using ImageFrame<TPixel> pass = cleanCopy.Clone();
using (var processor = new ConvolutionProcessor<TPixel>(this.Configuration, kernels[i], true, this.Source, this.SourceRectangle))
{ {
shiftY = 0; processor.Apply(pass);
} }
var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); ParallelRowIterator.IterateRows(
Rectangle.FromLTRB(minX, minY, maxX, maxY),
this.Configuration,
new RowIntervalAction(source.PixelBuffer, pass.PixelBuffer, minX, maxX, shiftY, shiftX));
}
}
// Additional runs. /// <summary>
// ReSharper disable once ForCanBeConvertedToForeach /// A <see langword="struct"/> implementing the convolution logic for <see cref="EdgeDetectorCompassProcessor{T}"/>.
for (int i = 1; i < kernels.Length; i++) /// </summary>
private readonly struct RowIntervalAction : IRowIntervalAction
{
private readonly Buffer2D<TPixel> targetPixels;
private readonly Buffer2D<TPixel> passPixels;
private readonly int minX;
private readonly int maxX;
private readonly int shiftY;
private readonly int shiftX;
/// <summary>
/// Initializes a new instance of the <see cref="RowIntervalAction"/> struct.
/// </summary>
/// <param name="targetPixels">The target pixel buffer to adjust.</param>
/// <param name="passPixels">The processed pixels for the current iteration. Cannot be null.</param>
/// <param name="minX">The minimum horizontal offset.</param>
/// <param name="maxX">The maximum horizontal offset.</param>
/// <param name="shiftY">The vertical offset shift.</param>
/// <param name="shiftX">The horizontal offset shift.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalAction(
Buffer2D<TPixel> targetPixels,
Buffer2D<TPixel> passPixels,
int minX,
int maxX,
int shiftY,
int shiftX)
{
this.targetPixels = targetPixels;
this.passPixels = passPixels;
this.minX = minX;
this.maxX = maxX;
this.shiftY = shiftY;
this.shiftX = shiftX;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows)
{
for (int y = rows.Min; y < rows.Max; y++)
{ {
using (ImageFrame<TPixel> pass = cleanCopy.Clone()) int offsetY = y - this.shiftY;
ref TPixel passPixelsBase = ref MemoryMarshal.GetReference(this.passPixels.GetRowSpan(offsetY));
ref TPixel targetPixelsBase = ref MemoryMarshal.GetReference(this.targetPixels.GetRowSpan(offsetY));
for (int x = this.minX; x < this.maxX; x++)
{ {
using (var processor = new ConvolutionProcessor<TPixel>(this.Configuration, kernels[i], true, this.Source, this.SourceRectangle)) int offsetX = x - this.shiftX;
{
processor.Apply(pass); // Grab the max components of the two pixels
} ref TPixel currentPassPixel = ref Unsafe.Add(ref passPixelsBase, offsetX);
ref TPixel currentTargetPixel = ref Unsafe.Add(ref targetPixelsBase, offsetX);
Buffer2D<TPixel> passPixels = pass.PixelBuffer;
Buffer2D<TPixel> targetPixels = source.PixelBuffer; var pixelValue = Vector4.Max(
currentPassPixel.ToVector4(),
ParallelRowIterator.IterateRows( currentTargetPixel.ToVector4());
workingRect,
this.Configuration, currentTargetPixel.FromVector4(pixelValue);
rows =>
{
for (int y = rows.Min; y < rows.Max; y++)
{
int offsetY = y - shiftY;
ref TPixel passPixelsBase = ref MemoryMarshal.GetReference(passPixels.GetRowSpan(offsetY));
ref TPixel targetPixelsBase = ref MemoryMarshal.GetReference(targetPixels.GetRowSpan(offsetY));
for (int x = minX; x < maxX; x++)
{
int offsetX = x - shiftX;
// Grab the max components of the two pixels
ref TPixel currentPassPixel = ref Unsafe.Add(ref passPixelsBase, offsetX);
ref TPixel currentTargetPixel = ref Unsafe.Add(ref targetPixelsBase, offsetX);
var pixelValue = Vector4.Max(
currentPassPixel.ToVector4(),
currentTargetPixel.ToVector4());
currentTargetPixel.FromVector4(pixelValue);
}
}
});
} }
} }
} }

Loading…
Cancel
Save