diff --git a/src/ImageProcessor.Playground/Program.cs b/src/ImageProcessor.Playground/Program.cs
index d34732b34..1cc1aaf35 100644
--- a/src/ImageProcessor.Playground/Program.cs
+++ b/src/ImageProcessor.Playground/Program.cs
@@ -73,16 +73,16 @@ namespace ImageProcessor.PlayGround
//.BackgroundColor(Color.White)
//.Resize(new Size((int)(size.Width * 1.1), 0))
//.ContentAwareResize(layer)
- //.Constrain(size)
+ // .Constrain(size)
//.ReplaceColor(Color.FromArgb(255, 1, 107, 165), Color.FromArgb(255, 1, 165, 13), 80)
//.Resize(layer)
- //.DetectEdges(new KirschEdgeFilter())
+ .DetectEdges(new SobelEdgeFilter(), false)
//.DetectEdges(new LaplacianOfGaussianEdgeFilter())
//.EntropyCrop()
- //.Filter(MatrixFilters.Comic)
+ .Filter(MatrixFilters.Invert)
//.Filter(MatrixFilters.Comic)
//.Filter(MatrixFilters.HiSatch)
- .Pixelate(8)
+ //.Pixelate(8)
//.GaussianSharpen(10)
.Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name)));
diff --git a/src/ImageProcessor.Playground/images/input/circle.png b/src/ImageProcessor.Playground/images/input/circle.png
index 3d96cf303..7e46427ac 100644
--- a/src/ImageProcessor.Playground/images/input/circle.png
+++ b/src/ImageProcessor.Playground/images/input/circle.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:3df296a3fd58930899d308558b128db760879cb776afba8f2d6511aba3934dd0
-size 6957
+oid sha256:73f4d8e08292df487a457be0765cb7994f2d91600b1824170a82e8f20f0a6d0b
+size 5089
diff --git a/src/ImageProcessor.Playground/images/input/monster.png.REMOVED.git-id b/src/ImageProcessor.Playground/images/input/monster.png.REMOVED.git-id
index 3d53156f1..c13b65e9e 100644
--- a/src/ImageProcessor.Playground/images/input/monster.png.REMOVED.git-id
+++ b/src/ImageProcessor.Playground/images/input/monster.png.REMOVED.git-id
@@ -1 +1 @@
-6b1252209f60025427722f765dbbc271d125114e
\ No newline at end of file
+4edf74a6857665c8efe2d3282c25907f5b20ca81
\ No newline at end of file
diff --git a/src/ImageProcessor/Imaging/Filters/Artistic/OilPaintingFilter.cs b/src/ImageProcessor/Imaging/Filters/Artistic/OilPaintingFilter.cs
index 2213c043a..0208edbd5 100644
--- a/src/ImageProcessor/Imaging/Filters/Artistic/OilPaintingFilter.cs
+++ b/src/ImageProcessor/Imaging/Filters/Artistic/OilPaintingFilter.cs
@@ -118,6 +118,7 @@ namespace ImageProcessor.Imaging.Filters.Artistic
int[] blueBin = new int[this.levels];
int[] greenBin = new int[this.levels];
int[] redBin = new int[this.levels];
+ byte sourceAlpha = 255;
for (int i = 0; i <= radius; i++)
{
@@ -155,6 +156,7 @@ namespace ImageProcessor.Imaging.Filters.Artistic
byte sourceBlue = color.B;
byte sourceGreen = color.G;
byte sourceRed = color.R;
+ sourceAlpha = color.A;
int currentIntensity = (int)Math.Round(((sourceBlue + sourceGreen + sourceRed) / 3.0 * (this.levels - 1)) / 255.0);
@@ -177,7 +179,7 @@ namespace ImageProcessor.Imaging.Filters.Artistic
byte red = Math.Abs(redBin[maxIndex] / maxIntensity).ToByte();
// ReSharper disable once AccessToDisposedClosure
- destinationBitmap.SetPixel(x, y, Color.FromArgb(red, green, blue));
+ destinationBitmap.SetPixel(x, y, Color.FromArgb(sourceAlpha, red, green, blue));
}
});
}
diff --git a/src/ImageProcessor/Imaging/Filters/Photo/ComicMatrixFilter.cs b/src/ImageProcessor/Imaging/Filters/Photo/ComicMatrixFilter.cs
index ac9d488af..868a4d64e 100644
--- a/src/ImageProcessor/Imaging/Filters/Photo/ComicMatrixFilter.cs
+++ b/src/ImageProcessor/Imaging/Filters/Photo/ComicMatrixFilter.cs
@@ -19,6 +19,7 @@ namespace ImageProcessor.Imaging.Filters.Photo
using ImageProcessor.Common.Extensions;
using ImageProcessor.Imaging.Filters.Artistic;
+ using ImageProcessor.Imaging.Filters.EdgeDetection;
///
/// Encapsulates methods with which to add a comic filter to an image.
@@ -64,7 +65,7 @@ namespace ImageProcessor.Imaging.Filters.Photo
highBitmap = new OilPaintingFilter(3, 5).ApplyFilter((Bitmap)image);
// Draw the edges.
- edgeBitmap = DrawEdges((Bitmap)image, 120);
+ edgeBitmap = Trace((Bitmap)image, 120);
using (Graphics graphics = Graphics.FromImage(highBitmap))
{
@@ -169,7 +170,7 @@ namespace ImageProcessor.Imaging.Filters.Photo
/// Detects and draws edges.
/// TODO: Move this to another class and do edge detection.
///
- ///
+ ///
/// The source bitmap.
///
///
@@ -178,184 +179,44 @@ namespace ImageProcessor.Imaging.Filters.Photo
///
/// The .
///
- private static Bitmap DrawEdges(Bitmap sourceBitmap, byte threshold = 0)
+ private static Bitmap Trace(Bitmap source, byte threshold = 0)
{
- Color color = Color.Black;
- int width = sourceBitmap.Width;
- int height = sourceBitmap.Height;
-
- BitmapData sourceData = sourceBitmap.LockBits(
- new Rectangle(0, 0, width, height),
- ImageLockMode.ReadOnly,
- PixelFormat.Format32bppArgb);
-
- int strideWidth = sourceData.Stride;
- int scanHeight = sourceData.Height;
-
- int bufferSize = strideWidth * scanHeight;
- byte[] pixelBuffer = new byte[bufferSize];
- byte[] resultBuffer = new byte[bufferSize];
-
- Marshal.Copy(sourceData.Scan0, pixelBuffer, 0, pixelBuffer.Length);
-
- sourceBitmap.UnlockBits(sourceData);
-
- for (int offsetY = 1; offsetY < height - 1; offsetY++)
+ int width = source.Width;
+ int height = source.Height;
+
+ // Grab the edges converting to greyscale, and invert the colors.
+ ConvolutionFilter filter = new ConvolutionFilter(new SobelEdgeFilter(), true);
+ Bitmap destination = filter.Process2DFilter(source);
+ Bitmap invert = new Bitmap(width, height, PixelFormat.Format32bppArgb);
+ InvertMatrixFilter matrix = new InvertMatrixFilter();
+ invert = (Bitmap)matrix.TransformImage(destination, invert);
+
+ // Loop through and replace any colors more white than the threshold
+ // with a transparent one.
+ using (FastBitmap sourceBitmap = new FastBitmap(invert))
{
- for (int offsetX = 1; offsetX < width - 1; offsetX++)
- {
- int byteOffset = (offsetY * strideWidth) + (offsetX * 4);
-
- int blueGradient = Math.Abs(pixelBuffer[byteOffset - 4] - pixelBuffer[byteOffset + 4]);
-
- blueGradient +=
- Math.Abs(
- pixelBuffer[byteOffset - strideWidth] - pixelBuffer[byteOffset + strideWidth]);
-
- byteOffset++;
-
- int greenGradient = Math.Abs(pixelBuffer[byteOffset - 4] - pixelBuffer[byteOffset + 4]);
-
- greenGradient +=
- Math.Abs(
- pixelBuffer[byteOffset - strideWidth] - pixelBuffer[byteOffset + strideWidth]);
-
- byteOffset++;
-
- int redGradient = Math.Abs(pixelBuffer[byteOffset - 4] - pixelBuffer[byteOffset + 4]);
-
- redGradient +=
- Math.Abs(
- pixelBuffer[byteOffset - strideWidth] - pixelBuffer[byteOffset + strideWidth]);
-
- bool exceedsThreshold;
- if (blueGradient + greenGradient + redGradient > threshold)
+ Parallel.For(
+ 0,
+ height,
+ y =>
{
- exceedsThreshold = true;
- }
- else
- {
- byteOffset -= 2;
-
- blueGradient = Math.Abs(pixelBuffer[byteOffset - 4] - pixelBuffer[byteOffset + 4]);
- byteOffset++;
-
- greenGradient = Math.Abs(pixelBuffer[byteOffset - 4] - pixelBuffer[byteOffset + 4]);
- byteOffset++;
-
- redGradient = Math.Abs(pixelBuffer[byteOffset - 4] - pixelBuffer[byteOffset + 4]);
-
- if (blueGradient + greenGradient + redGradient > threshold)
- {
- exceedsThreshold = true;
- }
- else
+ for (int x = 0; x < width; x++)
{
- byteOffset -= 2;
-
- blueGradient =
- Math.Abs(pixelBuffer[byteOffset - strideWidth] - pixelBuffer[byteOffset + strideWidth]);
-
- byteOffset++;
-
- greenGradient =
- Math.Abs(pixelBuffer[byteOffset - strideWidth] - pixelBuffer[byteOffset + strideWidth]);
-
- byteOffset++;
-
- redGradient =
- Math.Abs(pixelBuffer[byteOffset - strideWidth] - pixelBuffer[byteOffset + strideWidth]);
-
- if (blueGradient + greenGradient + redGradient > threshold)
+ // ReSharper disable AccessToDisposedClosure
+ Color color = sourceBitmap.GetPixel(x, y);
+ if (color.B >= threshold)
{
- exceedsThreshold = true;
- }
- else
- {
- byteOffset -= 2;
-
- blueGradient =
- Math.Abs(
- pixelBuffer[byteOffset - 4 - strideWidth]
- - pixelBuffer[byteOffset + 4 + strideWidth]);
-
- blueGradient +=
- Math.Abs(
- pixelBuffer[byteOffset - strideWidth + 4]
- - pixelBuffer[byteOffset + strideWidth - 4]);
-
- byteOffset++;
-
- greenGradient =
- Math.Abs(
- pixelBuffer[byteOffset - 4 - strideWidth]
- - pixelBuffer[byteOffset + 4 + strideWidth]);
-
- greenGradient +=
- Math.Abs(
- pixelBuffer[byteOffset - strideWidth + 4]
- - pixelBuffer[byteOffset + strideWidth - 4]);
-
- byteOffset++;
-
- redGradient =
- Math.Abs(
- pixelBuffer[byteOffset - 4 - strideWidth]
- - pixelBuffer[byteOffset + 4 + strideWidth]);
-
- redGradient +=
- Math.Abs(
- pixelBuffer[byteOffset - strideWidth + 4]
- - pixelBuffer[byteOffset + strideWidth - 4]);
-
- exceedsThreshold = blueGradient + greenGradient + redGradient > threshold;
+ sourceBitmap.SetPixel(x, y, Color.Transparent);
}
+ // ReSharper restore AccessToDisposedClosure
}
- }
-
- byteOffset -= 2;
-
- double blue;
- double red;
- double green;
- double alpha;
- if (exceedsThreshold)
- {
- blue = color.B; // 0;
- green = color.G; // 0;
- red = color.R; // 0;
- alpha = 255;
- }
- else
- {
- // These would normally be used to transfer the correct value across.
- // blue = pixelBuffer[byteOffset];
- // green = pixelBuffer[byteOffset + 1];
- // red = pixelBuffer[byteOffset + 2];
- blue = 255;
- green = 255;
- red = 255;
- alpha = 0;
- }
-
- resultBuffer[byteOffset] = blue.ToByte();
- resultBuffer[byteOffset + 1] = green.ToByte();
- resultBuffer[byteOffset + 2] = red.ToByte();
- resultBuffer[byteOffset + 3] = alpha.ToByte();
- }
+ });
}
- Bitmap resultBitmap = new Bitmap(width, height);
-
- BitmapData resultData = resultBitmap.LockBits(
- new Rectangle(0, 0, resultBitmap.Width, resultBitmap.Height),
- ImageLockMode.WriteOnly,
- PixelFormat.Format32bppArgb);
-
- Marshal.Copy(resultBuffer, 0, resultData.Scan0, resultBuffer.Length);
+ destination.Dispose();
+ destination = invert;
- resultBitmap.UnlockBits(resultData);
- return resultBitmap;
+ return destination;
}
///
diff --git a/src/ImageProcessor/Imaging/PixelData.cs b/src/ImageProcessor/Imaging/PixelData.cs
index 741b295cd..78d494edc 100644
--- a/src/ImageProcessor/Imaging/PixelData.cs
+++ b/src/ImageProcessor/Imaging/PixelData.cs
@@ -10,8 +10,6 @@
namespace ImageProcessor.Imaging
{
- using System.Collections.Generic;
-
///
/// Contains the component parts that make up a single pixel.
///