Browse Source

Fixing comic filter

Former-commit-id: 3fe75f0dcb823383aee6f0b78f585e2d89443b9e
Former-commit-id: f67c0028ab9e096ad63030c0e84a80f51732a950
af/merge-core
James South 12 years ago
parent
commit
ef986a329e
  1. 8
      src/ImageProcessor.Playground/Program.cs
  2. 4
      src/ImageProcessor.Playground/images/input/circle.png
  3. 2
      src/ImageProcessor.Playground/images/input/monster.png.REMOVED.git-id
  4. 4
      src/ImageProcessor/Imaging/Filters/Artistic/OilPaintingFilter.cs
  5. 201
      src/ImageProcessor/Imaging/Filters/Photo/ComicMatrixFilter.cs
  6. 2
      src/ImageProcessor/Imaging/PixelData.cs

8
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)));

4
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

2
src/ImageProcessor.Playground/images/input/monster.png.REMOVED.git-id

@ -1 +1 @@
6b1252209f60025427722f765dbbc271d125114e
4edf74a6857665c8efe2d3282c25907f5b20ca81

4
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));
}
});
}

201
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;
/// <summary>
/// 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.
/// </summary>
/// <param name="sourceBitmap">
/// <param name="source">
/// The source bitmap.
/// </param>
/// <param name="threshold">
@ -178,184 +179,44 @@ namespace ImageProcessor.Imaging.Filters.Photo
/// <returns>
/// The <see cref="Bitmap"/>.
/// </returns>
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;
}
/// <summary>

2
src/ImageProcessor/Imaging/PixelData.cs

@ -10,8 +10,6 @@
namespace ImageProcessor.Imaging
{
using System.Collections.Generic;
/// <summary>
/// Contains the component parts that make up a single pixel.
/// </summary>

Loading…
Cancel
Save