From 84099e4793ecba7927a28d8e02e159dc21869efa Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 26 Jun 2018 13:31:41 +1000 Subject: [PATCH] Use DistanceSquared --- .../Processors/PaletteDitherProcessorBase.cs | 4 +- .../FrameQuantizerBase{TPixel}.cs | 34 +++++++--------- .../OctreeFrameQuantizer{TPixel}.cs | 40 +++++++++---------- 3 files changed, 36 insertions(+), 42 deletions(-) diff --git a/src/ImageSharp/Processing/Dithering/Processors/PaletteDitherProcessorBase.cs b/src/ImageSharp/Processing/Dithering/Processors/PaletteDitherProcessorBase.cs index 683ef7044..9317a6aad 100644 --- a/src/ImageSharp/Processing/Dithering/Processors/PaletteDitherProcessorBase.cs +++ b/src/ImageSharp/Processing/Dithering/Processors/PaletteDitherProcessorBase.cs @@ -42,8 +42,8 @@ namespace SixLabors.ImageSharp.Processing.Dithering.Processors } // Not found - loop through the palette and find the nearest match. - float leastDistance = int.MaxValue; - float secondLeastDistance = int.MaxValue; + float leastDistance = float.MaxValue; + float secondLeastDistance = float.MaxValue; var vector = pixel.ToVector4(); TPixel closest = default; diff --git a/src/ImageSharp/Processing/Quantization/FrameQuantizers/FrameQuantizerBase{TPixel}.cs b/src/ImageSharp/Processing/Quantization/FrameQuantizers/FrameQuantizerBase{TPixel}.cs index 08b0cb5c3..0e764b108 100644 --- a/src/ImageSharp/Processing/Quantization/FrameQuantizers/FrameQuantizerBase{TPixel}.cs +++ b/src/ImageSharp/Processing/Quantization/FrameQuantizers/FrameQuantizerBase{TPixel}.cs @@ -125,11 +125,10 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers protected byte GetClosestPixel(TPixel pixel, TPixel[] colorPalette, Dictionary cache) { // Check if the color is in the lookup table - if (cache.TryGetValue(pixel, out byte value)) - { - return value; - } - + // if (cache.TryGetValue(pixel, out byte value)) + // { + // return value; + // } return this.GetClosestPixelSlow(pixel, colorPalette, cache); } @@ -137,34 +136,31 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers private byte GetClosestPixelSlow(TPixel pixel, TPixel[] colorPalette, Dictionary cache) { // Loop through the palette and find the nearest match. - byte colorIndex = 0; - float leastDistance = int.MaxValue; + int colorIndex = 0; + float leastDistance = float.MaxValue; var vector = pixel.ToVector4(); for (int index = 0; index < colorPalette.Length; index++) { - float distance = Vector4.Distance(vector, colorPalette[index].ToVector4()); + ref TPixel candidate = ref colorPalette[index]; + float distance = Vector4.DistanceSquared(vector, candidate.ToVector4()); - // Greater... Move on. - if (!(distance < leastDistance)) + if (distance < leastDistance) { - continue; + colorIndex = index; + leastDistance = distance; } - colorIndex = (byte)index; - leastDistance = distance; - - // And if it's an exact match, exit the loop - if (MathF.Abs(distance) < Constants.Epsilon) + // If it's an exact match, exit the loop + if (distance == 0) { break; } } // Now I have the index, pop it into the cache for next time - cache.Add(pixel, colorIndex); - - return colorIndex; + // cache.Add(pixel, colorIndex); + return (byte)colorIndex; } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Quantization/FrameQuantizers/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Quantization/FrameQuantizers/OctreeFrameQuantizer{TPixel}.cs index df5fee506..ea30e3f35 100644 --- a/src/ImageSharp/Processing/Quantization/FrameQuantizers/OctreeFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Quantization/FrameQuantizers/OctreeFrameQuantizer{TPixel}.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; @@ -18,11 +19,6 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers internal sealed class OctreeFrameQuantizer : FrameQuantizerBase where TPixel : struct, IPixel { - /// - /// A lookup table for colors - /// - private readonly Dictionary colorMap = new Dictionary(); - /// /// Maximum allowed color depth /// @@ -33,6 +29,11 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers /// private readonly Octree octree; + /// + /// A lookup table for colors + /// + private Dictionary colorMap = new Dictionary(); + /// /// The reduced image palette /// @@ -476,7 +477,6 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers | ((rgba.R & Mask[level]) >> shift); OctreeNode child = this.children[index]; - if (child == null) { // Create a new child node and store it in the array @@ -501,12 +501,13 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers // Loop through all children and add their information to this node for (int index = 0; index < 8; index++) { - if (this.children[index] != null) + OctreeNode child = this.children[index]; + if (child != null) { - this.red += this.children[index].red; - this.green += this.children[index].green; - this.blue += this.children[index].blue; - this.pixelCount += this.children[index].pixelCount; + this.red += child.red; + this.green += child.green; + this.blue += child.blue; + this.pixelCount += child.pixelCount; ++childNodes; this.children[index] = null; } @@ -528,14 +529,10 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers { if (this.leaf) { - // This seems faster than using Vector4 - byte r = (this.red / this.pixelCount).ToByte(); - byte g = (this.green / this.pixelCount).ToByte(); - byte b = (this.blue / this.pixelCount).ToByte(); - - // And set the color of the palette entry + // Set the color of the palette entry + var vector = Vector3.Clamp(new Vector3(this.red, this.green, this.blue) / this.pixelCount, Vector3.Zero, new Vector3(255)); TPixel pixel = default; - pixel.PackFromRgba32(new Rgba32(r, g, b, 255)); + pixel.PackFromRgba32(new Rgba32((byte)vector.X, (byte)vector.Y, (byte)vector.Z, byte.MaxValue)); palette[index] = pixel; // Consume the next palette index @@ -573,13 +570,14 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers | ((rgba.G & Mask[level]) >> (shift - 1)) | ((rgba.R & Mask[level]) >> shift); - if (this.children[pixelIndex] != null) + OctreeNode child = this.children[pixelIndex]; + if (child != null) { - index = this.children[pixelIndex].GetPaletteIndex(ref pixel, level + 1, ref rgba); + index = child.GetPaletteIndex(ref pixel, level + 1, ref rgba); } else { - throw new Exception($"Cannot retrive a pixel at the given index {pixelIndex}."); + throw new Exception($"Cannot retrieve a pixel at the given index {pixelIndex}."); } }