Browse Source

optimized quantization

af/merge-core
Anton Firszov 9 years ago
parent
commit
005a454b40
  1. 28
      src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegBlockPostProcessor.cs
  2. 23
      src/ImageSharp/Formats/Jpeg/Common/ZigZag.cs
  3. 4
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegScanDecoder.ComputationData.cs
  4. 4
      src/ImageSharp/Formats/Jpeg/GolangPort/JpegEncoderCore.cs
  5. 26
      tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs
  6. 4
      tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs
  7. 2
      tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.cs

28
src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegBlockPostProcessor.cs

@ -34,26 +34,22 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
postProcessor->pointers = new DataPointers(&postProcessor->data);
int qtIndex = component.QuantizationTableIndex;
postProcessor->data.QuantiazationTable = decoder.QuantizationTables[qtIndex];
postProcessor->data.DequantiazationTable = ZigZag.CreateDequantizationTable(ref decoder.QuantizationTables[qtIndex]);
postProcessor->subSamplingDivisors = component.SubSamplingDivisors;
}
public void QuantizeAndTransform(ref Block8x8 sourceBlock)
public void ProcessBlockColorsInto(
ref Block8x8 sourceBlock,
BufferArea<float> destArea)
{
this.data.SourceBlock = sourceBlock.AsFloatBlock();
Block8x8F* b = this.pointers.SourceBlock;
Block8x8F.DequantizeBlock(b, this.pointers.QuantiazationTable, this.pointers.Unzig);
// Dequantize:
b->MultiplyInplace(ref this.data.DequantiazationTable);
FastFloatingPointDCT.TransformIDCT(ref *b, ref this.data.WorkspaceBlock1, ref this.data.WorkspaceBlock2);
}
public void ProcessBlockColorsInto(
ref Block8x8 sourceBlock,
BufferArea<float> destArea)
{
this.QuantizeAndTransform(ref sourceBlock);
this.data.WorkspaceBlock1.NormalizeColorsInplace();
@ -89,12 +85,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
/// <summary>
/// The quantization table as <see cref="Block8x8F"/>
/// </summary>
public Block8x8F QuantiazationTable;
public Block8x8F DequantiazationTable;
/// <summary>
/// The jpeg unzig data
/// </summary>
public UnzigData Unzig;
public ZigZag Unzig;
/// <summary>
/// Creates and initializes a new <see cref="ComputationData"/> instance
@ -103,7 +99,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
public static ComputationData Create()
{
var data = default(ComputationData);
data.Unzig = UnzigData.Create();
data.Unzig = ZigZag.CreateUnzigTable();
return data;
}
}
@ -129,9 +125,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
public Block8x8F* WorkspaceBlock2;
/// <summary>
/// Pointer to <see cref="ComputationData.QuantiazationTable"/>
/// Pointer to <see cref="ComputationData.DequantiazationTable"/>
/// </summary>
public Block8x8F* QuantiazationTable;
public Block8x8F* DequantiazationTable;
/// <summary>
/// Pointer to <see cref="ComputationData.Unzig"/> as int*
@ -147,7 +143,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
this.SourceBlock = &dataPtr->SourceBlock;
this.WorkspaceBlock1 = &dataPtr->WorkspaceBlock1;
this.WorkspaceBlock2 = &dataPtr->WorkspaceBlock2;
this.QuantiazationTable = &dataPtr->QuantiazationTable;
this.DequantiazationTable = &dataPtr->DequantiazationTable;
this.Unzig = dataPtr->Unzig.Data;
}
}

23
src/ImageSharp/Formats/Jpeg/Common/UnzigData.cs → src/ImageSharp/Formats/Jpeg/Common/ZigZag.cs

@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
/// unzig[3] is the column and row of the fourth element in zigzag order. The
/// value is 16, which means first column (16%8 == 0) and third row (16/8 == 2).
/// </summary>
internal unsafe struct UnzigData
internal unsafe struct ZigZag
{
/// <summary>
/// Copy of <see cref="Unzig"/> in a value type
@ -32,15 +32,30 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
};
/// <summary>
/// Creates and fills an instance of <see cref="UnzigData"/> with Jpeg unzig indices
/// Creates and fills an instance of <see cref="ZigZag"/> with Jpeg unzig indices
/// </summary>
/// <returns>The new instance</returns>
public static UnzigData Create()
public static ZigZag CreateUnzigTable()
{
UnzigData result = default(UnzigData);
ZigZag result = default(ZigZag);
int* unzigPtr = result.Data;
Marshal.Copy(Unzig, 0, (IntPtr)unzigPtr, 64);
return result;
}
/// <summary>
/// Apply Zigging to the given quantization table, so it will be sufficient to multiply blocks for dequantizing them.
/// </summary>
public static Block8x8F CreateDequantizationTable(ref Block8x8F qt)
{
Block8x8F result = default(Block8x8F);
for (int i = 0; i < 64; i++)
{
result[Unzig[i]] = qt[i];
}
return result;
}
}
}

4
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegScanDecoder.ComputationData.cs

@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// <summary>
/// The jpeg unzig data
/// </summary>
public UnzigData Unzig;
public ZigZag Unzig;
/// <summary>
/// The buffer storing the <see cref="OrigComponentScan"/>-s for each component
@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
public static ComputationData Create()
{
ComputationData data = default(ComputationData);
data.Unzig = UnzigData.Create();
data.Unzig = ZigZag.CreateUnzigTable();
return data;
}
}

4
src/ImageSharp/Formats/Jpeg/GolangPort/JpegEncoderCore.cs

@ -455,7 +455,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
Block8x8F onStackLuminanceQuantTable = this.luminanceQuantTable;
Block8x8F onStackChrominanceQuantTable = this.chrominanceQuantTable;
UnzigData unzig = UnzigData.Create();
ZigZag unzig = ZigZag.CreateUnzigTable();
// ReSharper disable once InconsistentNaming
int prevDCY = 0, prevDCCb = 0, prevDCCr = 0;
@ -912,7 +912,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
Block8x8F onStackLuminanceQuantTable = this.luminanceQuantTable;
Block8x8F onStackChrominanceQuantTable = this.chrominanceQuantTable;
UnzigData unzig = UnzigData.Create();
ZigZag unzig = ZigZag.CreateUnzigTable();
// ReSharper disable once InconsistentNaming
int prevDCY = 0, prevDCCb = 0, prevDCCr = 0;

26
tests/ImageSharp.Tests/Formats/Jpg/Block8x8FTests.cs

@ -309,7 +309,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
var qt = new Block8x8F();
qt.LoadFrom(Create8x8RoundedRandomFloatData(-2000, 2000, seed));
var unzig = UnzigData.Create();
var unzig = ZigZag.CreateUnzigTable();
int* expectedResults = stackalloc int[Block8x8F.Size];
ReferenceImplementations.UnZigDivRoundRational(&block, expectedResults, &qt, unzig.Data);
@ -396,7 +396,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
Block8x8F original = CreateRandomFloatBlock(-500, 500, seed);
Block8x8F qt = CreateRandomFloatBlock(0, 10, seed + 42);
var unzig = UnzigData.Create();
var unzig = ZigZag.CreateUnzigTable();
Block8x8F expected = original;
Block8x8F actual = original;
@ -406,5 +406,27 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
this.CompareBlocks(expected, actual, 0);
}
[Theory]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
public unsafe void ZigZag_CreateDequantizationTable_MultiplicationShouldQuantize(int seed)
{
Block8x8F original = CreateRandomFloatBlock(-500, 500, seed);
Block8x8F qt = CreateRandomFloatBlock(0, 10, seed + 42);
var unzig = ZigZag.CreateUnzigTable();
Block8x8F zigQt = ZigZag.CreateDequantizationTable(ref qt);
Block8x8F expected = original;
Block8x8F actual = original;
ReferenceImplementations.DequantizeBlock(&expected, &qt, unzig.Data);
actual.MultiplyInplace(ref zigQt);
this.CompareBlocks(expected, actual, 0);
}
}
}

4
tests/ImageSharp.Tests/Formats/Jpg/JpegProfilingBenchmarks.cs

@ -41,8 +41,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
this.DecodeJpegBenchmarkImpl(fileName, new OrigJpegDecoder());
}
[Theory] // Benchmark, enable manually
[MemberData(nameof(DecodeJpegData))]
//[Theory] // Benchmark, enable manually
//[MemberData(nameof(DecodeJpegData))]
public void DecodeJpeg_PdfJs(string fileName)
{
this.DecodeJpegBenchmarkImpl(fileName, new PdfJsJpegDecoder());

2
tests/ImageSharp.Tests/Formats/Jpg/Utils/ReferenceImplementations.cs

@ -114,7 +114,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils
/// <param name="src">The input block</param>
/// <param name="dest">The destination block of integers</param>
/// <param name="qt">The quantization table</param>
/// <param name="unzigPtr">Pointer to <see cref="UnzigData.Data"/> </param>
/// <param name="unzigPtr">Pointer to <see cref="ZigZag.Data"/> </param>
public static unsafe void UnZigDivRoundRational(Block8x8F* src, int* dest, Block8x8F* qt, int* unzigPtr)
{
float* s = (float*)src;

Loading…
Cancel
Save