From f63e9fe6816a4fda11c60ed501d9366eee12e041 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 3 Nov 2016 11:03:44 +1100 Subject: [PATCH] Simplify YCbCr --- src/ImageSharp/Colors/Colorspaces/YCbCr.cs | 75 +++++++------------ .../Colors/ColorConversionTests.cs | 36 ++++++--- 2 files changed, 52 insertions(+), 59 deletions(-) diff --git a/src/ImageSharp/Colors/Colorspaces/YCbCr.cs b/src/ImageSharp/Colors/Colorspaces/YCbCr.cs index 04a4b6e50..c9a0872c5 100644 --- a/src/ImageSharp/Colors/Colorspaces/YCbCr.cs +++ b/src/ImageSharp/Colors/Colorspaces/YCbCr.cs @@ -7,59 +7,49 @@ namespace ImageSharp { using System; using System.ComponentModel; - using System.Numerics; /// - /// 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. /// /// - public struct YCbCr : IEquatable, IAlmostEquatable + public struct YCbCr : IEquatable { /// /// Represents a that has Y, Cb, and Cr values set to zero. /// public static readonly YCbCr Empty = default(YCbCr); - /// - /// The epsilon for comparing floating point numbers. - /// - private const float Epsilon = 0.001F; - - /// - /// The backing vector for SIMD support. - /// - private Vector3 backingVector; - /// /// Initializes a new instance of the struct. /// /// The y luminance component. /// The cb chroma component. /// The cr chroma component. - 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; } /// /// Gets the Y luminance component. /// A value ranging between 0 and 255. /// - public float Y => this.backingVector.X; + public byte Y { get; } /// /// Gets the Cb chroma component. /// A value ranging between 0 and 255. /// - public float Cb => this.backingVector.Y; + public byte Cb { get; } /// /// Gets the Cr chroma component. /// A value ranging between 0 and 255. /// - public float Cr => this.backingVector.Z; + public byte Cr { get; } /// /// Gets a value indicating whether this is empty. @@ -79,13 +69,13 @@ namespace ImageSharp /// 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 /// 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; + } } /// @@ -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} ]"; } /// @@ -155,28 +151,7 @@ namespace ImageSharp /// public bool Equals(YCbCr other) { - return this.AlmostEquals(other, Epsilon); - } - - /// - 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; } - - /// - /// Returns the hash code for this instance. - /// - /// - /// The instance of to return the hash code for. - /// - /// - /// A 32-bit signed integer that is the hash code for this instance. - /// - private static int GetHashCode(YCbCr color) => color.backingVector.GetHashCode(); } -} +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colors/ColorConversionTests.cs b/tests/ImageSharp.Tests/Colors/ColorConversionTests.cs index 593a0bbe6..f1b6d5f9b 100644 --- a/tests/ImageSharp.Tests/Colors/ColorConversionTests.cs +++ b/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); } ///