From a4b511b8f9af6be9ed7eb62ecfeb194d90cc38b8 Mon Sep 17 00:00:00 2001 From: James South Date: Thu, 6 Nov 2014 16:32:24 +0000 Subject: [PATCH] Further quantizer cleanup Former-commit-id: b234976a3f56b6a1c759bfc82d9a39bf86d98769 Former-commit-id: 66529c17cd81a103e0a7627244b208db3a6f9d2f --- src/ImageProcessor.Playground/Program.cs | 3 +- .../images/input/rgba.png | 3 + src/ImageProcessor/ImageProcessor.csproj | 1 + .../Quantizers/WuQuantizer/ColorMoment.cs | 206 +++++++++++++----- .../Quantizers/WuQuantizer/Histogram.cs | 49 +++++ .../Quantizers/WuQuantizer/ImageBuffer.cs | 23 +- .../WuQuantizer/PaletteColorHistory.cs | 2 +- .../Quantizers/WuQuantizer/WuQuantizerBase.cs | 17 -- 8 files changed, 231 insertions(+), 73 deletions(-) create mode 100644 src/ImageProcessor.Playground/images/input/rgba.png create mode 100644 src/ImageProcessor/Imaging/Quantizers/WuQuantizer/Histogram.cs diff --git a/src/ImageProcessor.Playground/Program.cs b/src/ImageProcessor.Playground/Program.cs index a8362a2bd..2bfd70ff8 100644 --- a/src/ImageProcessor.Playground/Program.cs +++ b/src/ImageProcessor.Playground/Program.cs @@ -49,7 +49,8 @@ namespace ImageProcessor.PlayGround di.Create(); } - // Image mask = Image.FromFile(Path.Combine(resolvedPath, "mask2.png")); + // Image mask = Image.FromFile(Path.Combine(resolvedPath, "mask2.png")); + //FileInfo fileInfo = new FileInfo(Path.Combine(resolvedPath, "rgba.png")); IEnumerable files = GetFilesByExtensions(di, ".png"); //IEnumerable files = GetFilesByExtensions(di, ".gif", ".webp", ".bmp", ".jpg", ".png", ".tif"); diff --git a/src/ImageProcessor.Playground/images/input/rgba.png b/src/ImageProcessor.Playground/images/input/rgba.png new file mode 100644 index 000000000..1ecbdf4e3 --- /dev/null +++ b/src/ImageProcessor.Playground/images/input/rgba.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:91c2a86b4f41313c9db541649ae0a97661a45ade40bb70b1ec784ab60b065e55 +size 171 diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 1bea02cb9..fb8773734 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -185,6 +185,7 @@ + diff --git a/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/ColorMoment.cs b/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/ColorMoment.cs index 343422ec5..d69b590bd 100644 --- a/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/ColorMoment.cs +++ b/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/ColorMoment.cs @@ -1,86 +1,186 @@ - +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// The color moment for holding pixel information. +// Adapted from +// +// -------------------------------------------------------------------------------------------------------------------- + namespace ImageProcessor.Imaging.Quantizers.WuQuantizer { + /// + /// The color moment for holding pixel information. + /// Adapted from + /// internal struct ColorMoment { + /// + /// The alpha. + /// public long Alpha; - public long Red; - public long Green; + + /// + /// The blue. + /// public long Blue; - public int Weight; + + /// + /// The green. + /// + public long Green; + + /// + /// The moment. + /// public float Moment; - public static ColorMoment operator +(ColorMoment c1, ColorMoment c2) - { - c1.Alpha += c2.Alpha; - c1.Red += c2.Red; - c1.Green += c2.Green; - c1.Blue += c2.Blue; - c1.Weight += c2.Weight; - c1.Moment += c2.Moment; - return c1; - } + /// + /// The red. + /// + public long Red; - public static ColorMoment operator -(ColorMoment c1, ColorMoment c2) + /// + /// The weight. + /// + public int Weight; + + /// + /// Adds one to another. + /// + /// + /// The first . + /// + /// + /// The second . + /// + /// + /// The representing the sum of the addition. + /// + public static ColorMoment operator +(ColorMoment firstAddend, ColorMoment secondAddend) { - c1.Alpha -= c2.Alpha; - c1.Red -= c2.Red; - c1.Green -= c2.Green; - c1.Blue -= c2.Blue; - c1.Weight -= c2.Weight; - c1.Moment -= c2.Moment; - return c1; + firstAddend.Alpha += secondAddend.Alpha; + firstAddend.Red += secondAddend.Red; + firstAddend.Green += secondAddend.Green; + firstAddend.Blue += secondAddend.Blue; + firstAddend.Weight += secondAddend.Weight; + firstAddend.Moment += secondAddend.Moment; + return firstAddend; } - public static ColorMoment operator -(ColorMoment c1) + /// + /// Subtracts one from another. + /// + /// + /// The from which the other will be subtracted + /// + /// + /// The that is to be subtracted. + /// + /// + /// The representing the difference of the subtraction. + /// + public static ColorMoment operator -(ColorMoment minuend, ColorMoment subtrahend) { - c1.Alpha = -c1.Alpha; - c1.Red = -c1.Red; - c1.Green = -c1.Green; - c1.Blue = -c1.Blue; - c1.Weight = -c1.Weight; - c1.Moment = -c1.Moment; - return c1; + minuend.Alpha -= subtrahend.Alpha; + minuend.Red -= subtrahend.Red; + minuend.Green -= subtrahend.Green; + minuend.Blue -= subtrahend.Blue; + minuend.Weight -= subtrahend.Weight; + minuend.Moment -= subtrahend.Moment; + return minuend; } - public void Add(Pixel p) + /// + /// Negates the given . + /// + /// + /// The to negate. + /// + /// + /// The negated result + /// + public static ColorMoment operator -(ColorMoment moment) { - byte pAlpha = p.Alpha; - byte pRed = p.Red; - byte pGreen = p.Green; - byte pBlue = p.Blue; - Alpha += pAlpha; - Red += pRed; - Green += pGreen; - Blue += pBlue; - Weight++; - Moment += pAlpha * pAlpha + pRed * pRed + pGreen * pGreen + pBlue * pBlue; + moment.Alpha = -moment.Alpha; + moment.Red = -moment.Red; + moment.Green = -moment.Green; + moment.Blue = -moment.Blue; + moment.Weight = -moment.Weight; + moment.Moment = -moment.Moment; + return moment; } - public void AddFast(ref ColorMoment c2) + /// + /// Adds a pixel to the current instance. + /// + /// + /// The pixel to add. + /// + public void Add(Pixel pixel) { - Alpha += c2.Alpha; - Red += c2.Red; - Green += c2.Green; - Blue += c2.Blue; - Weight += c2.Weight; - Moment += c2.Moment; + byte alpha = pixel.Alpha; + byte red = pixel.Red; + byte green = pixel.Green; + byte blue = pixel.Blue; + this.Alpha += alpha; + this.Red += red; + this.Green += green; + this.Blue += blue; + this.Weight++; + this.Moment += (alpha * alpha) + (red * red) + (green * green) + (blue * blue); } - public long Amplitude() + /// + /// Adds a color moment to the current instance more quickly. + /// + /// + /// The to add. + /// + public void AddFast(ref ColorMoment moment) { - return Alpha * Alpha + Red * Red + Green * Green + Blue * Blue; + this.Alpha += moment.Alpha; + this.Red += moment.Red; + this.Green += moment.Green; + this.Blue += moment.Blue; + this.Weight += moment.Weight; + this.Moment += moment.Moment; } - public long WeightedDistance() + /// + /// The amplitude. + /// + /// + /// The representing the amplitude. + /// + public long Amplitude() { - return this.Amplitude() / this.Weight; + return (this.Alpha * this.Alpha) + (this.Red * this.Red) + (this.Green * this.Green) + (this.Blue * this.Blue); } + /// + /// The variance. + /// + /// + /// The representing the variance. + /// public float Variance() { float result = this.Moment - ((float)this.Amplitude() / this.Weight); return float.IsNaN(result) ? 0.0f : result; } + + /// + /// The weighted distance. + /// + /// + /// The . + /// + public long WeightedDistance() + { + return this.Amplitude() / this.Weight; + } } -} +} \ No newline at end of file diff --git a/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/Histogram.cs b/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/Histogram.cs new file mode 100644 index 000000000..5a6369678 --- /dev/null +++ b/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/Histogram.cs @@ -0,0 +1,49 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// The histogram representing the distribution of color data. +// Adapted from +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Imaging.Quantizers.WuQuantizer +{ + using System; + + /// + /// The histogram representing the distribution of color data. + /// Adapted from + /// + public class Histogram + { + /// + /// The moments. + /// + internal readonly ColorMoment[,,,] Moments; + + /// + /// The side size. + /// + private const int SideSize = 33; + + /// + /// Initializes a new instance of the class. + /// + public Histogram() + { + // 47,436,840 bytes + this.Moments = new ColorMoment[SideSize, SideSize, SideSize, SideSize]; + } + + /// + /// The clear. + /// + internal void Clear() + { + Array.Clear(this.Moments, 0, SideSize * SideSize * SideSize * SideSize); + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/ImageBuffer.cs b/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/ImageBuffer.cs index 5341b1cbb..14dbbdf31 100644 --- a/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/ImageBuffer.cs +++ b/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/ImageBuffer.cs @@ -11,8 +11,10 @@ namespace ImageProcessor.Imaging.Quantizers.WuQuantizer { + using System; using System.Collections.Generic; using System.Drawing; + using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.Runtime.InteropServices; @@ -62,6 +64,20 @@ namespace ImageProcessor.Imaging.Quantizers.WuQuantizer int height = this.Image.Height; int[] buffer = new int[width]; Pixel[] pixels = new Pixel[width]; + //using (FastBitmap bitmap = new FastBitmap(this.Image)) + //{ + // for (int y = 0; y < height; y++) + // { + // for (int x = 0; x < width; x++) + // { + // Color color = bitmap.GetPixel(x, y); + // pixels[x] = new Pixel(color.A, color.R, color.G, color.B); + // } + + // yield return pixels; + // } + //} + for (int rowIndex = 0; rowIndex < height; rowIndex++) { BitmapData data = this.Image.LockBits(Rectangle.FromLTRB(0, rowIndex, width, rowIndex + 1), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); @@ -93,11 +109,16 @@ namespace ImageProcessor.Imaging.Quantizers.WuQuantizer { int width = this.Image.Width; int height = this.Image.Height; - var indexesIterator = lineIndexes.GetEnumerator(); + + IEnumerator indexesIterator = lineIndexes.GetEnumerator(); + for (int rowIndex = 0; rowIndex < height; rowIndex++) { indexesIterator.MoveNext(); + + BitmapData data = this.Image.LockBits(Rectangle.FromLTRB(0, rowIndex, width, rowIndex + 1), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); + try { Marshal.Copy(indexesIterator.Current, 0, data.Scan0, width); diff --git a/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/PaletteColorHistory.cs b/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/PaletteColorHistory.cs index 973f92884..190dd09e2 100644 --- a/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/PaletteColorHistory.cs +++ b/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/PaletteColorHistory.cs @@ -59,7 +59,7 @@ namespace ImageProcessor.Imaging.Quantizers.WuQuantizer /// Adds a pixel to the color history. /// /// - /// The pixel. + /// The pixel to add. /// public void AddPixel(Pixel pixel) { diff --git a/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/WuQuantizerBase.cs b/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/WuQuantizerBase.cs index 0f8ac9a21..4b49cf6ba 100644 --- a/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/WuQuantizerBase.cs +++ b/src/ImageProcessor/Imaging/Quantizers/WuQuantizer/WuQuantizerBase.cs @@ -4,23 +4,6 @@ using System.Linq; namespace ImageProcessor.Imaging.Quantizers.WuQuantizer { - public class Histogram - { - private const int SideSize = 33; - internal readonly ColorMoment[, , ,] Moments; - - public Histogram() - { - // 47,436,840 bytes - Moments = new ColorMoment[SideSize, SideSize, SideSize, SideSize]; - } - - internal void Clear() - { - Array.Clear(Moments, 0, SideSize * SideSize * SideSize * SideSize); - } - } - public abstract class WuQuantizerBase { protected const byte AlphaColor = 255;