From 128cb4b1b03169de924e30a4fb7b34aed8275c19 Mon Sep 17 00:00:00 2001 From: James South Date: Wed, 8 Oct 2014 23:06:36 +0100 Subject: [PATCH] Fixing comic filter Former-commit-id: abffd6261fd58e5d3507916833b4e6d0c152db9d Former-commit-id: 32877091d96a8e85e393d44cb431bc20fdf961e0 --- src/ImageProcessor.Playground/Program.cs | 8 +- .../images/input/circle.png | Bin 6957 -> 5089 bytes .../images/input/monster.png.REMOVED.git-id | 2 +- .../Filters/Artistic/OilPaintingFilter.cs | 4 +- .../Filters/Photo/ComicMatrixFilter.cs | 201 +++--------------- src/ImageProcessor/Imaging/PixelData.cs | 2 - 6 files changed, 39 insertions(+), 178 deletions(-) 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 029091dbc72bf71881302caf881721fa18a235ad..bf833b1897a9ee6dde1950aefda13c2a29b9ae74 100644 GIT binary patch literal 5089 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 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. ///