Browse Source

Optimize several transforms

pull/1567/head
James Jackson-South 9 months ago
parent
commit
c5cc792304
  1. 8
      src/ImageSharp/ColorProfiles/CieXyz.cs
  2. 21
      src/ImageSharp/ColorProfiles/ColorConversionOptions.cs
  3. 2
      src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsIcc.cs
  4. 2
      src/ImageSharp/ColorProfiles/Icc/Calculators/ColorTrcCalculator.cs
  5. 17
      src/ImageSharp/ColorProfiles/Lms.cs
  6. 6
      src/ImageSharp/ColorProfiles/Rgb.cs
  7. 12
      src/ImageSharp/ColorProfiles/VonKriesChromaticAdaptation.cs
  8. 20
      src/ImageSharp/ColorProfiles/YCbCr.cs
  9. 3
      src/ImageSharp/ColorProfiles/YcbCrMatrix.cs
  10. 22
      src/ImageSharp/ColorProfiles/YccK.cs

8
src/ImageSharp/ColorProfiles/CieXyz.cs

@ -80,12 +80,8 @@ public readonly struct CieXyz : IProfileConnectingSpace<CieXyz, CieXyz>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(CieXyz left, CieXyz right) => !left.Equals(right);
/// <summary>
/// Returns a new <see cref="Vector3"/> representing this instance.
/// </summary>
/// <returns>The <see cref="Vector3"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector3 ToVector3() => new(this.X, this.Y, this.Z);
internal Vector3 ToVector3() => new(this.X, this.Y, this.Z);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Vector4 ToVector4()
@ -203,5 +199,5 @@ public readonly struct CieXyz : IProfileConnectingSpace<CieXyz, CieXyz>
public bool Equals(CieXyz other)
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
private Vector3 AsVector3Unsafe() => Unsafe.As<CieXyz, Vector3>(ref Unsafe.AsRef(in this));
internal Vector3 AsVector3Unsafe() => Unsafe.As<CieXyz, Vector3>(ref Unsafe.AsRef(in this));
}

21
src/ImageSharp/ColorProfiles/ColorConversionOptions.cs

@ -14,11 +14,16 @@ namespace SixLabors.ImageSharp.ColorProfiles;
public class ColorConversionOptions
{
private Matrix4x4 adaptationMatrix;
private YCbCrMatrix yCbCrMatrix;
/// <summary>
/// Initializes a new instance of the <see cref="ColorConversionOptions"/> class.
/// </summary>
public ColorConversionOptions() => this.AdaptationMatrix = KnownChromaticAdaptationMatrices.Bradford;
public ColorConversionOptions()
{
this.AdaptationMatrix = KnownChromaticAdaptationMatrices.Bradford;
this.YCbCrMatrix = KnownYCbCrMatrices.BT601;
}
/// <summary>
/// Gets the memory allocator.
@ -48,7 +53,15 @@ public class ColorConversionOptions
/// <summary>
/// Gets the YCbCr matrix to used to perform conversions from/to RGB.
/// </summary>
public YCbCrMatrix YCbCrMatrix { get; init; } = KnownYCbCrMatrices.BT601;
public YCbCrMatrix YCbCrMatrix
{
get => this.yCbCrMatrix;
init
{
this.yCbCrMatrix = value;
this.TransposedYCbCrMatrix = value.Transpose();
}
}
/// <summary>
/// Gets the source ICC profile.
@ -70,10 +83,12 @@ public class ColorConversionOptions
init
{
this.adaptationMatrix = value;
Matrix4x4.Invert(value, out Matrix4x4 inverted);
_ = Matrix4x4.Invert(value, out Matrix4x4 inverted);
this.InverseAdaptationMatrix = inverted;
}
}
internal YCbCrMatrix TransposedYCbCrMatrix { get; private set; }
internal Matrix4x4 InverseAdaptationMatrix { get; private set; }
}

2
src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsIcc.cs

@ -363,7 +363,7 @@ internal static class ColorProfileConverterExtensionsIcc
if (targetParams.HasNoPerceptualHandling ||
(oneProfileHasV2PerceptualAdjustment && targetParams.HasV2PerceptualHandling))
{
Vector3 vector = AdjustPcsToV2BlackPoint(xyz.ToVector3());
Vector3 vector = AdjustPcsToV2BlackPoint(xyz.AsVector3Unsafe());
// when using XYZ PCS, negative values are clipped after PCS adjustment (in DemoIccMAX)
if (targetParams.PcsType == IccColorSpaceType.CieXyz)

2
src/ImageSharp/ColorProfiles/Icc/Calculators/ColorTrcCalculator.cs

@ -58,7 +58,7 @@ internal class ColorTrcCalculator : IVector4Calculator
// when data to PCS, upstream process provides scaled XYZ
// but input to calculator is descaled XYZ
// (see DemoMaxICC IccCmm.cpp : CIccXformMatrixTRC::Apply)
xyz = new(CieXyz.FromScaledVector4(xyz).ToVector3(), 1);
xyz = new(CieXyz.FromScaledVector4(xyz).AsVector3Unsafe(), 1);
return this.curveCalculator.Calculate(xyz);
}
}

17
src/ImageSharp/ColorProfiles/Lms.cs

@ -82,13 +82,6 @@ public readonly struct Lms : IColorProfile<Lms, CieXyz>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Lms left, Lms right) => !left.Equals(right);
/// <summary>
/// Returns a new <see cref="Vector3"/> representing this instance.
/// </summary>
/// <returns>The <see cref="Vector3"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector3 ToVector3() => new(this.L, this.M, this.S);
/// <inheritdoc/>
public Vector4 ToScaledVector4()
{
@ -134,10 +127,7 @@ public readonly struct Lms : IColorProfile<Lms, CieXyz>
/// <inheritdoc/>
public static Lms FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source)
{
Vector3 vector = Vector3.Transform(source.ToVector3(), options.AdaptationMatrix);
return new Lms(vector);
}
=> new(Vector3.Transform(source.AsVector3Unsafe(), options.AdaptationMatrix));
/// <inheritdoc/>
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieXyz> source, Span<Lms> destination)
@ -153,10 +143,7 @@ public readonly struct Lms : IColorProfile<Lms, CieXyz>
/// <inheritdoc/>
public CieXyz ToProfileConnectingSpace(ColorConversionOptions options)
{
Vector3 vector = Vector3.Transform(this.ToVector3(), options.InverseAdaptationMatrix);
return new CieXyz(vector);
}
=> new(Vector3.Transform(this.AsVector3Unsafe(), options.InverseAdaptationMatrix));
/// <inheritdoc/>
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<Lms> source, Span<CieXyz> destination)

6
src/ImageSharp/ColorProfiles/Rgb.cs

@ -128,7 +128,7 @@ public readonly struct Rgb : IProfileConnectingSpace<Rgb, CieXyz>
public static Rgb FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source)
{
// Convert to linear rgb then compress.
Rgb linear = new(Vector3.Transform(source.ToVector3(), GetCieXyzToRgbMatrix(options.TargetRgbWorkingSpace)));
Rgb linear = new(Vector3.Transform(source.AsVector3Unsafe(), GetCieXyzToRgbMatrix(options.TargetRgbWorkingSpace)));
return FromScaledVector4(options.TargetRgbWorkingSpace.Compress(linear.ToScaledVector4()));
}
@ -141,7 +141,7 @@ public readonly struct Rgb : IProfileConnectingSpace<Rgb, CieXyz>
for (int i = 0; i < source.Length; i++)
{
// Convert to linear rgb then compress.
Rgb linear = new(Vector3.Transform(source[i].ToVector3(), matrix));
Rgb linear = new(Vector3.Transform(source[i].AsVector3Unsafe(), matrix));
Vector4 nonlinear = options.TargetRgbWorkingSpace.Compress(linear.ToScaledVector4());
destination[i] = FromScaledVector4(nonlinear);
}
@ -271,7 +271,7 @@ public readonly struct Rgb : IProfileConnectingSpace<Rgb, CieXyz>
Matrix4x4.Invert(xyzMatrix, out Matrix4x4 inverseXyzMatrix);
Vector3 vector = Vector3.Transform(workingSpace.WhitePoint.ToVector3(), inverseXyzMatrix);
Vector3 vector = Vector3.Transform(workingSpace.WhitePoint.AsVector3Unsafe(), inverseXyzMatrix);
// Use transposed Rows/Columns
return new Matrix4x4

12
src/ImageSharp/ColorProfiles/VonKriesChromaticAdaptation.cs

@ -34,9 +34,9 @@ public static class VonKriesChromaticAdaptation
return new(source.X, source.Y, source.Z);
}
Vector3 sourceColorLms = Vector3.Transform(source.ToVector3(), matrix);
Vector3 sourceWhitePointLms = Vector3.Transform(from.ToVector3(), matrix);
Vector3 targetWhitePointLms = Vector3.Transform(to.ToVector3(), matrix);
Vector3 sourceColorLms = Vector3.Transform(source.AsVector3Unsafe(), matrix);
Vector3 sourceWhitePointLms = Vector3.Transform(from.AsVector3Unsafe(), matrix);
Vector3 targetWhitePointLms = Vector3.Transform(to.AsVector3Unsafe(), matrix);
Vector3 vector = targetWhitePointLms / sourceWhitePointLms;
Vector3 targetColorLms = Vector3.Multiply(vector, sourceColorLms);
@ -76,8 +76,8 @@ public static class VonKriesChromaticAdaptation
ref CieXyz sourceBase = ref MemoryMarshal.GetReference(source);
ref CieXyz destinationBase = ref MemoryMarshal.GetReference(destination);
Vector3 sourceWhitePointLms = Vector3.Transform(from.ToVector3(), matrix);
Vector3 targetWhitePointLms = Vector3.Transform(to.ToVector3(), matrix);
Vector3 sourceWhitePointLms = Vector3.Transform(from.AsVector3Unsafe(), matrix);
Vector3 targetWhitePointLms = Vector3.Transform(to.AsVector3Unsafe(), matrix);
Vector3 vector = targetWhitePointLms / sourceWhitePointLms;
@ -86,7 +86,7 @@ public static class VonKriesChromaticAdaptation
ref CieXyz sp = ref Unsafe.Add(ref sourceBase, i);
ref CieXyz dp = ref Unsafe.Add(ref destinationBase, i);
Vector3 sourceColorLms = Vector3.Transform(sp.ToVector3(), matrix);
Vector3 sourceColorLms = Vector3.Transform(sp.AsVector3Unsafe(), matrix);
Vector3 targetColorLms = Vector3.Multiply(vector, sourceColorLms);
dp = new CieXyz(Vector3.Transform(targetColorLms, inverseMatrix));

20
src/ImageSharp/ColorProfiles/YCbCr.cs

@ -130,14 +130,10 @@ public readonly struct YCbCr : IColorProfile<YCbCr, Rgb>
public static YCbCr FromProfileConnectingSpace(ColorConversionOptions options, in Rgb source)
{
Vector3 rgb = source.AsVector3Unsafe();
Matrix4x4 m = options.YCbCrMatrix.Forward;
Vector3 offset = options.YCbCrMatrix.Offset;
Matrix4x4 m = options.TransposedYCbCrMatrix.Forward;
Vector3 offset = options.TransposedYCbCrMatrix.Offset;
float y = Vector3.Dot(rgb, new Vector3(m.M11, m.M12, m.M13));
float cb = Vector3.Dot(rgb, new Vector3(m.M21, m.M22, m.M23));
float cr = Vector3.Dot(rgb, new Vector3(m.M31, m.M32, m.M33));
return new YCbCr(new Vector3(y, cb, cr) + offset, true);
return new YCbCr(Vector3.Transform(rgb, m) + offset, true);
}
/// <inheritdoc/>
@ -156,15 +152,11 @@ public readonly struct YCbCr : IColorProfile<YCbCr, Rgb>
/// <inheritdoc/>
public Rgb ToProfileConnectingSpace(ColorConversionOptions options)
{
Matrix4x4 m = options.YCbCrMatrix.Inverse;
Vector3 offset = options.YCbCrMatrix.Offset;
Matrix4x4 m = options.TransposedYCbCrMatrix.Inverse;
Vector3 offset = options.TransposedYCbCrMatrix.Offset;
Vector3 normalized = this.AsVector3Unsafe() - offset;
float r = Vector3.Dot(normalized, new Vector3(m.M11, m.M12, m.M13));
float g = Vector3.Dot(normalized, new Vector3(m.M21, m.M22, m.M23));
float b = Vector3.Dot(normalized, new Vector3(m.M31, m.M32, m.M33));
return Rgb.FromScaledVector3(new Vector3(r, g, b));
return Rgb.FromScaledVector3(Vector3.Transform(normalized, m));
}
/// <inheritdoc/>

3
src/ImageSharp/ColorProfiles/YcbCrMatrix.cs

@ -55,4 +55,7 @@ public readonly struct YCbCrMatrix
/// Gets the chrominance offset vector to apply during encoding (add) or decoding (subtract).
/// </summary>
public Vector3 Offset { get; }
internal YCbCrMatrix Transpose()
=> new(Matrix4x4.Transpose(this.Forward), Matrix4x4.Transpose(this.Inverse), this.Offset);
}

22
src/ImageSharp/ColorProfiles/YccK.cs

@ -131,23 +131,18 @@ public readonly struct YccK : IColorProfile<YccK, Rgb>
/// <inheritdoc/>
public Rgb ToProfileConnectingSpace(ColorConversionOptions options)
{
Matrix4x4 m = options.YCbCrMatrix.Inverse;
Vector3 offset = options.YCbCrMatrix.Offset;
Matrix4x4 m = options.TransposedYCbCrMatrix.Inverse;
Vector3 offset = options.TransposedYCbCrMatrix.Offset;
Vector3 normalized = this.AsVector3Unsafe() - offset;
float r = Vector3.Dot(normalized, new Vector3(m.M11, m.M12, m.M13));
float g = Vector3.Dot(normalized, new Vector3(m.M21, m.M22, m.M23));
float b = Vector3.Dot(normalized, new Vector3(m.M31, m.M32, m.M33));
Vector3 rgb = new Vector3(r, g, b) * (1F - this.K);
return Rgb.FromScaledVector3(rgb);
return Rgb.FromScaledVector3(Vector3.Transform(normalized, m) * (1F - this.K));
}
/// <inheritdoc/>
public static YccK FromProfileConnectingSpace(ColorConversionOptions options, in Rgb source)
{
Matrix4x4 m = options.YCbCrMatrix.Forward;
Vector3 offset = options.YCbCrMatrix.Offset;
Matrix4x4 m = options.TransposedYCbCrMatrix.Forward;
Vector3 offset = options.TransposedYCbCrMatrix.Offset;
Vector3 rgb = source.AsVector3Unsafe();
float k = 1F - MathF.Max(rgb.X, MathF.Max(rgb.Y, rgb.Z));
@ -158,12 +153,7 @@ public readonly struct YccK : IColorProfile<YccK, Rgb>
}
rgb /= 1F - k;
float y = Vector3.Dot(rgb, new Vector3(m.M11, m.M12, m.M13));
float cb = Vector3.Dot(rgb, new Vector3(m.M21, m.M22, m.M23));
float cr = Vector3.Dot(rgb, new Vector3(m.M31, m.M32, m.M33));
return new YccK(new Vector4(y, cb, cr, k) + new Vector4(offset, 0F));
return new YccK(new Vector4(Vector3.Transform(rgb, m), k) + new Vector4(offset, 0F));
}
/// <inheritdoc/>

Loading…
Cancel
Save