Added first quantization tests

This commit is contained in:
Darth Affe 2024-07-06 17:12:14 +02:00
parent 5242845a3e
commit 822d9fa6f1
3 changed files with 205 additions and 2 deletions

View File

@ -85,6 +85,6 @@ public class ColorSourceGenerator : IIncrementalGenerator
foreach ((string name, string source) in feature.GenerateFor(colorFormats))
context.AddSource($"{name}.g.cs", SourceText.From(source, Encoding.UTF8));
}
#endregion
}

View File

@ -1,8 +1,94 @@
namespace HPPH.Reference;
using System.Numerics;
namespace HPPH.Reference;
public static partial class ReferencePixelHelper
{
#region Methods
public static IColor[] CreateColorPalette(IImage image, int paletteSize)
=> CreateColorPalette(image.ToArray(), paletteSize);
public static T[] CreateColorPalette<T>(RefImage<T> image, int paletteSize)
where T : unmanaged, IColor
=> CreateColorPalette<T>(image.ToArray(), paletteSize);
public static T[] CreateColorPalette<T>(Span<T> colors, int paletteSize)
where T : unmanaged, IColor =>
CreateColorPalette(colors.ToArray().Cast<IColor>().ToArray(), paletteSize).Select(x => T.Create(x.R, x.G, x.B, x.A)).Cast<T>().ToArray();
private static IColor[] CreateColorPalette(IColor[] colors, int paletteSize)
{
int splits = BitOperations.Log2((uint)paletteSize);
List<ColorCube> cubes = [new ColorCube(colors)];
for (int i = 0; i < splits; i++)
{
List<ColorCube> currentCubes = [.. cubes];
foreach (ColorCube currentCube in currentCubes)
{
currentCube.Split(out ColorCube a, out ColorCube b);
cubes.Remove(currentCube);
cubes.Add(a);
cubes.Add(b);
}
}
return cubes.Select(c => c.GetAverageColor()).ToArray();
}
#endregion
}
internal class ColorCube
{
#region Properties & Fields
private readonly List<IColor> _colors;
#endregion
#region Constructors
internal ColorCube(IList<IColor> colors)
{
int redRange = colors.Max(c => c.R) - colors.Min(c => c.R);
int greenRange = colors.Max(c => c.G) - colors.Min(c => c.G);
int blueRange = colors.Max(c => c.B) - colors.Min(c => c.B);
if ((redRange > greenRange) && (redRange > blueRange))
_colors = [.. colors.OrderBy(a => a.R)];
else if (greenRange > blueRange)
_colors = [.. colors.OrderBy(a => a.G)];
else
_colors = [.. colors.OrderBy(a => a.B)];
}
#endregion
#region Methods
internal void Split(out ColorCube a, out ColorCube b)
{
int median = _colors.Count / 2;
a = new ColorCube(_colors.GetRange(0, median));
b = new ColorCube(_colors.GetRange(median, _colors.Count - median));
}
internal IColor GetAverageColor()
{
int r = _colors.Sum(x => x.R);
int g = _colors.Sum(x => x.G);
int b = _colors.Sum(x => x.B);
int a = _colors.Sum(x => x.A);
return new ColorRGBA((byte)(r / _colors.Count),
(byte)(g / _colors.Count),
(byte)(b / _colors.Count),
(byte)(a / _colors.Count));
}
#endregion
}

117
HPPH.Test/QuantizeTests.cs Normal file
View File

@ -0,0 +1,117 @@
using HPPH.Reference;
namespace HPPH.Test;
[TestClass]
public class CreateColorPaletteTests
{
private static IEnumerable<string> GetTestImages() => Directory.EnumerateFiles(@"..\..\..\..\sample_data", "*.png", SearchOption.AllDirectories);
[TestMethod]
public void CreateColorPaletteReadOnlySpan3ByteSize1()
{
foreach (string image in GetTestImages())
{
ColorRGB[] data = ImageHelper.Get3ByteColorsFromImage(image);
Span<ColorRGB> span = data;
ColorRGB[] reference = [.. ReferencePixelHelper.CreateColorPalette(span, 1).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
ColorRGB[] test = [.. PixelHelper.CreateColorPalette(span, 1).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
Assert.AreEqual(reference.Length, test.Length, "Palette Size differs");
for (int i = 0; i < reference.Length; i++)
Assert.AreEqual(reference[i], test[i], $"Index {i} differs");
}
}
[TestMethod]
public void CreateColorPaletteReadOnlySpan3ByteSize4()
{
foreach (string image in GetTestImages())
{
ColorRGB[] data = ImageHelper.Get3ByteColorsFromImage(image);
Span<ColorRGB> span = data;
ColorRGB[] reference = [.. ReferencePixelHelper.CreateColorPalette(span, 2).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
ColorRGB[] test = [.. PixelHelper.CreateColorPalette(span, 2).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
Assert.AreEqual(reference.Length, test.Length, "Palette Size differs");
for (int i = 0; i < reference.Length; i++)
Assert.AreEqual(reference[i], test[i], $"Index {i} differs");
}
}
[TestMethod]
public void CreateColorPaletteReadOnlySpan3ByteSize16()
{
foreach (string image in GetTestImages())
{
ColorRGB[] data = ImageHelper.Get3ByteColorsFromImage(image);
Span<ColorRGB> span = data;
ColorRGB[] reference = [.. ReferencePixelHelper.CreateColorPalette(span, 16).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
ColorRGB[] test = [.. PixelHelper.CreateColorPalette(span, 16).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
Assert.AreEqual(reference.Length, test.Length, "Palette Size differs");
for (int i = 0; i < reference.Length; i++)
Assert.AreEqual(reference[i], test[i], $"Index {i} differs");
}
}
[TestMethod]
public void CreateColorPaletteReadOnlySpan4ByteSize1()
{
foreach (string image in GetTestImages())
{
ColorRGBA[] data = ImageHelper.Get4ByteColorsFromImage(image);
Span<ColorRGBA> span = data;
ColorRGBA[] reference = [.. ReferencePixelHelper.CreateColorPalette(span, 1).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
ColorRGBA[] test = [.. PixelHelper.CreateColorPalette(span, 1).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
Assert.AreEqual(reference.Length, test.Length, "Palette Size differs");
for (int i = 0; i < reference.Length; i++)
Assert.AreEqual(reference[i], test[i], $"Index {i} differs");
}
}
[TestMethod]
public void CreateColorPaletteReadOnlySpan4ByteSize4()
{
foreach (string image in GetTestImages())
{
ColorRGBA[] data = ImageHelper.Get4ByteColorsFromImage(image);
Span<ColorRGBA> span = data;
ColorRGBA[] reference = [.. ReferencePixelHelper.CreateColorPalette(span, 2).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
ColorRGBA[] test = [.. PixelHelper.CreateColorPalette(span, 2).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
Assert.AreEqual(reference.Length, test.Length, "Palette Size differs");
for (int i = 0; i < reference.Length; i++)
Assert.AreEqual(reference[i], test[i], $"Index {i} differs");
}
}
[TestMethod]
public void CreateColorPaletteReadOnlySpan4ByteSize16()
{
foreach (string image in GetTestImages())
{
ColorRGBA[] data = ImageHelper.Get4ByteColorsFromImage(image);
Span<ColorRGBA> span = data;
ColorRGBA[] reference = [.. ReferencePixelHelper.CreateColorPalette(span, 16).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
ColorRGBA[] test = [.. PixelHelper.CreateColorPalette(span, 16).OrderBy(x => x.R).ThenBy(x => x.G).ThenBy(x => x.B).ThenBy(x => x.A)];
Assert.AreEqual(reference.Length, test.Length, "Palette Size differs");
for (int i = 0; i < reference.Length; i++)
Assert.AreEqual(reference[i], test[i], $"Index {i} differs");
}
}
}