mirror of https://github.com/SixLabors/ImageSharp
2 changed files with 174 additions and 0 deletions
@ -0,0 +1,139 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Six Labors Split License.
|
||||
|
|
||||
|
using Microsoft.Diagnostics.Runtime.Interop; |
||||
|
using SixLabors.ImageSharp.Formats.Jxl.Memory.ImageTypes; |
||||
|
using SixLabors.ImageSharp.Formats.Jxl.Processing.Butteraugli; |
||||
|
using SixLabors.ImageSharp.Formats.Jxl.Processing.Image; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Tests.Formats.Jxl.Processing; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Tests for Google Butteraugli (C# implementation), a tool
|
||||
|
/// used for comparing images in a more sophisticated way
|
||||
|
/// (the way humans may notice differences). For example,
|
||||
|
/// if every pixel was off by 1, PSNR, which operates on a
|
||||
|
/// pixel-by-pixel basis, would report a large difference,
|
||||
|
/// while Butteraugli would report barely any differences,
|
||||
|
/// as us humans wouldn't notice anything if every pixel
|
||||
|
/// was just off by one.
|
||||
|
/// </summary>
|
||||
|
public class ButteraugliTests |
||||
|
{ |
||||
|
private static JxlImage3F SinglePixelImage(float r, float g, float b) |
||||
|
{ |
||||
|
JxlImage3F img = new(TestEnvironment.Configuration, 1, 1); |
||||
|
img.PlaneRow(0, 0)[0] = r; |
||||
|
img.PlaneRow(1, 0)[0] = r; |
||||
|
img.PlaneRow(2, 0)[0] = r; |
||||
|
return img; |
||||
|
} |
||||
|
|
||||
|
private static void AddUniformNoise(JxlImage3F img, float d, ulong seed) |
||||
|
{ |
||||
|
Rng generator = new(seed); |
||||
|
|
||||
|
for (int y = 0; y < img.YSize; ++y) |
||||
|
{ |
||||
|
for (int c = 0; c < 3; ++c) |
||||
|
{ |
||||
|
Span<float> planeRow = img.PlaneRow(c, y); |
||||
|
|
||||
|
for (int x = 0; x < img.XSize; ++x) |
||||
|
{ |
||||
|
planeRow[x] += generator.UniformF(-d, d); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static void AddEdge(JxlImage3F image, float d, int x0, int y0) |
||||
|
{ |
||||
|
int h = Math.Min(image.YSize - y0, 100); |
||||
|
int w = Math.Min(image.XSize - x0, 5); |
||||
|
|
||||
|
for (int dy = 0; dy < h; ++dy) |
||||
|
{ |
||||
|
Span<float> planeRow = image.PlaneRow(1, y0 + dy); |
||||
|
|
||||
|
for (int dx = 0; dx < w; ++dx) |
||||
|
{ |
||||
|
planeRow[x0 + dx] += d; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void TestSinglePixel() |
||||
|
{ |
||||
|
JxlImage3F rgb0 = SinglePixelImage(0.5f, 0.5f, 0.5f); |
||||
|
JxlImage3F rgb1 = SinglePixelImage(0.5f, 0.49f, 0.5f); |
||||
|
|
||||
|
ButteraugliParameters butteraugliParameters = new(); |
||||
|
JxlImageF diffmap = new(); |
||||
|
|
||||
|
Assert.True( |
||||
|
Butteraugli.ButteraugliInterface(TestEnvironment.Configuration, rgb0, rgb1, butteraugliParameters, diffmap, out double diffval), |
||||
|
"Butteraugli initialization failed"); |
||||
|
|
||||
|
Assert.True(new TolerantMath(0.5).AreEqual(diffval, 2.5), $"Diff value isn't even close to 2.5 (it's {diffval})"); |
||||
|
|
||||
|
JxlImageF diffmap2 = new(); |
||||
|
Assert.True(Butteraugli.ButteraugliInterfaceInPlace( |
||||
|
TestEnvironment.Configuration, |
||||
|
rgb0, |
||||
|
rgb1, |
||||
|
butteraugliParameters, |
||||
|
diffmap2, |
||||
|
out double diffval2)); |
||||
|
|
||||
|
Assert.True(new TolerantMath(1e-10).AreEqual(diffval, diffval2), $"Diff value isn't even close to diffval2 (diffval={diffval}, diffval2={diffval2})"); |
||||
|
} |
||||
|
|
||||
|
// TODO: we need to port test image stuff from libjxl
|
||||
|
[Fact] |
||||
|
public void TestLargeImage() |
||||
|
{ |
||||
|
const int xSize = 1024; |
||||
|
const int ySize = 1024; |
||||
|
|
||||
|
JxlTestImage img = new(); |
||||
|
img.SetDimensions(xSize, ySize); |
||||
|
|
||||
|
JxlTestFrame frame = img.AddFrame(); |
||||
|
frame.RandomFill(777); |
||||
|
|
||||
|
JxlImage3F rgb0 = GetColorImage(img.Ppf); |
||||
|
JxlImage3F rgb1 = new(TestEnvironment.Configuration, xSize, ySize); |
||||
|
JxlImageOperations.CopyImage(rgb0, rgb1); |
||||
|
|
||||
|
AddUniformNoise(rgb1, 0.02f, 7777uL); |
||||
|
AddEdge(rgb1, 0.1f, xSize / 2, xSize / 2); |
||||
|
|
||||
|
ButteraugliParameters butteraugliParameters = new(); |
||||
|
JxlImageF diffmap = new(); |
||||
|
Assert.True( |
||||
|
Butteraugli.ButteraugliInterface(TestEnvironment.Configuration,, rgb0, rgb1, butteraugliParameters, diffmap, out double diffval), |
||||
|
"Couldn't initialize Butteraugli"); |
||||
|
|
||||
|
double distp = Butteraugli.ComputeDistanceP(diffmap, butteraugliParameters, 3.0); |
||||
|
Assert.True(new TolerantMath(0.5).AreEqual(diffval, 4.0), $"Diff isn't even close to 4.0 (diffval={diffval})"); |
||||
|
Assert.True(new TolerantMath(0.5).AreEqual(distp, 1.5), $"Distance isn't even close to 4.0 (distp={distp})"); |
||||
|
|
||||
|
JxlImageF diffmap2 = new(); |
||||
|
Assert.True( |
||||
|
Butteraugli.ButteraugliInterfaceInPlace( |
||||
|
TestEnvironment.Configuration, |
||||
|
rgb0, |
||||
|
rgb1, |
||||
|
butteraugliParameters, |
||||
|
diffmap2, |
||||
|
out double diffval2), |
||||
|
"Butteraugli in-place interface initialization failed"); |
||||
|
|
||||
|
double distp2 = Butteraugli.ComputeDistanceP(diffmap2, butteraugliParameters, 3.0); |
||||
|
|
||||
|
Assert.True(new TolerantMath(5e-7).AreEqual(diffval, diffval2), $"Diffval != diffval2 (diffval={diffval}, diffval2={diffval2})"); |
||||
|
Assert.True(new TolerantMath(1e-7).AreEqual(distp, distp2), $"Distp != distp2 (distp={distp}, distp2={distp2})"); |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue