Browse Source

Faster pixelate and oilpaint

Former-commit-id: 14e4fa2fdef88ce05c76ee4a0446536310ea6eff
Former-commit-id: 09ccde9cc33ffeae0de019e3310507cabbb01009
af/merge-core
James South 12 years ago
parent
commit
0cffee7da2
  1. 4
      src/ImageProcessor.Playground/Program.cs
  2. 93
      src/ImageProcessor/Common/Extensions/EnumerableExtensions.cs
  3. 1
      src/ImageProcessor/ImageProcessor.csproj
  4. 110
      src/ImageProcessor/Imaging/Filters/Artistic/OilPaintingFilter.cs
  5. 29
      src/ImageProcessor/Imaging/Filters/Photo/ComicMatrixFilter.cs
  6. 55
      src/ImageProcessor/Processors/Pixelate.cs

4
src/ImageProcessor.Playground/Program.cs

@ -77,12 +77,12 @@ namespace ImageProcessor.PlayGround
//.ReplaceColor(Color.FromArgb(255, 1, 107, 165), Color.FromArgb(255, 1, 165, 13), 80)
//.Resize(layer)
//.DetectEdges(new KirschEdgeFilter())
.DetectEdges(new LaplacianOfGaussianEdgeFilter())
//.DetectEdges(new LaplacianOfGaussianEdgeFilter())
//.EntropyCrop()
//.Filter(MatrixFilters.Comic)
//.Filter(MatrixFilters.Comic)
//.Filter(MatrixFilters.HiSatch)
//.Pixelate(8)
.Pixelate(8)
//.GaussianSharpen(10)
.Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name)));

93
src/ImageProcessor/Common/Extensions/EnumerableExtensions.cs

@ -0,0 +1,93 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="EnumerableExtensions.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// <summary>
// Encapsulates a series of time saving extension methods to the <see cref="T:System.Collections.IEnumerable" /> interface.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Common.Extensions
{
using System;
using System.Collections.Generic;
/// <summary>
/// Encapsulates a series of time saving extension methods to the <see cref="T:System.Collections.IEnumerable"/> interface.
/// </summary>
public static class EnumerableExtensions
{
/// <summary>
/// Generates a sequence of integral numbers within a specified range.
/// </summary>
/// <param name="fromInclusive">
/// The start index, inclusive.
/// </param>
/// <param name="toExclusive">
/// The end index, exclusive.
/// </param>
/// <param name="step">
/// The incremental step.
/// </param>
/// <returns>
/// The <see cref="IEnumerable{Int32}"/> that contains a range of sequential integral numbers.
/// </returns>
public static IEnumerable<int> SteppedRange(int fromInclusive, int toExclusive, int step)
{
// Borrowed from Enumerable.Range
long num = (fromInclusive + toExclusive) - 1L;
if ((toExclusive < 0) || (num > 0x7fffffffL))
{
throw new ArgumentOutOfRangeException("toExclusive");
}
return RangeIterator(fromInclusive, i => i < toExclusive, step);
}
/// <summary>
/// Generates a sequence of integral numbers within a specified range.
/// </summary>
/// <param name="fromInclusive">
/// The start index, inclusive.
/// </param>
/// <param name="toDelegate">
/// A method that has one parameter and returns a <see cref="System.Boolean"/> calculating the end index
/// </param>
/// <param name="step">
/// The incremental step.
/// </param>
/// <returns>
/// The <see cref="IEnumerable{Int32}"/> that contains a range of sequential integral numbers.
/// </returns>
public static IEnumerable<int> SteppedRange(int fromInclusive, Func<int, bool> toDelegate, int step)
{
return RangeIterator(fromInclusive, toDelegate, step);
}
/// <summary>
/// Generates a sequence of integral numbers within a specified range.
/// </summary>
/// <param name="fromInclusive">
/// The start index, inclusive.
/// </param>
/// <param name="toDelegate">
/// A method that has one parameter and returns a <see cref="System.Boolean"/> calculating the end index
/// </param>
/// <param name="step">
/// The incremental step.
/// </param>
/// <returns>
/// The <see cref="IEnumerable{Int32}"/> that contains a range of sequential integral numbers.
/// </returns>
private static IEnumerable<int> RangeIterator(int fromInclusive, Func<int, bool> toDelegate, int step)
{
int i = fromInclusive;
while (toDelegate(i))
{
yield return i;
i += step;
}
}
}
}

1
src/ImageProcessor/ImageProcessor.csproj

@ -125,6 +125,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Common\Extensions\AssemblyExtensions.cs" />
<Compile Include="Common\Extensions\EnumerableExtensions.cs" />
<Compile Include="Configuration\ImageProcessorBootstrapper.cs" />
<Compile Include="Common\Exceptions\ImageProcessingException.cs" />
<Compile Include="Common\Extensions\DoubleExtensions.cs" />

110
src/ImageProcessor/Imaging/Filters/Artistic/OilPaintingFilter.cs

@ -12,6 +12,7 @@ namespace ImageProcessor.Imaging.Filters.Artistic
{
using System;
using System.Drawing;
using System.Threading.Tasks;
using ImageProcessor.Common.Extensions;
@ -104,76 +105,81 @@ namespace ImageProcessor.Imaging.Filters.Artistic
{
using (FastBitmap destinationBitmap = new FastBitmap(destination))
{
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
Parallel.For(
0,
height,
y =>
{
int maxIntensity = 0;
int maxIndex = 0;
int[] intensityBin = new int[this.levels];
int[] blueBin = new int[this.levels];
int[] greenBin = new int[this.levels];
int[] redBin = new int[this.levels];
for (int i = 0; i <= radius; i++)
for (int x = 0; x < width; x++)
{
int ir = i - radius;
int offsetY = y + ir;
// Skip the current row
if (offsetY < 0)
int maxIntensity = 0;
int maxIndex = 0;
int[] intensityBin = new int[this.levels];
int[] blueBin = new int[this.levels];
int[] greenBin = new int[this.levels];
int[] redBin = new int[this.levels];
for (int i = 0; i <= radius; i++)
{
continue;
}
// Outwith the current bounds so break.
if (offsetY >= height)
{
break;
}
int ir = i - radius;
int offsetY = y + ir;
for (int fx = 0; fx <= radius; fx++)
{
int jr = fx - radius;
int offsetX = x + jr;
// Skip the column
if (offsetX < 0)
// Skip the current row
if (offsetY < 0)
{
continue;
}
if (offsetX < width)
// Outwith the current bounds so break.
if (offsetY >= height)
{
Color color = sourceBitmap.GetPixel(offsetX, offsetY);
byte sourceBlue = color.B;
byte sourceGreen = color.G;
byte sourceRed = color.R;
break;
}
int currentIntensity = (int)Math.Round(((sourceBlue + sourceGreen + sourceRed) / 3.0 * (this.levels - 1)) / 255.0);
for (int fx = 0; fx <= radius; fx++)
{
int jr = fx - radius;
int offsetX = x + jr;
intensityBin[currentIntensity] += 1;
blueBin[currentIntensity] += sourceBlue;
greenBin[currentIntensity] += sourceGreen;
redBin[currentIntensity] += sourceRed;
// Skip the column
if (offsetX < 0)
{
continue;
}
if (intensityBin[currentIntensity] > maxIntensity)
if (offsetX < width)
{
maxIntensity = intensityBin[currentIntensity];
maxIndex = currentIntensity;
// ReSharper disable once AccessToDisposedClosure
Color color = sourceBitmap.GetPixel(offsetX, offsetY);
byte sourceBlue = color.B;
byte sourceGreen = color.G;
byte sourceRed = color.R;
int currentIntensity = (int)Math.Round(((sourceBlue + sourceGreen + sourceRed) / 3.0 * (this.levels - 1)) / 255.0);
intensityBin[currentIntensity] += 1;
blueBin[currentIntensity] += sourceBlue;
greenBin[currentIntensity] += sourceGreen;
redBin[currentIntensity] += sourceRed;
if (intensityBin[currentIntensity] > maxIntensity)
{
maxIntensity = intensityBin[currentIntensity];
maxIndex = currentIntensity;
}
}
}
}
}
byte blue = Math.Abs(blueBin[maxIndex] / maxIntensity).ToByte();
byte green = Math.Abs(greenBin[maxIndex] / maxIntensity).ToByte();
byte red = Math.Abs(redBin[maxIndex] / maxIntensity).ToByte();
byte blue = Math.Abs(blueBin[maxIndex] / maxIntensity).ToByte();
byte green = Math.Abs(greenBin[maxIndex] / maxIntensity).ToByte();
byte red = Math.Abs(redBin[maxIndex] / maxIntensity).ToByte();
destinationBitmap.SetPixel(x, y, Color.FromArgb(red, green, blue));
}
}
// ReSharper disable once AccessToDisposedClosure
destinationBitmap.SetPixel(x, y, Color.FromArgb(red, green, blue));
}
});
}
}

29
src/ImageProcessor/Imaging/Filters/Photo/ComicMatrixFilter.cs

@ -15,6 +15,7 @@ namespace ImageProcessor.Imaging.Filters.Photo
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using ImageProcessor.Common.Extensions;
using ImageProcessor.Imaging.Filters.Artistic;
@ -61,7 +62,7 @@ namespace ImageProcessor.Imaging.Filters.Photo
// Apply a oil painting filter to the image.
highBitmap = new OilPaintingFilter(3, 5).ApplyFilter((Bitmap)image);
// Draw the edges.
edgeBitmap = DrawEdges((Bitmap)image, 120);
@ -383,19 +384,25 @@ namespace ImageProcessor.Imaging.Filters.Photo
int width = source.Width;
int height = source.Height;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
Parallel.For(
0,
height,
y =>
{
Color sourceColor = sourceBitmap.GetPixel(x, y);
Color destinationColor = destinationBitmap.GetPixel(x, y);
if (destinationColor.A != 0)
for (int x = 0; x < width; x++)
{
destinationBitmap.SetPixel(x, y, Color.FromArgb(sourceColor.B, destinationColor.R, destinationColor.G, destinationColor.B));
// ReSharper disable AccessToDisposedClosure
Color sourceColor = sourceBitmap.GetPixel(x, y);
Color destinationColor = destinationBitmap.GetPixel(x, y);
if (destinationColor.A != 0)
{
destinationBitmap.SetPixel(x, y, Color.FromArgb(sourceColor.B, destinationColor.R, destinationColor.G, destinationColor.B));
}
// ReSharper restore AccessToDisposedClosure
}
}
}
});
}
}
}

55
src/ImageProcessor/Processors/Pixelate.cs

@ -13,8 +13,10 @@ namespace ImageProcessor.Processors
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Threading.Tasks;
using ImageProcessor.Common.Exceptions;
using ImageProcessor.Common.Extensions;
using ImageProcessor.Imaging;
/// <summary>
@ -82,37 +84,44 @@ namespace ImageProcessor.Processors
using (FastBitmap fastBitmap = new FastBitmap(newImage))
{
for (int j = y; j < y + height && j < maxHeight; j += size)
{
for (int i = x; i < x + width && i < maxWidth; i += size)
{
int offsetX = offset;
int offsetY = offset;
// Get the range of on the y-plane to choose from.
IEnumerable<int> range = EnumerableExtensions.SteppedRange(y, i => i < y + height && i < maxHeight, size);
// Make sure that the offset is within the boundary of the image.
while (j + offsetY >= maxHeight)
Parallel.ForEach(
range,
j =>
{
for (int i = x; i < x + width && i < maxWidth; i += size)
{
offsetY--;
}
int offsetX = offset;
int offsetY = offset;
while (i + offsetX >= maxWidth)
{
offsetX--;
}
// Make sure that the offset is within the boundary of the image.
while (j + offsetY >= maxHeight)
{
offsetY--;
}
// Get the pixel color in the centre of the soon to be pixelated area.
Color pixel = fastBitmap.GetPixel(i + offsetX, j + offsetY);
while (i + offsetX >= maxWidth)
{
offsetX--;
}
// For each pixel in the pixelate size, set it to the centre color.
for (int l = j; l < j + size && l < maxHeight; l++)
{
for (int k = i; k < i + size && k < maxWidth; k++)
// Get the pixel color in the centre of the soon to be pixelated area.
// ReSharper disable AccessToDisposedClosure
Color pixel = fastBitmap.GetPixel(i + offsetX, j + offsetY);
// For each pixel in the pixelate size, set it to the centre color.
for (int l = j; l < j + size && l < maxHeight; l++)
{
fastBitmap.SetPixel(k, l, pixel);
for (int k = i; k < i + size && k < maxWidth; k++)
{
fastBitmap.SetPixel(k, l, pixel);
}
}
// ReSharper restore AccessToDisposedClosure
}
}
}
});
}
image.Dispose();

Loading…
Cancel
Save