Browse Source

Simplify YCbCr

pull/20/head
James Jackson-South 9 years ago
parent
commit
f63e9fe681
  1. 75
      src/ImageSharp/Colors/Colorspaces/YCbCr.cs
  2. 36
      tests/ImageSharp.Tests/Colors/ColorConversionTests.cs

75
src/ImageSharp/Colors/Colorspaces/YCbCr.cs

@ -7,59 +7,49 @@ namespace ImageSharp
{
using System;
using System.ComponentModel;
using System.Numerics;
/// <summary>
/// Represents an YCbCr (luminance, blue chroma, red chroma) color conforming to the
/// Full range standard used in digital imaging systems.
/// Represents an YCbCr (luminance, blue chroma, red chroma) color conforming to the full range standard used in digital imaging systems.
/// <see href="http://en.wikipedia.org/wiki/YCbCr"/>
/// </summary>
public struct YCbCr : IEquatable<YCbCr>, IAlmostEquatable<YCbCr, float>
public struct YCbCr : IEquatable<YCbCr>
{
/// <summary>
/// Represents a <see cref="YCbCr"/> that has Y, Cb, and Cr values set to zero.
/// </summary>
public static readonly YCbCr Empty = default(YCbCr);
/// <summary>
/// The epsilon for comparing floating point numbers.
/// </summary>
private const float Epsilon = 0.001F;
/// <summary>
/// The backing vector for SIMD support.
/// </summary>
private Vector3 backingVector;
/// <summary>
/// Initializes a new instance of the <see cref="YCbCr"/> struct.
/// </summary>
/// <param name="y">The y luminance component.</param>
/// <param name="cb">The cb chroma component.</param>
/// <param name="cr">The cr chroma component.</param>
public YCbCr(float y, float cb, float cr)
public YCbCr(byte y, byte cb, byte cr)
: this()
{
this.backingVector = Vector3.Clamp(new Vector3(y, cb, cr), Vector3.Zero, new Vector3(255));
this.Y = y;
this.Cb = cb;
this.Cr = cr;
}
/// <summary>
/// Gets the Y luminance component.
/// <remarks>A value ranging between 0 and 255.</remarks>
/// </summary>
public float Y => this.backingVector.X;
public byte Y { get; }
/// <summary>
/// Gets the Cb chroma component.
/// <remarks>A value ranging between 0 and 255.</remarks>
/// </summary>
public float Cb => this.backingVector.Y;
public byte Cb { get; }
/// <summary>
/// Gets the Cr chroma component.
/// <remarks>A value ranging between 0 and 255.</remarks>
/// </summary>
public float Cr => this.backingVector.Z;
public byte Cr { get; }
/// <summary>
/// Gets a value indicating whether this <see cref="YCbCr"/> is empty.
@ -79,13 +69,13 @@ namespace ImageSharp
/// </returns>
public static implicit operator YCbCr(Color color)
{
float r = color.R;
float g = color.G;
float b = color.B;
byte r = color.R;
byte g = color.G;
byte b = color.B;
float y = (float)((0.299 * r) + (0.587 * g) + (0.114 * b));
float cb = 128 + (float)((-0.168736 * r) - (0.331264 * g) + (0.5 * b));
float cr = 128 + (float)((0.5 * r) - (0.418688 * g) - (0.081312 * b));
byte y = (byte)((0.299F * r) + (0.587F * g) + (0.114F * b));
byte cb = (byte)(128 + ((-0.168736F * r) - (0.331264F * g) + (0.5F * b)));
byte cr = (byte)(128 + ((0.5F * r) - (0.418688F * g) - (0.081312F * b)));
return new YCbCr(y, cb, cr);
}
@ -127,7 +117,13 @@ namespace ImageSharp
/// <inheritdoc/>
public override int GetHashCode()
{
return GetHashCode(this);
unchecked
{
int hashCode = this.Y.GetHashCode();
hashCode = (hashCode * 397) ^ this.Cb.GetHashCode();
hashCode = (hashCode * 397) ^ this.Cr.GetHashCode();
return hashCode;
}
}
/// <inheritdoc/>
@ -138,7 +134,7 @@ namespace ImageSharp
return "YCbCr [ Empty ]";
}
return $"YCbCr [ Y={this.Y:#0.##}, Cb={this.Cb:#0.##}, Cr={this.Cr:#0.##} ]";
return $"YCbCr [ Y={this.Y}, Cb={this.Cb}, Cr={this.Cr} ]";
}
/// <inheritdoc/>
@ -155,28 +151,7 @@ namespace ImageSharp
/// <inheritdoc/>
public bool Equals(YCbCr other)
{
return this.AlmostEquals(other, Epsilon);
}
/// <inheritdoc/>
public bool AlmostEquals(YCbCr other, float precision)
{
Vector3 result = Vector3.Abs(this.backingVector - other.backingVector);
return result.X < precision
&& result.Y < precision
&& result.Z < precision;
return this.Y == other.Y && this.Cb == other.Cb && this.Cr == other.Cr;
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <param name="color">
/// The instance of <see cref="YCbCr"/> to return the hash code for.
/// </param>
/// <returns>
/// A 32-bit signed integer that is the hash code for this instance.
/// </returns>
private static int GetHashCode(YCbCr color) => color.backingVector.GetHashCode();
}
}
}

36
tests/ImageSharp.Tests/Colors/ColorConversionTests.cs

@ -31,23 +31,41 @@ namespace ImageSharp.Tests
Color color = Color.White;
YCbCr yCbCr = color;
Assert.Equal(255, yCbCr.Y, 0);
Assert.Equal(128, yCbCr.Cb, 0);
Assert.Equal(128, yCbCr.Cr, 0);
Assert.Equal(255, yCbCr.Y);
Assert.Equal(128, yCbCr.Cb);
Assert.Equal(128, yCbCr.Cr);
// Black
Color color2 = Color.Black;
YCbCr yCbCr2 = color2;
Assert.Equal(0, yCbCr2.Y, 0);
Assert.Equal(128, yCbCr2.Cb, 0);
Assert.Equal(128, yCbCr2.Cr, 0);
Assert.Equal(0, yCbCr2.Y);
Assert.Equal(128, yCbCr2.Cb);
Assert.Equal(128, yCbCr2.Cr);
// Gray
Color color3 = Color.Gray;
YCbCr yCbCr3 = color3;
Assert.Equal(128, yCbCr3.Y, 0);
Assert.Equal(128, yCbCr3.Cb, 0);
Assert.Equal(128, yCbCr3.Cr, 0);
Assert.Equal(128, yCbCr3.Y);
Assert.Equal(128, yCbCr3.Cb);
Assert.Equal(128, yCbCr3.Cr);
//Assert.Equal(255, yCbCr.Y, 0);
//Assert.Equal(128, yCbCr.Cb, 0);
//Assert.Equal(128, yCbCr.Cr, 0);
//// Black
//Color color2 = Color.Black;
//YCbCr yCbCr2 = color2;
//Assert.Equal(0, yCbCr2.Y, 0);
//Assert.Equal(128, yCbCr2.Cb, 0);
//Assert.Equal(128, yCbCr2.Cr, 0);
//// Gray
//Color color3 = Color.Gray;
//YCbCr yCbCr3 = color3;
//Assert.Equal(128, yCbCr3.Y, 0);
//Assert.Equal(128, yCbCr3.Cb, 0);
//Assert.Equal(128, yCbCr3.Cr, 0);
}
/// <summary>

Loading…
Cancel
Save