Browse Source

Use DistanceSquared

af/merge-core
James Jackson-South 8 years ago
parent
commit
84099e4793
  1. 4
      src/ImageSharp/Processing/Dithering/Processors/PaletteDitherProcessorBase.cs
  2. 34
      src/ImageSharp/Processing/Quantization/FrameQuantizers/FrameQuantizerBase{TPixel}.cs
  3. 40
      src/ImageSharp/Processing/Quantization/FrameQuantizers/OctreeFrameQuantizer{TPixel}.cs

4
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;

34
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<TPixel, byte> 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<TPixel, byte> 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;
}
}
}

40
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<TPixel> : FrameQuantizerBase<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// A lookup table for colors
/// </summary>
private readonly Dictionary<TPixel, byte> colorMap = new Dictionary<TPixel, byte>();
/// <summary>
/// Maximum allowed color depth
/// </summary>
@ -33,6 +29,11 @@ namespace SixLabors.ImageSharp.Processing.Quantization.FrameQuantizers
/// </summary>
private readonly Octree octree;
/// <summary>
/// A lookup table for colors
/// </summary>
private Dictionary<TPixel, byte> colorMap = new Dictionary<TPixel, byte>();
/// <summary>
/// The reduced image palette
/// </summary>
@ -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}.");
}
}

Loading…
Cancel
Save