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. 10
      src/ImageProcessor/Imaging/Filters/Artistic/OilPaintingFilter.cs
  5. 11
      src/ImageProcessor/Imaging/Filters/Photo/ComicMatrixFilter.cs
  6. 13
      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) //.ReplaceColor(Color.FromArgb(255, 1, 107, 165), Color.FromArgb(255, 1, 165, 13), 80)
//.Resize(layer) //.Resize(layer)
//.DetectEdges(new KirschEdgeFilter()) //.DetectEdges(new KirschEdgeFilter())
.DetectEdges(new LaplacianOfGaussianEdgeFilter()) //.DetectEdges(new LaplacianOfGaussianEdgeFilter())
//.EntropyCrop() //.EntropyCrop()
//.Filter(MatrixFilters.Comic) //.Filter(MatrixFilters.Comic)
//.Filter(MatrixFilters.Comic) //.Filter(MatrixFilters.Comic)
//.Filter(MatrixFilters.HiSatch) //.Filter(MatrixFilters.HiSatch)
//.Pixelate(8) .Pixelate(8)
//.GaussianSharpen(10) //.GaussianSharpen(10)
.Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name))); .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>
<ItemGroup> <ItemGroup>
<Compile Include="Common\Extensions\AssemblyExtensions.cs" /> <Compile Include="Common\Extensions\AssemblyExtensions.cs" />
<Compile Include="Common\Extensions\EnumerableExtensions.cs" />
<Compile Include="Configuration\ImageProcessorBootstrapper.cs" /> <Compile Include="Configuration\ImageProcessorBootstrapper.cs" />
<Compile Include="Common\Exceptions\ImageProcessingException.cs" /> <Compile Include="Common\Exceptions\ImageProcessingException.cs" />
<Compile Include="Common\Extensions\DoubleExtensions.cs" /> <Compile Include="Common\Extensions\DoubleExtensions.cs" />

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

@ -12,6 +12,7 @@ namespace ImageProcessor.Imaging.Filters.Artistic
{ {
using System; using System;
using System.Drawing; using System.Drawing;
using System.Threading.Tasks;
using ImageProcessor.Common.Extensions; using ImageProcessor.Common.Extensions;
@ -104,7 +105,10 @@ namespace ImageProcessor.Imaging.Filters.Artistic
{ {
using (FastBitmap destinationBitmap = new FastBitmap(destination)) using (FastBitmap destinationBitmap = new FastBitmap(destination))
{ {
for (int y = 0; y < height; y++) Parallel.For(
0,
height,
y =>
{ {
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
@ -145,6 +149,7 @@ namespace ImageProcessor.Imaging.Filters.Artistic
if (offsetX < width) if (offsetX < width)
{ {
// ReSharper disable once AccessToDisposedClosure
Color color = sourceBitmap.GetPixel(offsetX, offsetY); Color color = sourceBitmap.GetPixel(offsetX, offsetY);
byte sourceBlue = color.B; byte sourceBlue = color.B;
@ -171,9 +176,10 @@ namespace ImageProcessor.Imaging.Filters.Artistic
byte green = Math.Abs(greenBin[maxIndex] / maxIntensity).ToByte(); byte green = Math.Abs(greenBin[maxIndex] / maxIntensity).ToByte();
byte red = Math.Abs(redBin[maxIndex] / maxIntensity).ToByte(); 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(red, green, blue));
} }
} });
} }
} }

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

@ -15,6 +15,7 @@ namespace ImageProcessor.Imaging.Filters.Photo
using System.Drawing.Drawing2D; using System.Drawing.Drawing2D;
using System.Drawing.Imaging; using System.Drawing.Imaging;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading.Tasks;
using ImageProcessor.Common.Extensions; using ImageProcessor.Common.Extensions;
using ImageProcessor.Imaging.Filters.Artistic; using ImageProcessor.Imaging.Filters.Artistic;
@ -383,10 +384,14 @@ namespace ImageProcessor.Imaging.Filters.Photo
int width = source.Width; int width = source.Width;
int height = source.Height; int height = source.Height;
for (int y = 0; y < height; y++) Parallel.For(
0,
height,
y =>
{ {
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
// ReSharper disable AccessToDisposedClosure
Color sourceColor = sourceBitmap.GetPixel(x, y); Color sourceColor = sourceBitmap.GetPixel(x, y);
Color destinationColor = destinationBitmap.GetPixel(x, y); Color destinationColor = destinationBitmap.GetPixel(x, y);
@ -394,8 +399,10 @@ namespace ImageProcessor.Imaging.Filters.Photo
{ {
destinationBitmap.SetPixel(x, y, Color.FromArgb(sourceColor.B, destinationColor.R, destinationColor.G, destinationColor.B)); destinationBitmap.SetPixel(x, y, Color.FromArgb(sourceColor.B, destinationColor.R, destinationColor.G, destinationColor.B));
} }
// ReSharper restore AccessToDisposedClosure
} }
} });
} }
} }
} }

13
src/ImageProcessor/Processors/Pixelate.cs

@ -13,8 +13,10 @@ namespace ImageProcessor.Processors
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Threading.Tasks;
using ImageProcessor.Common.Exceptions; using ImageProcessor.Common.Exceptions;
using ImageProcessor.Common.Extensions;
using ImageProcessor.Imaging; using ImageProcessor.Imaging;
/// <summary> /// <summary>
@ -82,7 +84,12 @@ namespace ImageProcessor.Processors
using (FastBitmap fastBitmap = new FastBitmap(newImage)) using (FastBitmap fastBitmap = new FastBitmap(newImage))
{ {
for (int j = y; j < y + height && j < maxHeight; j += size) // Get the range of on the y-plane to choose from.
IEnumerable<int> range = EnumerableExtensions.SteppedRange(y, i => i < y + height && i < maxHeight, size);
Parallel.ForEach(
range,
j =>
{ {
for (int i = x; i < x + width && i < maxWidth; i += size) for (int i = x; i < x + width && i < maxWidth; i += size)
{ {
@ -101,6 +108,7 @@ namespace ImageProcessor.Processors
} }
// Get the pixel color in the centre of the soon to be pixelated area. // 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); Color pixel = fastBitmap.GetPixel(i + offsetX, j + offsetY);
// For each pixel in the pixelate size, set it to the centre color. // For each pixel in the pixelate size, set it to the centre color.
@ -111,8 +119,9 @@ namespace ImageProcessor.Processors
fastBitmap.SetPixel(k, l, pixel); fastBitmap.SetPixel(k, l, pixel);
} }
} }
// ReSharper restore AccessToDisposedClosure
} }
} });
} }
image.Dispose(); image.Dispose();

Loading…
Cancel
Save