Browse Source

managed to figure out everything regarding IDCT reference implementations

pull/322/head
Anton Firszov 9 years ago
parent
commit
41eff8c3b2
  1. 53
      src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs
  2. 64
      src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs
  3. 9
      tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.FastFloatingPointDCT.cs
  4. 29
      tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.StandardIntegerDCT.cs
  5. 51
      tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.AccurateDCT.cs
  6. 9
      tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.FastFloatingPointDCT.cs
  7. 7
      tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.StandardIntegerDCT.cs

53
src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs

@ -60,6 +60,58 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
return !left.Equals(right);
}
public static Block8x8 operator *(Block8x8 block, int value)
{
Block8x8 result = block;
for (int i = 0; i < Size; i++)
{
int val = result[i];
val *= value;
result[i] = (short)val;
}
return result;
}
public static Block8x8 operator /(Block8x8 block, int value)
{
Block8x8 result = block;
for (int i = 0; i < Size; i++)
{
int val = result[i];
val /= value;
result[i] = (short)val;
}
return result;
}
public static Block8x8 operator +(Block8x8 block, int value)
{
Block8x8 result = block;
for (int i = 0; i < Size; i++)
{
int val = result[i];
val += value;
result[i] = (short)val;
}
return result;
}
public static Block8x8 operator -(Block8x8 block, int value)
{
Block8x8 result = block;
for (int i = 0; i < Size; i++)
{
int val = result[i];
val -= value;
result[i] = (short)val;
}
return result;
}
/// <summary>
/// Pointer-based "Indexer" (getter part)
/// </summary>
@ -195,5 +247,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
return result;
}
}
}

64
src/ImageSharp/Formats/Jpeg/Common/Block8x8F.cs

@ -89,6 +89,58 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
set => this[(y * 8) + x] = value;
}
public static Block8x8F operator *(Block8x8F block, float value)
{
Block8x8F result = block;
for (int i = 0; i < Size; i++)
{
float val = result[i];
val *= value;
result[i] = val;
}
return result;
}
public static Block8x8F operator /(Block8x8F block, float value)
{
Block8x8F result = block;
for (int i = 0; i < Size; i++)
{
float val = result[i];
val /= value;
result[i] = (float)val;
}
return result;
}
public static Block8x8F operator +(Block8x8F block, float value)
{
Block8x8F result = block;
for (int i = 0; i < Size; i++)
{
float val = result[i];
val += value;
result[i] = (float)val;
}
return result;
}
public static Block8x8F operator -(Block8x8F block, float value)
{
Block8x8F result = block;
for (int i = 0; i < Size; i++)
{
float val = result[i];
val -= value;
result[i] = (float)val;
}
return result;
}
/// <summary>
/// Pointer-based "Indexer" (getter part)
/// </summary>
@ -119,18 +171,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
fp[idx] = value;
}
//public Block8x8 AsInt16Block()
//{
// // TODO: Optimize this
// var result = default(Block8x8);
// for (int i = 0; i < Size; i++)
// {
// result[i] = (short)this[i];
// }
// return result;
//}
/// <summary>
/// Fill the block with defaults (zeroes)
/// </summary>

9
tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.FastFloatingPointDCT.cs

@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
this.CompareBlocks(data.ConvertAllToFloat(), src, 2f);
}
[Theory]
[Theory(Skip = "Sandboxing only! (Incorrect reference implementation)")]
[InlineData(42)]
[InlineData(1)]
[InlineData(2)]
@ -82,12 +82,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
int[] intData = JpegUtilityTestFixture.Create8x8RandomIntData(-1000, 1000, seed);
float[] floatSrc = intData.ConvertAllToFloat();
ReferenceImplementations.StandardIntegerDCT.TransformFDCTInplace(intData);
ReferenceImplementations.StandardIntegerDCT.Subtract128_TransformFDCT_Upscale8_Inplace(intData);
float[] dest = new float[64];
float[] temp = new float[64];
ReferenceImplementations.FastFloatingPointDCT.fDCT2D_llm(floatSrc, dest, temp, offsetSourceByNeg128: true);
ReferenceImplementations.FastFloatingPointDCT.fDCT2D_llm(floatSrc, dest, temp, subtract128FromSource: true);
this.CompareBlocks(intData.ConvertAllToFloat(), dest, 2f);
}
@ -104,7 +104,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
source.LoadFrom(floatData);
Block8x8F expected = ReferenceImplementations.AccurateDCT.TransformFDCT(ref source);
Block8x8F actual = ReferenceImplementations.FastFloatingPointDCT.TransformFDCT(ref source);
Block8x8F actual = ReferenceImplementations.FastFloatingPointDCT.TransformFDCT_UpscaleBy8(ref source);
actual /= 8;
this.CompareBlocks(expected, actual, 1f);

29
tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementationsTests.StandardIntegerDCT.cs

@ -1,3 +1,4 @@
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
using System;
@ -10,16 +11,14 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
public partial class ReferenceImplementationsTests
{
public class StandardIntegerDCT
public class StandardIntegerDCT : JpegUtilityTestFixture
{
public StandardIntegerDCT(ITestOutputHelper output)
: base(output)
{
this.Output = output;
}
private ITestOutputHelper Output { get; }
[Theory]
[Theory(Skip = "Sandboxing only! (Incorrect reference implementation)")]
[InlineData(42)]
[InlineData(1)]
[InlineData(2)]
@ -54,18 +53,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
int[] data = Create8x8RandomIntData(-1000, 1000, seed);
Block8x8 source = default(Block8x8);
Block8x8F source = default(Block8x8F);
source.LoadFrom(data);
Block8x8 expected = ReferenceImplementations.AccurateDCT.TransformFDCT(ref source);
Block8x8 actual = ReferenceImplementations.StandardIntegerDCT.TransformFDCT(ref source);
long diff = Block8x8.TotalDifference(ref expected, ref actual);
this.Output.WriteLine(expected.ToString());
this.Output.WriteLine(actual.ToString());
this.Output.WriteLine("DIFFERENCE: " + diff);
Block8x8F expected = ReferenceImplementations.AccurateDCT.TransformFDCT(ref source);
Assert.True(diff < 4);
source += 128;
Block8x8 temp = source.RoundAsInt16Block();
Block8x8 actual8 = ReferenceImplementations.StandardIntegerDCT.Subtract128_TransformFDCT_Upscale8(ref temp);
Block8x8F actual = actual8.AsFloatBlock();
actual /= 8;
this.CompareBlocks(expected, actual, 1f);
}
@ -79,7 +78,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
Span<int> block = original.AddScalarToAllValues(128);
ReferenceImplementations.StandardIntegerDCT.TransformFDCTInplace(block);
ReferenceImplementations.StandardIntegerDCT.Subtract128_TransformFDCT_Upscale8_Inplace(block);
for (int i = 0; i < 64; i++)
{

51
tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.AccurateDCT.cs

@ -7,7 +7,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
internal static partial class ReferenceImplementations
{
/// <summary>
/// Reference implementations based on:
/// True accurate FDCT/IDCT implementations. We should test everything against them!
/// Based on:
/// https://github.com/keithw/mympeg2enc/blob/master/idct.c#L222
/// Claiming:
/// /* reference idct taken from "ieeetest.c"
@ -18,8 +19,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
internal static class AccurateDCT
{
private static double[,] CosLut = InitCosLut();
public static Block8x8 TransformIDCT(ref Block8x8 block)
{
Block8x8F temp = block.AsFloatBlock();
@ -50,27 +50,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
result.CopyTo(span);
}
private static double[,] InitCosLut()
{
double[,] coslu = new double[8,8];
int a, b;
double tmp;
for (a = 0; a < 8; a++)
for (b = 0; b < 8; b++)
{
tmp = Math.Cos((double)((a + a + 1) * b) * (3.14159265358979323846 / 16.0));
if (b == 0)
{
tmp /= Math.Sqrt(2.0);
}
coslu[a, b] = tmp * 0.5;
}
return coslu;
}
public static Block8x8F TransformIDCT(ref Block8x8F block)
{
int x, y, u, v;
@ -92,8 +71,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
}
return res;
}
public static Block8x8F TransformFDCT(ref Block8x8F block)
{
int x, y, u, v;
@ -119,7 +97,26 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
}
return res;
}
}
private static double[,] InitCosLut()
{
double[,] coslu = new double[8, 8];
int a, b;
double tmp;
for (a = 0; a < 8; a++)
for (b = 0; b < 8; b++)
{
tmp = Math.Cos((double)((a + a + 1) * b) * (3.14159265358979323846 / 16.0));
if (b == 0)
{
tmp /= Math.Sqrt(2.0);
}
coslu[a, b] = tmp * 0.5;
}
return coslu;
}
}
}
}

9
tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.FastFloatingPointDCT.cs

@ -1,3 +1,4 @@
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
{
using System;
@ -24,7 +25,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
return result;
}
public static Block8x8F TransformFDCT(ref Block8x8F source)
public static Block8x8F TransformFDCT_UpscaleBy8(ref Block8x8F source)
{
float[] s = new float[64];
source.CopyTo(s);
@ -480,15 +481,15 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
y[1] = c0 + c3;
y[7] = c0 - c3;
}
internal static void fDCT2D_llm(
Span<float> s,
Span<float> d,
Span<float> temp,
bool downscaleBy8 = false,
bool offsetSourceByNeg128 = false)
bool subtract128FromSource = false)
{
Span<float> sWorker = offsetSourceByNeg128 ? s.AddScalarToAllValues(-128f) : s;
Span<float> sWorker = subtract128FromSource ? s.AddScalarToAllValues(-128f) : s;
for (int j = 0; j < 8; j++)
{

7
tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.StandardIntegerDCT.cs

@ -1,3 +1,4 @@
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
{
using System;
@ -65,11 +66,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
/// </summary>
private const int CenterJSample = 128;
public static Block8x8 TransformFDCT(ref Block8x8 block)
public static Block8x8 Subtract128_TransformFDCT_Upscale8(ref Block8x8 block)
{
int[] temp = new int[Block8x8.Size];
block.CopyTo(temp);
TransformFDCTInplace(temp);
Subtract128_TransformFDCT_Upscale8_Inplace(temp);
var result = default(Block8x8);
result.LoadFrom(temp);
return result;
@ -91,7 +92,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
/// Leave results scaled up by an overall factor of 8.
/// </summary>
/// <param name="block">The block of coefficients.</param>
public static void TransformFDCTInplace(Span<int> block)
public static void Subtract128_TransformFDCT_Upscale8_Inplace(Span<int> block)
{
// Pass 1: process rows.
for (int y = 0; y < 8; y++)

Loading…
Cancel
Save