From dfbdba57637f0819d983afc5a450cd07fc3352df Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Feb 2017 00:02:01 +1100 Subject: [PATCH] Use caching for the distance calculation --- src/ImageSharp/Quantizers/Octree/Quantizer.cs | 48 +++++++++++++------ .../Quantizers/Palette/PaletteQuantizer.cs | 42 ++-------------- 2 files changed, 37 insertions(+), 53 deletions(-) diff --git a/src/ImageSharp/Quantizers/Octree/Quantizer.cs b/src/ImageSharp/Quantizers/Octree/Quantizer.cs index 4d16c5df3..87705de94 100644 --- a/src/ImageSharp/Quantizers/Octree/Quantizer.cs +++ b/src/ImageSharp/Quantizers/Octree/Quantizer.cs @@ -6,6 +6,7 @@ namespace ImageSharp.Quantizers { using System; + using System.Collections.Generic; using System.Numerics; using System.Runtime.CompilerServices; @@ -18,6 +19,11 @@ namespace ImageSharp.Quantizers public abstract class Quantizer : IDitheredQuantizer where TColor : struct, IPackedPixel, IEquatable { + /// + /// A lookup table for colors + /// + private readonly Dictionary colorMap = new Dictionary(); + /// /// Flag used to indicate whether a single pass or two passes are needed for quantization. /// @@ -129,7 +135,7 @@ namespace ImageSharp.Quantizers { // Apply the dithering matrix TColor sourcePixel = source[x, y]; - TColor transformedPixel = this.palette[GetClosestColor(sourcePixel, this.palette)]; + TColor transformedPixel = this.palette[this.GetClosestColor(sourcePixel, this.palette, this.colorMap)]; this.DitherType.Dither(source, sourcePixel, transformedPixel, x, y, width, height); } @@ -171,32 +177,46 @@ namespace ImageSharp.Quantizers /// Returns the closest color from the palette to the given color by calculating the Euclidean distance. /// /// The color. - /// The color palette. + /// The color palette. + /// The cache to store the result in. /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static byte GetClosestColor(TColor pixel, TColor[] palette) + protected byte GetClosestColor(TColor pixel, TColor[] colorPalette, Dictionary cache) { + // Check if the color is in the lookup table + if (this.colorMap.ContainsKey(pixel)) + { + return this.colorMap[pixel]; + } + + // Not found - loop through the palette and find the nearest match. + byte colorIndex = 0; float leastDistance = int.MaxValue; Vector4 vector = pixel.ToVector4(); - byte colorIndex = 0; - for (int index = 0; index < palette.Length; index++) + for (int index = 0; index < colorPalette.Length; index++) { - float distance = Vector4.Distance(vector, palette[index].ToVector4()); + float distance = Vector4.Distance(vector, colorPalette[index].ToVector4()); - if (distance < leastDistance) + // Greater... Move on. + if (!(distance < leastDistance)) { - colorIndex = (byte)index; - leastDistance = distance; + continue; + } - // And if it's an exact match, exit the loop - if (Math.Abs(distance) < Constants.Epsilon) - { - break; - } + colorIndex = (byte)index; + leastDistance = distance; + + // And if it's an exact match, exit the loop + if (Math.Abs(distance) < Constants.Epsilon) + { + break; } } + // Now I have the index, pop it into the cache for next time + this.colorMap.Add(pixel, colorIndex); + return colorIndex; } } diff --git a/src/ImageSharp/Quantizers/Palette/PaletteQuantizer.cs b/src/ImageSharp/Quantizers/Palette/PaletteQuantizer.cs index abf1e5dc5..e55d67037 100644 --- a/src/ImageSharp/Quantizers/Palette/PaletteQuantizer.cs +++ b/src/ImageSharp/Quantizers/Palette/PaletteQuantizer.cs @@ -7,15 +7,14 @@ namespace ImageSharp.Quantizers { using System; using System.Collections.Generic; - using System.Numerics; /// /// Encapsulates methods to create a quantized image based upon the given palette. /// /// /// The pixel format. - public class PaletteQuantizer : Quantizer - where TColor : struct, IPackedPixel, IEquatable + public sealed class PaletteQuantizer : Quantizer + where TColor : struct, IPackedPixel, IEquatable { /// /// The pixel buffer, used to reduce allocations. @@ -73,42 +72,7 @@ namespace ImageSharp.Quantizers /// protected override byte QuantizePixel(TColor pixel) { - byte colorIndex = 0; - TColor colorHash = pixel; - - // Check if the color is in the lookup table - if (this.colorMap.ContainsKey(colorHash)) - { - colorIndex = this.colorMap[colorHash]; - } - else - { - // Not found - loop through the palette and find the nearest match. - float leastDistance = int.MaxValue; - Vector4 vector = pixel.ToVector4(); - - for (int index = 0; index < this.colors.Length; index++) - { - float distance = Vector4.Distance(vector, this.colors[index].ToVector4()); - - if (distance < leastDistance) - { - colorIndex = (byte)index; - leastDistance = distance; - - // And if it's an exact match, exit the loop - if (Math.Abs(distance) < Constants.Epsilon) - { - break; - } - } - } - - // Now I have the color, pop it into the cache for next time - this.colorMap.Add(colorHash, colorIndex); - } - - return colorIndex; + return this.GetClosestColor(pixel, this.colors, this.colorMap); } ///