mirror of https://github.com/SixLabors/ImageSharp
36 changed files with 941 additions and 56 deletions
@ -0,0 +1,229 @@ |
|||
// <copyright file="CieLuv.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.ColorSpaces |
|||
{ |
|||
using System; |
|||
using System.ComponentModel; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
/// <summary>
|
|||
/// The CIE 1976 (L*, u*, v*) color space, commonly known by its abbreviation CIELUV, is a color space adopted by the International
|
|||
/// Commission on Illumination (CIE) in 1976, as a simple-to-compute transformation of the 1931 CIE XYZ color space, but which
|
|||
/// attempted perceptual uniformity
|
|||
/// <see href="https://en.wikipedia.org/wiki/CIELUV"/>
|
|||
/// </summary>
|
|||
public struct CieLuv : IColorVector, IEquatable<CieLuv>, IAlmostEquatable<CieLuv, float> |
|||
{ |
|||
/// <summary>
|
|||
/// D65 standard illuminant.
|
|||
/// Used when reference white is not specified explicitly.
|
|||
/// </summary>
|
|||
public static readonly CieXyz DefaultWhitePoint = Illuminants.D65; |
|||
|
|||
/// <summary>
|
|||
/// Represents a <see cref="CieLuv"/> that has L, U, and V values set to zero.
|
|||
/// </summary>
|
|||
public static readonly CieLuv Empty = default(CieLuv); |
|||
|
|||
/// <summary>
|
|||
/// The backing vector for SIMD support.
|
|||
/// </summary>
|
|||
private readonly Vector3 backingVector; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="CieLuv"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="l">The lightness dimension.</param>
|
|||
/// <param name="u">The blue-yellow chromaticity coordinate of the given whitepoint.</param>
|
|||
/// <param name="v">The red-green chromaticity coordinate of the given whitepoint.</param>
|
|||
/// <remarks>Uses <see cref="DefaultWhitePoint"/> as white point.</remarks>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public CieLuv(float l, float u, float v) |
|||
: this(new Vector3(l, u, v), DefaultWhitePoint) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="CieLuv"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="l">The lightness dimension.</param>
|
|||
/// <param name="u">The blue-yellow chromaticity coordinate of the given whitepoint.</param>
|
|||
/// <param name="v">The red-green chromaticity coordinate of the given whitepoint.</param>
|
|||
/// <param name="whitePoint">The reference white point. <see cref="Illuminants"/></param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public CieLuv(float l, float u, float v, CieXyz whitePoint) |
|||
: this(new Vector3(l, u, v), whitePoint) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="CieLuv"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="vector">The vector representing the l, u, v components.</param>
|
|||
/// <remarks>Uses <see cref="DefaultWhitePoint"/> as white point.</remarks>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public CieLuv(Vector3 vector) |
|||
: this(vector, DefaultWhitePoint) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="CieLuv"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="vector">The vector representing the l, u, v components.</param>
|
|||
/// <param name="whitePoint">The reference white point. <see cref="Illuminants"/></param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public CieLuv(Vector3 vector, CieXyz whitePoint) |
|||
: this() |
|||
{ |
|||
this.backingVector = vector; |
|||
this.WhitePoint = whitePoint; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the reference white point of this color
|
|||
/// </summary>
|
|||
public CieXyz WhitePoint |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
get; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the lightness dimension
|
|||
/// <remarks>A value usually ranging between 0 and 100.</remarks>
|
|||
/// </summary>
|
|||
public float L |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
get => this.backingVector.X; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the blue-yellow chromaticity coordinate of the given whitepoint.
|
|||
/// <remarks>A value usually ranging between -100 and 100.</remarks>
|
|||
/// </summary>
|
|||
public float U |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
get => this.backingVector.Y; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the red-green chromaticity coordinate of the given whitepoint.
|
|||
/// <remarks>A value usually ranging between -100 and 100.</remarks>
|
|||
/// </summary>
|
|||
public float V |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
get => this.backingVector.Z; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether this <see cref="CieLuv"/> is empty.
|
|||
/// </summary>
|
|||
[EditorBrowsable(EditorBrowsableState.Never)] |
|||
public bool IsEmpty => this.Equals(Empty); |
|||
|
|||
/// <inheritdoc />
|
|||
public Vector3 Vector |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
get => this.backingVector; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="CieLuv"/> objects for equality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="CieLuv"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="CieLuv"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static bool operator ==(CieLuv left, CieLuv right) |
|||
{ |
|||
return left.Equals(right); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Compares two <see cref="CieLuv"/> objects for inequality.
|
|||
/// </summary>
|
|||
/// <param name="left">
|
|||
/// The <see cref="CieLuv"/> on the left side of the operand.
|
|||
/// </param>
|
|||
/// <param name="right">
|
|||
/// The <see cref="CieLuv"/> on the right side of the operand.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
|
|||
/// </returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static bool operator !=(CieLuv left, CieLuv right) |
|||
{ |
|||
return !left.Equals(right); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override int GetHashCode() |
|||
{ |
|||
unchecked |
|||
{ |
|||
int hashCode = this.WhitePoint.GetHashCode(); |
|||
hashCode = (hashCode * 397) ^ this.backingVector.GetHashCode(); |
|||
return hashCode; |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override string ToString() |
|||
{ |
|||
if (this.IsEmpty) |
|||
{ |
|||
return "CieLuv [ Empty ]"; |
|||
} |
|||
|
|||
return $"CieLuv [ L={this.L:#0.##}, U={this.U:#0.##}, V={this.V:#0.##} ]"; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public override bool Equals(object obj) |
|||
{ |
|||
if (obj is CieLuv) |
|||
{ |
|||
return this.Equals((CieLuv)obj); |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public bool Equals(CieLuv other) |
|||
{ |
|||
return this.backingVector.Equals(other.backingVector) |
|||
&& this.WhitePoint.Equals(other.WhitePoint); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public bool AlmostEquals(CieLuv other, float precision) |
|||
{ |
|||
Vector3 result = Vector3.Abs(this.backingVector - other.backingVector); |
|||
|
|||
return this.WhitePoint.Equals(other.WhitePoint) |
|||
&& result.X <= precision |
|||
&& result.Y <= precision |
|||
&& result.Z <= precision; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,178 @@ |
|||
// <copyright file="ColorSpaceConverter.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.ColorSpaces.Conversion |
|||
{ |
|||
using ImageSharp.ColorSpaces; |
|||
using ImageSharp.ColorSpaces.Conversion.Implementation.CieLuv; |
|||
|
|||
/// <summary>
|
|||
/// Converts between color spaces ensuring that the color is adapted using chromatic adaptation.
|
|||
/// </summary>
|
|||
public partial class ColorSpaceConverter |
|||
{ |
|||
/// <summary>
|
|||
/// Converts a <see cref="CieLab"/> into a <see cref="CieLuv"/>
|
|||
/// </summary>
|
|||
/// <param name="color">The color to convert.</param>
|
|||
/// <returns>The <see cref="CieLuv"/></returns>
|
|||
public CieLuv ToCieLuv(CieLab color) |
|||
{ |
|||
Guard.NotNull(color, nameof(color)); |
|||
|
|||
CieXyz xyzColor = this.ToCieXyz(color); |
|||
return this.ToCieLuv(xyzColor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="CieLch"/> into a <see cref="CieLuv"/>
|
|||
/// </summary>
|
|||
/// <param name="color">The color to convert.</param>
|
|||
/// <returns>The <see cref="CieLuv"/></returns>
|
|||
public CieLuv ToCieLuv(CieLch color) |
|||
{ |
|||
Guard.NotNull(color, nameof(color)); |
|||
|
|||
CieXyz xyzColor = this.ToCieXyz(color); |
|||
return this.ToCieLuv(xyzColor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="CieXyy"/> into a <see cref="CieLuv"/>
|
|||
/// </summary>
|
|||
/// <param name="color">The color to convert.</param>
|
|||
/// <returns>The <see cref="CieLuv"/></returns>
|
|||
public CieLuv ToCieLuv(CieXyy color) |
|||
{ |
|||
Guard.NotNull(color, nameof(color)); |
|||
|
|||
CieXyz xyzColor = this.ToCieXyz(color); |
|||
return this.ToCieLuv(xyzColor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="CieXyz"/> into a <see cref="CieLuv"/>
|
|||
/// </summary>
|
|||
/// <param name="color">The color to convert.</param>
|
|||
/// <returns>The <see cref="CieLuv"/></returns>
|
|||
public CieLuv ToCieLuv(CieXyz color) |
|||
{ |
|||
Guard.NotNull(color, nameof(color)); |
|||
|
|||
// Adaptation
|
|||
CieXyz adapted = !this.WhitePoint.Equals(this.TargetLabWhitePoint) && this.IsChromaticAdaptationPerformed |
|||
? this.ChromaticAdaptation.Transform(color, this.WhitePoint, this.TargetLabWhitePoint) |
|||
: color; |
|||
|
|||
// Conversion
|
|||
CieXyzToCieLuvConverter converter = new CieXyzToCieLuvConverter(this.TargetLuvWhitePoint); |
|||
return converter.Convert(adapted); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="Cmyk"/> into a <see cref="CieLuv"/>
|
|||
/// </summary>
|
|||
/// <param name="color">The color to convert.</param>
|
|||
/// <returns>The <see cref="CieLuv"/></returns>
|
|||
public CieLuv ToCieLuv(Cmyk color) |
|||
{ |
|||
Guard.NotNull(color, nameof(color)); |
|||
|
|||
CieXyz xyzColor = this.ToCieXyz(color); |
|||
return this.ToCieLuv(xyzColor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="Hsl"/> into a <see cref="CieLuv"/>
|
|||
/// </summary>
|
|||
/// <param name="color">The color to convert.</param>
|
|||
/// <returns>The <see cref="CieLuv"/></returns>
|
|||
public CieLuv ToCieLuv(Hsl color) |
|||
{ |
|||
Guard.NotNull(color, nameof(color)); |
|||
|
|||
CieXyz xyzColor = this.ToCieXyz(color); |
|||
return this.ToCieLuv(xyzColor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="Hsv"/> into a <see cref="CieLuv"/>
|
|||
/// </summary>
|
|||
/// <param name="color">The color to convert.</param>
|
|||
/// <returns>The <see cref="CieLuv"/></returns>
|
|||
public CieLuv ToCieLuv(Hsv color) |
|||
{ |
|||
Guard.NotNull(color, nameof(color)); |
|||
|
|||
CieXyz xyzColor = this.ToCieXyz(color); |
|||
return this.ToCieLuv(xyzColor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="HunterLab"/> into a <see cref="CieLuv"/>
|
|||
/// </summary>
|
|||
/// <param name="color">The color to convert.</param>
|
|||
/// <returns>The <see cref="CieLuv"/></returns>
|
|||
public CieLuv ToCieLuv(HunterLab color) |
|||
{ |
|||
Guard.NotNull(color, nameof(color)); |
|||
|
|||
CieXyz xyzColor = this.ToCieXyz(color); |
|||
return this.ToCieLuv(xyzColor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="Lms"/> into a <see cref="CieLuv"/>
|
|||
/// </summary>
|
|||
/// <param name="color">The color to convert.</param>
|
|||
/// <returns>The <see cref="CieLuv"/></returns>
|
|||
public CieLuv ToCieLuv(Lms color) |
|||
{ |
|||
Guard.NotNull(color, nameof(color)); |
|||
|
|||
CieXyz xyzColor = this.ToCieXyz(color); |
|||
return this.ToCieLuv(xyzColor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="LinearRgb"/> into a <see cref="CieLuv"/>
|
|||
/// </summary>
|
|||
/// <param name="color">The color to convert.</param>
|
|||
/// <returns>The <see cref="CieLuv"/></returns>
|
|||
public CieLuv ToCieLuv(LinearRgb color) |
|||
{ |
|||
Guard.NotNull(color, nameof(color)); |
|||
|
|||
CieXyz xyzColor = this.ToCieXyz(color); |
|||
return this.ToCieLuv(xyzColor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="Rgb"/> into a <see cref="CieLuv"/>
|
|||
/// </summary>
|
|||
/// <param name="color">The color to convert.</param>
|
|||
/// <returns>The <see cref="CieLuv"/></returns>
|
|||
public CieLuv ToCieLuv(Rgb color) |
|||
{ |
|||
Guard.NotNull(color, nameof(color)); |
|||
|
|||
CieXyz xyzColor = this.ToCieXyz(color); |
|||
return this.ToCieLuv(xyzColor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a <see cref="YCbCr"/> into a <see cref="CieLuv"/>
|
|||
/// </summary>
|
|||
/// <param name="color">The color to convert.</param>
|
|||
/// <returns>The <see cref="CieLuv"/></returns>
|
|||
public CieLuv ToCieLuv(YCbCr color) |
|||
{ |
|||
Guard.NotNull(color, nameof(color)); |
|||
|
|||
CieXyz xyzColor = this.ToCieXyz(color); |
|||
return this.ToCieLuv(xyzColor); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,80 @@ |
|||
// <copyright file="CieLuvToCieXyzConverter.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.ColorSpaces.Conversion.Implementation.CieLuv |
|||
{ |
|||
using System.Runtime.CompilerServices; |
|||
using ImageSharp.ColorSpaces; |
|||
|
|||
/// <summary>
|
|||
/// Converts from <see cref="CieLuv"/> to <see cref="CieXyz"/>.
|
|||
/// </summary>
|
|||
internal class CieLuvToCieXyzConverter : IColorConversion<CieLuv, CieXyz> |
|||
{ |
|||
/// <inheritdoc/>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public CieXyz Convert(CieLuv input) |
|||
{ |
|||
DebugGuard.NotNull(input, nameof(input)); |
|||
|
|||
// Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_Luv_to_XYZ.html
|
|||
float l = input.L, u = input.U, v = input.V; |
|||
|
|||
float u0 = ComputeU0(input.WhitePoint); |
|||
float v0 = ComputeV0(input.WhitePoint); |
|||
|
|||
float y = l > CieConstants.Kappa * CieConstants.Epsilon |
|||
? MathF.Pow((l + 16) / 116, 3) |
|||
: l / CieConstants.Kappa; |
|||
|
|||
float a = ((52 * l / (u + (13 * l * u0))) - 1) / 3; |
|||
float b = -5 * y; |
|||
float c = -0.3333333F; |
|||
float d = y * ((39 * l / (v + (13 * l * v0))) - 5); |
|||
|
|||
float x = (d - b) / (a - c); |
|||
float z = (x * a) + b; |
|||
|
|||
if (float.IsNaN(x) || x < 0) |
|||
{ |
|||
x = 0; |
|||
} |
|||
|
|||
if (float.IsNaN(y) || y < 0) |
|||
{ |
|||
y = 0; |
|||
} |
|||
|
|||
if (float.IsNaN(z) || z < 0) |
|||
{ |
|||
z = 0; |
|||
} |
|||
|
|||
return new CieXyz(x, y, z); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Calculates the blue-yellow chromacity based on the given whitepoint.
|
|||
/// </summary>
|
|||
/// <param name="input">The whitepoint</param>
|
|||
/// <returns>The <see cref="float"/></returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static float ComputeU0(CieXyz input) |
|||
{ |
|||
return (4 * input.X) / (input.X + (15 * input.Y) + (3 * input.Z)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Calculates the red-green chromacity based on the given whitepoint.
|
|||
/// </summary>
|
|||
/// <param name="input">The whitepoint</param>
|
|||
/// <returns>The <see cref="float"/></returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static float ComputeV0(CieXyz input) |
|||
{ |
|||
return (9 * input.Y) / (input.X + (15 * input.Y) + (3 * input.Z)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,102 @@ |
|||
// <copyright file="CieXyzToCieLuvConverter.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.ColorSpaces.Conversion.Implementation.CieLuv |
|||
{ |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
using ImageSharp.ColorSpaces; |
|||
|
|||
/// <summary>
|
|||
/// Converts from <see cref="CieXyz"/> to <see cref="CieLuv"/>.
|
|||
/// </summary>
|
|||
internal class CieXyzToCieLuvConverter : IColorConversion<CieXyz, CieLuv> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="CieXyzToCieLuvConverter"/> class.
|
|||
/// </summary>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public CieXyzToCieLuvConverter() |
|||
: this(CieLuv.DefaultWhitePoint) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="CieXyzToCieLuvConverter"/> class.
|
|||
/// </summary>
|
|||
/// <param name="luvWhitePoint">The target reference luv white point</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public CieXyzToCieLuvConverter(CieXyz luvWhitePoint) |
|||
{ |
|||
this.LuvWhitePoint = luvWhitePoint; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the target reference whitepoint. When not set, <see cref="CieLuv.DefaultWhitePoint"/> is used.
|
|||
/// </summary>
|
|||
public CieXyz LuvWhitePoint |
|||
{ |
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
get; |
|||
} |
|||
|
|||
/// <inheritdoc />
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public CieLuv Convert(CieXyz input) |
|||
{ |
|||
DebugGuard.NotNull(input, nameof(input)); |
|||
|
|||
// Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Luv.html
|
|||
float yr = input.Y / this.LuvWhitePoint.Y; |
|||
float up = ComputeUp(input); |
|||
float vp = ComputeVp(input); |
|||
float upr = ComputeUp(this.LuvWhitePoint); |
|||
float vpr = ComputeVp(this.LuvWhitePoint); |
|||
|
|||
float l = yr > CieConstants.Epsilon ? ((116 * MathF.Pow(yr, 0.3333333F)) - 16F) : (CieConstants.Kappa * yr); |
|||
|
|||
if (float.IsNaN(l) || l < 0) |
|||
{ |
|||
l = 0; |
|||
} |
|||
|
|||
float u = 13 * l * (up - upr); |
|||
float v = 13 * l * (vp - vpr); |
|||
|
|||
if (float.IsNaN(u)) |
|||
{ |
|||
u = 0; |
|||
} |
|||
|
|||
if (float.IsNaN(v)) |
|||
{ |
|||
v = 0; |
|||
} |
|||
|
|||
return new CieLuv(l, u, v, this.LuvWhitePoint); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Calculates the blue-yellow chromacity based on the given whitepoint.
|
|||
/// </summary>
|
|||
/// <param name="input">The whitepoint</param>
|
|||
/// <returns>The <see cref="float"/></returns>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static float ComputeUp(CieXyz input) |
|||
{ |
|||
return (4 * input.X) / (input.X + (15 * input.Y) + (3 * input.Z)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Calculates the red-green chromacity based on the given whitepoint.
|
|||
/// </summary>
|
|||
/// <param name="input">The whitepoint</param>
|
|||
/// <returns>The <see cref="float"/></returns>
|
|||
private static float ComputeVp(CieXyz input) |
|||
{ |
|||
return (9 * input.Y) / (input.X + (15 * input.Y) + (3 * input.Z)); |
|||
} |
|||
} |
|||
} |
|||
@ -1,4 +1,4 @@ |
|||
namespace ImageSharp.Tests.Colors.Colorspaces |
|||
namespace ImageSharp.Tests.Colorspaces |
|||
{ |
|||
using System.Collections.Generic; |
|||
using ImageSharp.ColorSpaces; |
|||
@ -0,0 +1,71 @@ |
|||
namespace ImageSharp.Tests |
|||
{ |
|||
using System.Collections.Generic; |
|||
using ImageSharp.ColorSpaces; |
|||
using ImageSharp.ColorSpaces.Conversion; |
|||
|
|||
using Xunit; |
|||
|
|||
/// <summary>
|
|||
/// Tests <see cref="CieXyz"/>-<see cref="CieLuv"/> conversions.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Test data generated using:
|
|||
/// <see href="http://www.brucelindbloom.com/index.html?ColorCalculator.html"/>
|
|||
/// </remarks>
|
|||
public class CieXyzAndCieLuvConversionTest |
|||
{ |
|||
private static readonly IEqualityComparer<float> FloatRoundingComparer = new FloatRoundingComparer(4); |
|||
|
|||
/// <summary>
|
|||
/// Tests conversion from <see cref="CieLuv"/> to <see cref="CieXyz"/> (<see cref="Illuminants.D65"/>).
|
|||
/// </summary>
|
|||
[Theory] |
|||
[InlineData(0, 0, 0, 0, 0, 0)] |
|||
[InlineData(0, 100, 50, 0, 0, 0)] |
|||
[InlineData(0.1, 100, 50, 0.000493, 0.000111, 0)] |
|||
[InlineData(70.0000, 86.3525, 2.8240, 0.569310, 0.407494, 0.365843)] |
|||
[InlineData(10.0000, -1.2345, -10.0000, 0.012191, 0.011260, 0.025939)] |
|||
[InlineData(100, 0, 0, 0.950470, 1.000000, 1.088830)] |
|||
[InlineData(1, 1, 1, 0.001255, 0.001107, 0.000137)] |
|||
public void Convert_Luv_to_Xyz(float l, float u, float v, float x, float y, float z) |
|||
{ |
|||
// Arrange
|
|||
CieLuv input = new CieLuv(l, u, v, Illuminants.D65); |
|||
ColorSpaceConverter converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; |
|||
|
|||
// Act
|
|||
CieXyz output = converter.ToCieXyz(input); |
|||
|
|||
// Assert
|
|||
Assert.Equal(x, output.X, FloatRoundingComparer); |
|||
Assert.Equal(y, output.Y, FloatRoundingComparer); |
|||
Assert.Equal(z, output.Z, FloatRoundingComparer); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Tests conversion from <see cref="CieXyz"/> (<see cref="Illuminants.D65"/>) to <see cref="CieLuv"/>.
|
|||
/// </summary>
|
|||
[Theory] |
|||
[InlineData(0, 0, 0, 0, 0, 0)] |
|||
[InlineData(0.000493, 0.000111, 0, 0.1003, 0.9332, -0.0070)] |
|||
[InlineData(0.569310, 0.407494, 0.365843, 70.0000, 86.3524, 2.8240)] |
|||
[InlineData(0.012191, 0.011260, 0.025939, 9.9998, -1.2343, -9.9999)] |
|||
[InlineData(0.950470, 1.000000, 1.088830, 100, 0, 0)] |
|||
[InlineData(0.001255, 0.001107, 0.000137, 0.9999, 0.9998, 1.0004)] |
|||
public void Convert_Xyz_to_Luv(float x, float y, float z, float l, float u, float v) |
|||
{ |
|||
// Arrange
|
|||
CieXyz input = new CieXyz(x, y, z); |
|||
ColorSpaceConverter converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; |
|||
|
|||
// Act
|
|||
CieLuv output = converter.ToCieLuv(input); |
|||
|
|||
// Assert
|
|||
Assert.Equal(l, output.L, FloatRoundingComparer); |
|||
Assert.Equal(u, output.U, FloatRoundingComparer); |
|||
Assert.Equal(v, output.V, FloatRoundingComparer); |
|||
} |
|||
} |
|||
} |
|||
@ -1,4 +1,4 @@ |
|||
namespace ImageSharp.Tests.Colors.Colorspaces |
|||
namespace ImageSharp.Tests.Colorspaces |
|||
{ |
|||
using System.Collections.Generic; |
|||
|
|||
@ -1,4 +1,4 @@ |
|||
namespace ImageSharp.Tests.Colors.Colorspaces |
|||
namespace ImageSharp.Tests.Colorspaces |
|||
{ |
|||
using System.Collections.Generic; |
|||
|
|||
@ -1,4 +1,4 @@ |
|||
namespace ImageSharp.Tests.Colors.Colorspaces |
|||
namespace ImageSharp.Tests.Colorspaces |
|||
{ |
|||
using System.Collections.Generic; |
|||
|
|||
@ -1,4 +1,4 @@ |
|||
namespace ImageSharp.Tests.Colors.Colorspaces |
|||
namespace ImageSharp.Tests.Colorspaces |
|||
{ |
|||
using System.Collections.Generic; |
|||
|
|||
@ -1,4 +1,4 @@ |
|||
namespace ImageSharp.Tests.Colors.Colorspaces |
|||
namespace ImageSharp.Tests.Colorspaces |
|||
{ |
|||
using System.Collections.Generic; |
|||
|
|||
Loading…
Reference in new issue