diff --git a/src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs b/src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs
new file mode 100644
index 0000000000..9a6d63342f
--- /dev/null
+++ b/src/ImageSharp/Processing/AdaptiveThresholdExtensions.cs
@@ -0,0 +1,47 @@
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Processing.Processors;
+using SixLabors.Primitives;
+
+namespace SixLabors.ImageSharp.Processing
+{
+ ///
+ /// Extensions to perform AdaptiveThreshold through Mutator
+ ///
+ public static class AdaptiveThresholdExtensions
+ {
+ ///
+ /// Applies Bradley Adaptive Threshold to the image.
+ ///
+ /// The image this method extends.
+ /// The pixel format.
+ /// The .
+ public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source)
+ where TPixel : struct, IPixel
+ => source.ApplyProcessor(new AdaptiveThresholdProcessor());
+
+ ///
+ /// Applies Bradley Adaptive Threshold to the image.
+ ///
+ /// The image this method extends.
+ /// Upper (white) color for thresholding.
+ /// Lower (black) color for thresholding
+ /// /// The pixel format.
+ /// The .
+ public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, TPixel upper, TPixel lower)
+ where TPixel : struct, IPixel
+ => source.ApplyProcessor(new AdaptiveThresholdProcessor(upper, lower));
+
+ ///
+ /// Applies Bradley Adaptive Threshold to the image.
+ ///
+ /// The image this method extends.
+ /// Upper (white) color for thresholding.
+ /// Lower (black) color for thresholding
+ /// Rectangle region to apply the processor on.
+ /// The pixel format.
+ /// The .
+ public static IImageProcessingContext AdaptiveThreshold(this IImageProcessingContext source, TPixel upper, TPixel lower, Rectangle rectangle)
+ where TPixel : struct, IPixel
+ => source.ApplyProcessor(new AdaptiveThresholdProcessor(upper, lower), rectangle);
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs
new file mode 100644
index 0000000000..b14de6679f
--- /dev/null
+++ b/src/ImageSharp/Processing/Processors/Binarization/AdaptiveThresholdProcessor.cs
@@ -0,0 +1,115 @@
+using System;
+using SixLabors.ImageSharp.Advanced;
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.Primitives;
+
+namespace SixLabors.ImageSharp.Processing.Processors
+{
+ ///
+ /// Performs Bradley Adaptive Threshold filter against an image
+ ///
+ /// The pixel format of the image
+ internal class AdaptiveThresholdProcessor : IImageProcessor
+ where TPixel : struct, IPixel
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public AdaptiveThresholdProcessor()
+ : this(NamedColors.White, NamedColors.Black)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Color for upper threshold
+ /// Color for lower threshold
+ public AdaptiveThresholdProcessor(TPixel upper, TPixel lower)
+ {
+ this.Upper = upper;
+ this.Lower = lower;
+ }
+
+ ///
+ /// Gets or sets upper color limit for thresholding
+ ///
+ public TPixel Upper { get; set; }
+
+ ///
+ /// Gets or sets lower color limit for threshold
+ ///
+ public TPixel Lower { get; set; }
+
+ public unsafe void Apply(Image source, Rectangle sourceRectangle)
+ {
+ ushort xStart = (ushort)Math.Max(0, sourceRectangle.X);
+ ushort yStart = (ushort)Math.Max(0, sourceRectangle.Y);
+ ushort xEnd = (ushort)Math.Min(xStart + sourceRectangle.Width, source.Width);
+ ushort yEnd = (ushort)Math.Min(yStart + sourceRectangle.Height, source.Height);
+
+ // Algorithm variables
+ uint sum, count;
+ ushort s = (ushort)Math.Truncate((xEnd / 16f) - 1);
+ uint[,] intImage = new uint[yEnd, xEnd];
+
+ // Trying to figure out how to do this
+ // Using (Buffer2D intImg = source.GetConfiguration().MemoryAllocator.Allocate2D)
+ Rgb24 rgb = default;
+
+ for (ushort i = yStart; i < yEnd; i++)
+ {
+ Span span = source.GetPixelRowSpan(i);
+
+ sum = 0;
+
+ for (ushort j = xStart; j < xEnd; j++)
+ {
+ span[j].ToRgb24(ref rgb);
+
+ sum += (uint)(rgb.R + rgb.G + rgb.B);
+
+ if (i != 0)
+ {
+ intImage[i, j] = intImage[i - 1, j] + sum;
+ }
+ else
+ {
+ intImage[i, j] = sum;
+ }
+ }
+ }
+
+ // How can I parallelize this?
+ ushort x1, x2, y1, y2;
+
+ for (ushort i = yStart; i < yEnd; i++)
+ {
+ Span span = source.GetPixelRowSpan(i);
+
+ for (ushort j = xStart; j < xEnd; j++)
+ {
+ x1 = (ushort)Math.Max(i - s + 1, 0);
+ x2 = (ushort)Math.Min(i + s + 1, yEnd - 1);
+ y1 = (ushort)Math.Max(j - s + 1, 0);
+ y2 = (ushort)Math.Min(j + s + 1, xEnd - 1);
+
+ count = (ushort)((x2 - x1) * (y2 - y1));
+
+ sum = intImage[x2, y2] - intImage[x1, y2] - intImage[x2, y1] + intImage[x1, y1];
+
+ span[j].ToRgb24(ref rgb);
+
+ if ((rgb.R + rgb.G + rgb.B) * count < sum * (1.0 - 0.15))
+ {
+ span[j] = this.Lower;
+ }
+ else
+ {
+ span[j] = this.Upper;
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file