mirror of https://github.com/SixLabors/ImageSharp
committed by
GitHub
237 changed files with 4899 additions and 3389 deletions
@ -0,0 +1,22 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp |
|||
{ |
|||
/// <summary>
|
|||
/// A visitor to implement double-dispatch pattern in order to apply pixel-specific operations
|
|||
/// on non-generic <see cref="Image"/> instances. The operation is dispatched by <see cref="Image.AcceptVisitor"/>.
|
|||
/// </summary>
|
|||
internal interface IImageVisitor |
|||
{ |
|||
/// <summary>
|
|||
/// Provides a pixel-specific implementation for a given operation.
|
|||
/// </summary>
|
|||
/// <param name="image">The image.</param>
|
|||
/// <typeparam name="TPixel">The pixel type.</typeparam>
|
|||
void Visit<TPixel>(Image<TPixel> image) |
|||
where TPixel : struct, IPixel<TPixel>; |
|||
} |
|||
} |
|||
@ -0,0 +1,123 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System.IO; |
|||
|
|||
using SixLabors.ImageSharp.Advanced; |
|||
using SixLabors.ImageSharp.Formats; |
|||
using SixLabors.ImageSharp.Metadata; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.Primitives; |
|||
|
|||
namespace SixLabors.ImageSharp |
|||
{ |
|||
/// <summary>
|
|||
/// Encapsulates an image, which consists of the pixel data for a graphics image and its attributes.
|
|||
/// For the non-generic <see cref="Image"/> type, the pixel type is only known at runtime.
|
|||
/// <see cref="Image"/> is always implemented by a pixel-specific <see cref="Image{TPixel}"/> instance.
|
|||
/// </summary>
|
|||
public abstract partial class Image : IImage, IConfigurable |
|||
{ |
|||
private Size size; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Image"/> class.
|
|||
/// </summary>
|
|||
/// <param name="configuration">The <see cref="Configuration"/>.</param>
|
|||
/// <param name="pixelType">The <see cref="PixelTypeInfo"/>.</param>
|
|||
/// <param name="metadata">The <see cref="ImageMetadata"/>.</param>
|
|||
/// <param name="size">The <see cref="size"/>.</param>
|
|||
protected Image(Configuration configuration, PixelTypeInfo pixelType, ImageMetadata metadata, Size size) |
|||
{ |
|||
this.Configuration = configuration ?? Configuration.Default; |
|||
this.PixelType = pixelType; |
|||
this.size = size; |
|||
this.Metadata = metadata ?? new ImageMetadata(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Image"/> class.
|
|||
/// </summary>
|
|||
internal Image( |
|||
Configuration configuration, |
|||
PixelTypeInfo pixelType, |
|||
ImageMetadata metadata, |
|||
int width, |
|||
int height) |
|||
: this(configuration, pixelType, metadata, new Size(width, height)) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the <see cref="Configuration"/>.
|
|||
/// </summary>
|
|||
protected Configuration Configuration { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
public PixelTypeInfo PixelType { get; } |
|||
|
|||
/// <inheritdoc />
|
|||
public int Width => this.size.Width; |
|||
|
|||
/// <inheritdoc />
|
|||
public int Height => this.size.Height; |
|||
|
|||
/// <inheritdoc/>
|
|||
public ImageMetadata Metadata { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the pixel buffer.
|
|||
/// </summary>
|
|||
Configuration IConfigurable.Configuration => this.Configuration; |
|||
|
|||
/// <inheritdoc />
|
|||
public abstract void Dispose(); |
|||
|
|||
/// <summary>
|
|||
/// Saves the image to the given stream using the given image encoder.
|
|||
/// </summary>
|
|||
/// <param name="stream">The stream to save the image to.</param>
|
|||
/// <param name="encoder">The encoder to save the image with.</param>
|
|||
/// <exception cref="System.ArgumentNullException">Thrown if the stream or encoder is null.</exception>
|
|||
public void Save(Stream stream, IImageEncoder encoder) |
|||
{ |
|||
Guard.NotNull(stream, nameof(stream)); |
|||
Guard.NotNull(encoder, nameof(encoder)); |
|||
|
|||
EncodeVisitor visitor = new EncodeVisitor(encoder, stream); |
|||
this.AcceptVisitor(visitor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Accept a <see cref="IImageVisitor"/>.
|
|||
/// Implemented by <see cref="Image{TPixel}"/> invoking <see cref="IImageVisitor.Visit{TPixel}"/>
|
|||
/// with the pixel type of the image.
|
|||
/// </summary>
|
|||
internal abstract void AcceptVisitor(IImageVisitor visitor); |
|||
|
|||
/// <summary>
|
|||
/// Update the size of the image after mutation.
|
|||
/// </summary>
|
|||
/// <param name="size">The <see cref="Size"/>.</param>
|
|||
protected void UpdateSize(Size size) => this.size = size; |
|||
|
|||
private class EncodeVisitor : IImageVisitor |
|||
{ |
|||
private readonly IImageEncoder encoder; |
|||
|
|||
private readonly Stream stream; |
|||
|
|||
public EncodeVisitor(IImageEncoder encoder, Stream stream) |
|||
{ |
|||
this.encoder = encoder; |
|||
this.stream = stream; |
|||
} |
|||
|
|||
public void Visit<TPixel>(Image<TPixel> image) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
this.encoder.Encode(image, this.stream); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,40 +1,36 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing.Processors.Transforms; |
|||
using SixLabors.Primitives; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing |
|||
{ |
|||
/// <summary>
|
|||
/// Adds extensions that allow the application of cropping operations to the <see cref="Image{TPixel}"/> type.
|
|||
/// Defines extensions that allow the application of cropping operations on an <see cref="Image"/>
|
|||
/// using Mutate/Clone.
|
|||
/// </summary>
|
|||
public static class CropExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Crops an image to the given width and height.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="source">The image to resize.</param>
|
|||
/// <param name="width">The target image width.</param>
|
|||
/// <param name="height">The target image height.</param>
|
|||
/// <returns>The <see cref="Image{TPixel}"/></returns>
|
|||
public static IImageProcessingContext<TPixel> Crop<TPixel>(this IImageProcessingContext<TPixel> source, int width, int height) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
=> Crop(source, new Rectangle(0, 0, width, height)); |
|||
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
|
|||
public static IImageProcessingContext Crop(this IImageProcessingContext source, int width, int height) => |
|||
Crop(source, new Rectangle(0, 0, width, height)); |
|||
|
|||
/// <summary>
|
|||
/// Crops an image to the given rectangle.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="source">The image to crop.</param>
|
|||
/// <param name="cropRectangle">
|
|||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to retain.
|
|||
/// </param>
|
|||
/// <returns>The <see cref="Image{TPixel}"/></returns>
|
|||
public static IImageProcessingContext<TPixel> Crop<TPixel>(this IImageProcessingContext<TPixel> source, Rectangle cropRectangle) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
=> source.ApplyProcessor(new CropProcessor<TPixel>(cropRectangle, source.GetCurrentSize())); |
|||
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
|
|||
public static IImageProcessingContext Crop(this IImageProcessingContext source, Rectangle cropRectangle) => |
|||
source.ApplyProcessor(new CropProcessor(cropRectangle, source.GetCurrentSize())); |
|||
} |
|||
} |
|||
@ -1,35 +1,31 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing.Processors.Transforms; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing |
|||
{ |
|||
/// <summary>
|
|||
/// Adds extensions that allow the application of entropy cropping operations to the <see cref="Image{TPixel}"/> type.
|
|||
/// Defines extensions that allow the application of entropy cropping operations on an <see cref="Image"/>
|
|||
/// using Mutate/Clone.
|
|||
/// </summary>
|
|||
public static class EntropyCropExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Crops an image to the area of greatest entropy using a threshold for entropic density of <value>.5F</value>.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="source">The image to crop.</param>
|
|||
/// <returns>The <see cref="Image{TPixel}"/></returns>
|
|||
public static IImageProcessingContext<TPixel> EntropyCrop<TPixel>(this IImageProcessingContext<TPixel> source) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
=> source.ApplyProcessor(new EntropyCropProcessor<TPixel>()); |
|||
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
|
|||
public static IImageProcessingContext EntropyCrop(this IImageProcessingContext source) => |
|||
source.ApplyProcessor(new EntropyCropProcessor()); |
|||
|
|||
/// <summary>
|
|||
/// Crops an image to the area of greatest entropy.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="source">The image to crop.</param>
|
|||
/// <param name="threshold">The threshold for entropic density.</param>
|
|||
/// <returns>The <see cref="Image{TPixel}"/></returns>
|
|||
public static IImageProcessingContext<TPixel> EntropyCrop<TPixel>(this IImageProcessingContext<TPixel> source, float threshold) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
=> source.ApplyProcessor(new EntropyCropProcessor<TPixel>(threshold)); |
|||
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
|
|||
public static IImageProcessingContext EntropyCrop(this IImageProcessingContext source, float threshold) => |
|||
source.ApplyProcessor(new EntropyCropProcessor(threshold)); |
|||
} |
|||
} |
|||
@ -1,25 +1,23 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing.Processors.Transforms; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing |
|||
{ |
|||
/// <summary>
|
|||
/// Adds extensions that allow the application of flipping operations to the <see cref="Image{TPixel}"/> type.
|
|||
/// Defines extensions that allow the application of flipping operations on an <see cref="Image"/>
|
|||
/// using Mutate/Clone.
|
|||
/// </summary>
|
|||
public static class FlipExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Flips an image by the given instructions.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="source">The image to rotate, flip, or both.</param>
|
|||
/// <param name="flipMode">The <see cref="FlipMode"/> to perform the flip.</param>
|
|||
/// <returns>The <see cref="Image{TPixel}"/></returns>
|
|||
public static IImageProcessingContext<TPixel> Flip<TPixel>(this IImageProcessingContext<TPixel> source, FlipMode flipMode) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
=> source.ApplyProcessor(new FlipProcessor<TPixel>(flipMode)); |
|||
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
|
|||
public static IImageProcessingContext Flip(this IImageProcessingContext source, FlipMode flipMode) |
|||
=> source.ApplyProcessor(new FlipProcessor(flipMode)); |
|||
} |
|||
} |
|||
@ -1,50 +1,47 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing.Processors.Convolution; |
|||
using SixLabors.Primitives; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing |
|||
{ |
|||
/// <summary>
|
|||
/// Adds Gaussian sharpening extensions to the <see cref="Image{TPixel}"/> type.
|
|||
/// Defines Gaussian sharpening extensions to apply on an <see cref="Image"/>
|
|||
/// using Mutate/Clone.
|
|||
/// </summary>
|
|||
public static class GaussianSharpenExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Applies a Gaussian sharpening filter to the image.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
|
|||
public static IImageProcessingContext<TPixel> GaussianSharpen<TPixel>(this IImageProcessingContext<TPixel> source) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
=> source.ApplyProcessor(new GaussianSharpenProcessor<TPixel>()); |
|||
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
|
|||
public static IImageProcessingContext GaussianSharpen(this IImageProcessingContext source) => |
|||
source.ApplyProcessor(new GaussianSharpenProcessor()); |
|||
|
|||
/// <summary>
|
|||
/// Applies a Gaussian sharpening filter to the image.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="sigma">The 'sigma' value representing the weight of the blur.</param>
|
|||
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
|
|||
public static IImageProcessingContext<TPixel> GaussianSharpen<TPixel>(this IImageProcessingContext<TPixel> source, float sigma) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
=> source.ApplyProcessor(new GaussianSharpenProcessor<TPixel>(sigma)); |
|||
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
|
|||
public static IImageProcessingContext GaussianSharpen(this IImageProcessingContext source, float sigma) => |
|||
source.ApplyProcessor(new GaussianSharpenProcessor(sigma)); |
|||
|
|||
/// <summary>
|
|||
/// Applies a Gaussian sharpening filter to the image.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="sigma">The 'sigma' value representing the weight of the blur.</param>
|
|||
/// <param name="rectangle">
|
|||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
|
|||
/// </param>
|
|||
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
|
|||
public static IImageProcessingContext<TPixel> GaussianSharpen<TPixel>(this IImageProcessingContext<TPixel> source, float sigma, Rectangle rectangle) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
=> source.ApplyProcessor(new GaussianSharpenProcessor<TPixel>(sigma), rectangle); |
|||
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
|
|||
public static IImageProcessingContext GaussianSharpen( |
|||
this IImageProcessingContext source, |
|||
float sigma, |
|||
Rectangle rectangle) => |
|||
source.ApplyProcessor(new GaussianSharpenProcessor(sigma), rectangle); |
|||
} |
|||
} |
|||
} |
|||
@ -1,62 +1,32 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing.Processors.Normalization; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing |
|||
{ |
|||
/// <summary>
|
|||
/// Adds extension that allow the adjustment of the contrast of an image via its histogram.
|
|||
/// Defines extension that allow the adjustment of the contrast of an image via its histogram.
|
|||
/// </summary>
|
|||
public static class HistogramEqualizationExtension |
|||
{ |
|||
/// <summary>
|
|||
/// Equalizes the histogram of an image to increases the contrast.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
|
|||
public static IImageProcessingContext<TPixel> HistogramEqualization<TPixel>(this IImageProcessingContext<TPixel> source) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
=> HistogramEqualization(source, HistogramEqualizationOptions.Default); |
|||
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
|
|||
public static IImageProcessingContext HistogramEqualization(this IImageProcessingContext source) => |
|||
HistogramEqualization(source, HistogramEqualizationOptions.Default); |
|||
|
|||
/// <summary>
|
|||
/// Equalizes the histogram of an image to increases the contrast.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="options">The histogram equalization options to use.</param>
|
|||
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
|
|||
public static IImageProcessingContext<TPixel> HistogramEqualization<TPixel>(this IImageProcessingContext<TPixel> source, HistogramEqualizationOptions options) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
=> source.ApplyProcessor(GetProcessor<TPixel>(options)); |
|||
|
|||
private static HistogramEqualizationProcessor<TPixel> GetProcessor<TPixel>(HistogramEqualizationOptions options) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
HistogramEqualizationProcessor<TPixel> processor; |
|||
|
|||
switch (options.Method) |
|||
{ |
|||
case HistogramEqualizationMethod.Global: |
|||
processor = new GlobalHistogramEqualizationProcessor<TPixel>(options.LuminanceLevels, options.ClipHistogram, options.ClipLimitPercentage); |
|||
break; |
|||
|
|||
case HistogramEqualizationMethod.AdaptiveTileInterpolation: |
|||
processor = new AdaptiveHistEqualizationProcessor<TPixel>(options.LuminanceLevels, options.ClipHistogram, options.ClipLimitPercentage, options.Tiles); |
|||
break; |
|||
|
|||
case HistogramEqualizationMethod.AdaptiveSlidingWindow: |
|||
processor = new AdaptiveHistEqualizationSWProcessor<TPixel>(options.LuminanceLevels, options.ClipHistogram, options.ClipLimitPercentage, options.Tiles); |
|||
break; |
|||
|
|||
default: |
|||
processor = new GlobalHistogramEqualizationProcessor<TPixel>(options.LuminanceLevels, options.ClipHistogram, options.ClipLimitPercentage); |
|||
break; |
|||
} |
|||
|
|||
return processor; |
|||
} |
|||
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
|
|||
public static IImageProcessingContext HistogramEqualization( |
|||
this IImageProcessingContext source, |
|||
HistogramEqualizationOptions options) => |
|||
source.ApplyProcessor(HistogramEqualizationProcessor.FromOptions(options)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.Processing.Processors; |
|||
using SixLabors.Memory; |
|||
using SixLabors.Primitives; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing |
|||
{ |
|||
/// <summary>
|
|||
/// A pixel-agnostic interface to queue up image operations to apply to an image.
|
|||
/// </summary>
|
|||
public interface IImageProcessingContext |
|||
{ |
|||
/// <summary>
|
|||
/// Gets a reference to the <see cref="MemoryAllocator" /> used to allocate buffers
|
|||
/// for this context.
|
|||
/// </summary>
|
|||
MemoryAllocator MemoryAllocator { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the image dimensions at the current point in the processing pipeline.
|
|||
/// </summary>
|
|||
/// <returns>The <see cref="Rectangle"/>.</returns>
|
|||
Size GetCurrentSize(); |
|||
|
|||
/// <summary>
|
|||
/// Adds the processor to the current set of image operations to be applied.
|
|||
/// </summary>
|
|||
/// <param name="processor">The processor to apply.</param>
|
|||
/// <param name="rectangle">The area to apply it to.</param>
|
|||
/// <returns>The current operations class to allow chaining of operations.</returns>
|
|||
IImageProcessingContext ApplyProcessor(IImageProcessor processor, Rectangle rectangle); |
|||
|
|||
/// <summary>
|
|||
/// Adds the processor to the current set of image operations to be applied.
|
|||
/// </summary>
|
|||
/// <param name="processor">The processor to apply.</param>
|
|||
/// <returns>The current operations class to allow chaining of operations.</returns>
|
|||
IImageProcessingContext ApplyProcessor(IImageProcessor processor); |
|||
} |
|||
} |
|||
@ -1,50 +1,46 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing.Processors.Effects; |
|||
using SixLabors.Primitives; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing |
|||
{ |
|||
/// <summary>
|
|||
/// Adds pixelation effect extensions to the <see cref="Image{TPixel}"/> type.
|
|||
/// Defines pixelation effect extensions applicable on an <see cref="Image"/>
|
|||
/// using Mutate/Clone.
|
|||
/// </summary>
|
|||
public static class PixelateExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Pixelates an image with the given pixel size.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
|
|||
public static IImageProcessingContext<TPixel> Pixelate<TPixel>(this IImageProcessingContext<TPixel> source) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
=> Pixelate(source, 4); |
|||
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
|
|||
public static IImageProcessingContext Pixelate(this IImageProcessingContext source) => Pixelate(source, 4); |
|||
|
|||
/// <summary>
|
|||
/// Pixelates an image with the given pixel size.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="size">The size of the pixels.</param>
|
|||
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
|
|||
public static IImageProcessingContext<TPixel> Pixelate<TPixel>(this IImageProcessingContext<TPixel> source, int size) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
=> source.ApplyProcessor(new PixelateProcessor<TPixel>(size)); |
|||
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
|
|||
public static IImageProcessingContext Pixelate(this IImageProcessingContext source, int size) => |
|||
source.ApplyProcessor(new PixelateProcessor(size)); |
|||
|
|||
/// <summary>
|
|||
/// Pixelates an image with the given pixel size.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="source">The image this method extends.</param>
|
|||
/// <param name="size">The size of the pixels.</param>
|
|||
/// <param name="rectangle">
|
|||
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
|
|||
/// </param>
|
|||
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
|
|||
public static IImageProcessingContext<TPixel> Pixelate<TPixel>(this IImageProcessingContext<TPixel> source, int size, Rectangle rectangle) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
=> source.ApplyProcessor(new PixelateProcessor<TPixel>(size), rectangle); |
|||
/// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
|
|||
public static IImageProcessingContext Pixelate( |
|||
this IImageProcessingContext source, |
|||
int size, |
|||
Rectangle rectangle) => |
|||
source.ApplyProcessor(new PixelateProcessor(size), rectangle); |
|||
} |
|||
} |
|||
@ -0,0 +1,63 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Primitives; |
|||
using SixLabors.Primitives; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
|||
{ |
|||
/// <summary>
|
|||
/// Applies box blur processing to the image.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
internal class BoxBlurProcessor<TPixel> : ImageProcessor<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
private readonly BoxBlurProcessor definition; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BoxBlurProcessor{TPixel}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="definition">The <see cref="BoxBlurProcessor"/> defining the processor parameters.</param>
|
|||
public BoxBlurProcessor(BoxBlurProcessor definition) |
|||
{ |
|||
this.definition = definition; |
|||
int kernelSize = (definition.Radius * 2) + 1; |
|||
this.KernelX = CreateBoxKernel(kernelSize); |
|||
this.KernelY = this.KernelX.Transpose(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the horizontal gradient operator.
|
|||
/// </summary>
|
|||
public DenseMatrix<float> KernelX { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the vertical gradient operator.
|
|||
/// </summary>
|
|||
public DenseMatrix<float> KernelY { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnFrameApply( |
|||
ImageFrame<TPixel> source, |
|||
Rectangle sourceRectangle, |
|||
Configuration configuration) => |
|||
new Convolution2PassProcessor<TPixel>(this.KernelX, this.KernelY, false).Apply( |
|||
source, |
|||
sourceRectangle, |
|||
configuration); |
|||
|
|||
/// <summary>
|
|||
/// Create a 1 dimensional Box kernel.
|
|||
/// </summary>
|
|||
/// <param name="kernelSize">The maximum size of the kernel in either direction.</param>
|
|||
/// <returns>The <see cref="DenseMatrix{T}"/>.</returns>
|
|||
private static DenseMatrix<float> CreateBoxKernel(int kernelSize) |
|||
{ |
|||
var kernel = new DenseMatrix<float>(kernelSize, 1); |
|||
kernel.Fill(1F / kernelSize); |
|||
return kernel; |
|||
} |
|||
} |
|||
} |
|||
@ -1,9 +1,10 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.InteropServices; |
|||
|
|||
using SixLabors.ImageSharp.Memory; |
|||
using SixLabors.ImageSharp.ParallelUtils; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
@ -0,0 +1,93 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
|
|||
using SixLabors.ImageSharp.Primitives; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
|||
{ |
|||
internal static class ConvolutionProcessorHelpers |
|||
{ |
|||
/// <summary>
|
|||
/// Kernel radius is calculated using the minimum viable value.
|
|||
/// See <see href="http://chemaguerra.com/gaussian-filter-radius/"/>.
|
|||
/// </summary>
|
|||
internal static int GetDefaultGaussianRadius(float sigma) |
|||
{ |
|||
return (int)MathF.Ceiling(sigma * 3); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Create a 1 dimensional Gaussian kernel using the Gaussian G(x) function.
|
|||
/// </summary>
|
|||
/// <returns>The <see cref="DenseMatrix{T}"/>.</returns>
|
|||
internal static DenseMatrix<float> CreateGaussianBlurKernel(int size, float weight) |
|||
{ |
|||
var kernel = new DenseMatrix<float>(size, 1); |
|||
|
|||
float sum = 0F; |
|||
float midpoint = (size - 1) / 2F; |
|||
|
|||
for (int i = 0; i < size; i++) |
|||
{ |
|||
float x = i - midpoint; |
|||
float gx = ImageMaths.Gaussian(x, weight); |
|||
sum += gx; |
|||
kernel[0, i] = gx; |
|||
} |
|||
|
|||
// Normalize kernel so that the sum of all weights equals 1
|
|||
for (int i = 0; i < size; i++) |
|||
{ |
|||
kernel[0, i] /= sum; |
|||
} |
|||
|
|||
return kernel; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Create a 1 dimensional Gaussian kernel using the Gaussian G(x) function
|
|||
/// </summary>
|
|||
/// <returns>The <see cref="DenseMatrix{T}"/>.</returns>
|
|||
internal static DenseMatrix<float> CreateGaussianSharpenKernel(int size, float weight) |
|||
{ |
|||
var kernel = new DenseMatrix<float>(size, 1); |
|||
|
|||
float sum = 0; |
|||
|
|||
float midpoint = (size - 1) / 2F; |
|||
for (int i = 0; i < size; i++) |
|||
{ |
|||
float x = i - midpoint; |
|||
float gx = ImageMaths.Gaussian(x, weight); |
|||
sum += gx; |
|||
kernel[0, i] = gx; |
|||
} |
|||
|
|||
// Invert the kernel for sharpening.
|
|||
int midpointRounded = (int)midpoint; |
|||
for (int i = 0; i < size; i++) |
|||
{ |
|||
if (i == midpointRounded) |
|||
{ |
|||
// Calculate central value
|
|||
kernel[0, i] = (2F * sum) - kernel[0, i]; |
|||
} |
|||
else |
|||
{ |
|||
// invert value
|
|||
kernel[0, i] = -kernel[0, i]; |
|||
} |
|||
} |
|||
|
|||
// Normalize kernel so that the sum of all weights equals 1
|
|||
for (int i = 0; i < size; i++) |
|||
{ |
|||
kernel[0, i] /= sum; |
|||
} |
|||
|
|||
return kernel; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Primitives; |
|||
using SixLabors.ImageSharp.Processing.Processors.Filters; |
|||
using SixLabors.Primitives; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
|||
{ |
|||
/// <summary>
|
|||
/// Defines a processor that detects edges within an image using a single two dimensional matrix.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
internal class EdgeDetectorProcessor<TPixel> : ImageProcessor<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="EdgeDetectorProcessor{TPixel}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="kernelXY">The 2d gradient operator.</param>
|
|||
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
|
|||
public EdgeDetectorProcessor(in DenseMatrix<float> kernelXY, bool grayscale) |
|||
{ |
|||
this.KernelXY = kernelXY; |
|||
this.Grayscale = grayscale; |
|||
} |
|||
|
|||
public bool Grayscale { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the 2d gradient operator.
|
|||
/// </summary>
|
|||
public DenseMatrix<float> KernelXY { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void BeforeFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration) |
|||
{ |
|||
if (this.Grayscale) |
|||
{ |
|||
new GrayscaleBt709Processor(1F).ApplyToFrame(source, sourceRectangle, configuration); |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration) |
|||
=> new ConvolutionProcessor<TPixel>(this.KernelXY, true).Apply(source, sourceRectangle, configuration); |
|||
} |
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Primitives; |
|||
using SixLabors.Primitives; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
|||
{ |
|||
/// <summary>
|
|||
/// Applies Gaussian blur processing to an image.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
internal class GaussianBlurProcessor<TPixel> : ImageProcessor<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GaussianBlurProcessor{TPixel}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="definition">The <see cref="GaussianBlurProcessor"/> defining the processor parameters.</param>
|
|||
public GaussianBlurProcessor(GaussianBlurProcessor definition) |
|||
{ |
|||
int kernelSize = (definition.Radius * 2) + 1; |
|||
this.KernelX = ConvolutionProcessorHelpers.CreateGaussianBlurKernel(kernelSize, definition.Sigma); |
|||
this.KernelY = this.KernelX.Transpose(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the horizontal gradient operator.
|
|||
/// </summary>
|
|||
public DenseMatrix<float> KernelX { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the vertical gradient operator.
|
|||
/// </summary>
|
|||
public DenseMatrix<float> KernelY { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnFrameApply( |
|||
ImageFrame<TPixel> source, |
|||
Rectangle sourceRectangle, |
|||
Configuration configuration) => |
|||
new Convolution2PassProcessor<TPixel>(this.KernelX, this.KernelY, false).Apply( |
|||
source, |
|||
sourceRectangle, |
|||
configuration); |
|||
} |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Primitives; |
|||
using SixLabors.Primitives; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
|||
{ |
|||
/// <summary>
|
|||
/// Applies Gaussian sharpening processing to the image.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
internal class GaussianSharpenProcessor<TPixel> : ImageProcessor<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="GaussianSharpenProcessor{TPixel}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="definition">The <see cref="GaussianBlurProcessor"/> defining the processor parameters.</param>
|
|||
public GaussianSharpenProcessor(GaussianSharpenProcessor definition) |
|||
{ |
|||
int kernelSize = (definition.Radius * 2) + 1; |
|||
this.KernelX = ConvolutionProcessorHelpers.CreateGaussianSharpenKernel(kernelSize, definition.Sigma); |
|||
this.KernelY = this.KernelX.Transpose(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the horizontal gradient operator.
|
|||
/// </summary>
|
|||
public DenseMatrix<float> KernelX { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the vertical gradient operator.
|
|||
/// </summary>
|
|||
public DenseMatrix<float> KernelY { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration) |
|||
=> new Convolution2PassProcessor<TPixel>(this.KernelX, this.KernelY, false).Apply(source, sourceRectangle, configuration); |
|||
} |
|||
} |
|||
@ -1,28 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.ImageSharp.Processing.Processors; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
|||
{ |
|||
/// <summary>
|
|||
/// Provides properties and methods allowing the detection of edges within an image.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
public interface IEdgeDetectorProcessor<TPixel> : IImageProcessor<TPixel>, IEdgeDetectorProcessor |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Provides properties and methods allowing the detection of edges within an image.
|
|||
/// </summary>
|
|||
public interface IEdgeDetectorProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// Gets a value indicating whether to convert the image to grayscale before performing edge detection.
|
|||
/// </summary>
|
|||
bool Grayscale { get; } |
|||
} |
|||
} |
|||
@ -1,24 +1,30 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
|||
{ |
|||
/// <summary>
|
|||
/// Applies edge detection processing to the image using the Kayyali operator filter. <see href="http://edgedetection.webs.com/"/>
|
|||
/// Defines edge detection processing using the Kayyali operator filter.
|
|||
/// See <see href="http://edgedetection.webs.com/"/>.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
internal class KayyaliProcessor<TPixel> : EdgeDetector2DProcessor<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
public sealed class KayyaliProcessor : EdgeDetectorProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="KayyaliProcessor{TPixel}"/> class.
|
|||
/// Initializes a new instance of the <see cref="KayyaliProcessor"/> class.
|
|||
/// </summary>
|
|||
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
|
|||
public KayyaliProcessor(bool grayscale) |
|||
: base(KayyaliKernels.KayyaliX, KayyaliKernels.KayyaliY, grayscale) |
|||
: base(grayscale) |
|||
{ |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>() |
|||
{ |
|||
return new EdgeDetector2DProcessor<TPixel>( |
|||
KayyaliKernels.KayyaliX, |
|||
KayyaliKernels.KayyaliY, |
|||
this.Grayscale); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,57 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.Primitives; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
|||
{ |
|||
internal abstract class CompassKernels |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the North gradient operator.
|
|||
/// </summary>
|
|||
public abstract DenseMatrix<float> North { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the NorthWest gradient operator.
|
|||
/// </summary>
|
|||
public abstract DenseMatrix<float> NorthWest { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the West gradient operator.
|
|||
/// </summary>
|
|||
public abstract DenseMatrix<float> West { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the SouthWest gradient operator.
|
|||
/// </summary>
|
|||
public abstract DenseMatrix<float> SouthWest { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the South gradient operator.
|
|||
/// </summary>
|
|||
public abstract DenseMatrix<float> South { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the SouthEast gradient operator.
|
|||
/// </summary>
|
|||
public abstract DenseMatrix<float> SouthEast { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the East gradient operator.
|
|||
/// </summary>
|
|||
public abstract DenseMatrix<float> East { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the NorthEast gradient operator.
|
|||
/// </summary>
|
|||
public abstract DenseMatrix<float> NorthEast { get; } |
|||
|
|||
public DenseMatrix<float>[] Flatten() => |
|||
new[] |
|||
{ |
|||
this.North, this.NorthWest, this.West, this.SouthWest, |
|||
this.South, this.SouthEast, this.East, this.NorthEast |
|||
}; |
|||
} |
|||
} |
|||
@ -1,25 +1,27 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
|||
{ |
|||
/// <summary>
|
|||
/// Applies edge detection processing to the image using the Laplacian 5x5 operator filter.
|
|||
/// <see href="http://en.wikipedia.org/wiki/Discrete_Laplace_operator"/>
|
|||
/// Defines edge detection processing using the Laplacian 5x5 operator filter.
|
|||
/// <see href="http://en.wikipedia.org/wiki/Discrete_Laplace_operator"/>.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
internal class Laplacian5x5Processor<TPixel> : EdgeDetectorProcessor<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
public sealed class Laplacian5x5Processor : EdgeDetectorProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Laplacian5x5Processor{TPixel}"/> class.
|
|||
/// Initializes a new instance of the <see cref="Laplacian5x5Processor"/> class.
|
|||
/// </summary>
|
|||
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
|
|||
public Laplacian5x5Processor(bool grayscale) |
|||
: base(LaplacianKernels.Laplacian5x5, grayscale) |
|||
: base(grayscale) |
|||
{ |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>() |
|||
{ |
|||
return new EdgeDetectorProcessor<TPixel>(LaplacianKernels.Laplacian5x5, this.Grayscale); |
|||
} |
|||
} |
|||
} |
|||
@ -1,25 +1,27 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
|||
{ |
|||
/// <summary>
|
|||
/// Applies edge detection processing to the image using the Laplacian of Gaussian operator filter.
|
|||
/// <see href="http://fourier.eng.hmc.edu/e161/lectures/gradient/node8.html"/>
|
|||
/// See <see href="http://fourier.eng.hmc.edu/e161/lectures/gradient/node8.html"/>.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
internal class LaplacianOfGaussianProcessor<TPixel> : EdgeDetectorProcessor<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
public sealed class LaplacianOfGaussianProcessor : EdgeDetectorProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="LaplacianOfGaussianProcessor{TPixel}"/> class.
|
|||
/// Initializes a new instance of the <see cref="LaplacianOfGaussianProcessor"/> class.
|
|||
/// </summary>
|
|||
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
|
|||
public LaplacianOfGaussianProcessor(bool grayscale) |
|||
: base(LaplacianKernels.LaplacianOfGaussianXY, grayscale) |
|||
: base(grayscale) |
|||
{ |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>() |
|||
{ |
|||
return new EdgeDetectorProcessor<TPixel>(LaplacianKernels.LaplacianOfGaussianXY, this.Grayscale); |
|||
} |
|||
} |
|||
} |
|||
@ -1,25 +1,27 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Convolution |
|||
{ |
|||
/// <summary>
|
|||
/// Applies edge detection processing to the image using the Prewitt operator filter.
|
|||
/// <see href="http://en.wikipedia.org/wiki/Prewitt_operator"/>
|
|||
/// Defines edge detection using the Prewitt operator filter.
|
|||
/// See <see href="http://en.wikipedia.org/wiki/Prewitt_operator"/>.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
internal class PrewittProcessor<TPixel> : EdgeDetector2DProcessor<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
public sealed class PrewittProcessor : EdgeDetectorProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="PrewittProcessor{TPixel}"/> class.
|
|||
/// Initializes a new instance of the <see cref="PrewittProcessor"/> class.
|
|||
/// </summary>
|
|||
/// <param name="grayscale">Whether to convert the image to grayscale before performing edge detection.</param>
|
|||
public PrewittProcessor(bool grayscale) |
|||
: base(PrewittKernels.PrewittX, PrewittKernels.PrewittY, grayscale) |
|||
: base(grayscale) |
|||
{ |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
public override IImageProcessor<TPixel> CreatePixelSpecificProcessor<TPixel>() |
|||
{ |
|||
return new EdgeDetector2DProcessor<TPixel>(PrewittKernels.PrewittX, PrewittKernels.PrewittY, this.Grayscale); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,129 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
using SixLabors.ImageSharp.Advanced; |
|||
using SixLabors.ImageSharp.Memory; |
|||
using SixLabors.ImageSharp.ParallelUtils; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.Primitives; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Effects |
|||
{ |
|||
/// <summary>
|
|||
/// Applies oil painting effect processing to the image.
|
|||
/// </summary>
|
|||
/// <remarks>Adapted from <see href="https://softwarebydefault.com/2013/06/29/oil-painting-cartoon-filter/"/> by Dewald Esterhuizen.</remarks>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
internal class OilPaintingProcessor<TPixel> : ImageProcessor<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
private readonly OilPaintingProcessor definition; |
|||
|
|||
public OilPaintingProcessor(OilPaintingProcessor definition) |
|||
{ |
|||
this.definition = definition; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnFrameApply( |
|||
ImageFrame<TPixel> source, |
|||
Rectangle sourceRectangle, |
|||
Configuration configuration) |
|||
{ |
|||
int brushSize = this.definition.BrushSize; |
|||
if (brushSize <= 0 || brushSize > source.Height || brushSize > source.Width) |
|||
{ |
|||
throw new ArgumentOutOfRangeException(nameof(brushSize)); |
|||
} |
|||
|
|||
int startY = sourceRectangle.Y; |
|||
int endY = sourceRectangle.Bottom; |
|||
int startX = sourceRectangle.X; |
|||
int endX = sourceRectangle.Right; |
|||
int maxY = endY - 1; |
|||
int maxX = endX - 1; |
|||
|
|||
int radius = brushSize >> 1; |
|||
int levels = this.definition.Levels; |
|||
|
|||
using (Buffer2D<TPixel> targetPixels = configuration.MemoryAllocator.Allocate2D<TPixel>(source.Size())) |
|||
{ |
|||
source.CopyTo(targetPixels); |
|||
|
|||
var workingRect = Rectangle.FromLTRB(startX, startY, endX, endY); |
|||
ParallelHelper.IterateRows( |
|||
workingRect, |
|||
configuration, |
|||
rows => |
|||
{ |
|||
for (int y = rows.Min; y < rows.Max; y++) |
|||
{ |
|||
Span<TPixel> sourceRow = source.GetPixelRowSpan(y); |
|||
Span<TPixel> targetRow = targetPixels.GetRowSpan(y); |
|||
|
|||
for (int x = startX; x < endX; x++) |
|||
{ |
|||
int maxIntensity = 0; |
|||
int maxIndex = 0; |
|||
|
|||
int[] intensityBin = new int[levels]; |
|||
float[] redBin = new float[levels]; |
|||
float[] blueBin = new float[levels]; |
|||
float[] greenBin = new float[levels]; |
|||
|
|||
for (int fy = 0; fy <= radius; fy++) |
|||
{ |
|||
int fyr = fy - radius; |
|||
int offsetY = y + fyr; |
|||
|
|||
offsetY = offsetY.Clamp(0, maxY); |
|||
|
|||
Span<TPixel> sourceOffsetRow = source.GetPixelRowSpan(offsetY); |
|||
|
|||
for (int fx = 0; fx <= radius; fx++) |
|||
{ |
|||
int fxr = fx - radius; |
|||
int offsetX = x + fxr; |
|||
offsetX = offsetX.Clamp(0, maxX); |
|||
|
|||
var vector = sourceOffsetRow[offsetX].ToVector4(); |
|||
|
|||
float sourceRed = vector.X; |
|||
float sourceBlue = vector.Z; |
|||
float sourceGreen = vector.Y; |
|||
|
|||
int currentIntensity = (int)MathF.Round( |
|||
(sourceBlue + sourceGreen + sourceRed) / 3F * (levels - 1)); |
|||
|
|||
intensityBin[currentIntensity]++; |
|||
blueBin[currentIntensity] += sourceBlue; |
|||
greenBin[currentIntensity] += sourceGreen; |
|||
redBin[currentIntensity] += sourceRed; |
|||
|
|||
if (intensityBin[currentIntensity] > maxIntensity) |
|||
{ |
|||
maxIntensity = intensityBin[currentIntensity]; |
|||
maxIndex = currentIntensity; |
|||
} |
|||
} |
|||
|
|||
float red = MathF.Abs(redBin[maxIndex] / maxIntensity); |
|||
float green = MathF.Abs(greenBin[maxIndex] / maxIntensity); |
|||
float blue = MathF.Abs(blueBin[maxIndex] / maxIntensity); |
|||
|
|||
ref TPixel pixel = ref targetRow[x]; |
|||
pixel.FromVector4( |
|||
new Vector4(red, green, blue, sourceRow[x].ToVector4().W)); |
|||
} |
|||
} |
|||
} |
|||
}); |
|||
|
|||
Buffer2D<TPixel>.SwapOrCopyContent(source.PixelBuffer, targetPixels); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,111 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
|
|||
using SixLabors.ImageSharp.Advanced; |
|||
using SixLabors.ImageSharp.Common; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
using SixLabors.Primitives; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Effects |
|||
{ |
|||
/// <summary>
|
|||
/// Applies a pixelation effect processing to the image.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
internal class PixelateProcessor<TPixel> : ImageProcessor<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
private readonly PixelateProcessor definition; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="PixelateProcessor{TPixel}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="definition">The <see cref="PixelateProcessor"/>.</param>
|
|||
public PixelateProcessor(PixelateProcessor definition) |
|||
{ |
|||
this.definition = definition; |
|||
} |
|||
|
|||
private int Size => this.definition.Size; |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration) |
|||
{ |
|||
if (this.Size <= 0 || this.Size > source.Height || this.Size > source.Width) |
|||
{ |
|||
throw new ArgumentOutOfRangeException(nameof(this.Size)); |
|||
} |
|||
|
|||
int startY = sourceRectangle.Y; |
|||
int endY = sourceRectangle.Bottom; |
|||
int startX = sourceRectangle.X; |
|||
int endX = sourceRectangle.Right; |
|||
int size = this.Size; |
|||
int offset = this.Size / 2; |
|||
|
|||
// Align start/end positions.
|
|||
int minX = Math.Max(0, startX); |
|||
int maxX = Math.Min(source.Width, endX); |
|||
int minY = Math.Max(0, startY); |
|||
int maxY = Math.Min(source.Height, endY); |
|||
|
|||
// Reset offset if necessary.
|
|||
if (minX > 0) |
|||
{ |
|||
startX = 0; |
|||
} |
|||
|
|||
if (minY > 0) |
|||
{ |
|||
startY = 0; |
|||
} |
|||
|
|||
// Get the range on the y-plane to choose from.
|
|||
IEnumerable<int> range = EnumerableExtensions.SteppedRange(minY, i => i < maxY, size); |
|||
|
|||
Parallel.ForEach( |
|||
range, |
|||
configuration.GetParallelOptions(), |
|||
y => |
|||
{ |
|||
int offsetY = y - startY; |
|||
int offsetPy = offset; |
|||
|
|||
// Make sure that the offset is within the boundary of the image.
|
|||
while (offsetY + offsetPy >= maxY) |
|||
{ |
|||
offsetPy--; |
|||
} |
|||
|
|||
Span<TPixel> row = source.GetPixelRowSpan(offsetY + offsetPy); |
|||
|
|||
for (int x = minX; x < maxX; x += size) |
|||
{ |
|||
int offsetX = x - startX; |
|||
int offsetPx = offset; |
|||
|
|||
while (x + offsetPx >= maxX) |
|||
{ |
|||
offsetPx--; |
|||
} |
|||
|
|||
// Get the pixel color in the centre of the soon to be pixelated area.
|
|||
TPixel pixel = row[offsetX + offsetPx]; |
|||
|
|||
// For each pixel in the pixelate size, set it to the centre color.
|
|||
for (int l = offsetY; l < offsetY + size && l < maxY; l++) |
|||
{ |
|||
for (int k = offsetX; k < offsetX + size && k < maxX; k++) |
|||
{ |
|||
source[k, l] = pixel; |
|||
} |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue