public void GamutContainsWorksCorrectly() { Random r = new Random(0); for (int trial = 0; trial < 1000; trial++) { var point = new CIE1931Point(r.NextDouble(), r.NextDouble()); var gamutB = CIE1931Gamut.ForModel("LCT001"); Assert.AreEqual(ReferenceColorConverter.CheckPointInLampsReach(point), gamutB.Contains(point)); } }
/// <summary> /// Method to see if the given XY value is within the reach of the lamps. /// </summary> /// <param name="p">p the point containing the X,Y value</param> /// <returns>true if within reach, false otherwise.</returns> public static bool CheckPointInLampsReach(CIE1931Point p) { CIE1931Point v1 = new CIE1931Point(Lime.x - Red.x, Lime.y - Red.y); CIE1931Point v2 = new CIE1931Point(Blue.x - Red.x, Blue.y - Red.y); CIE1931Point q = new CIE1931Point(p.x - Red.x, p.y - Red.y); double s = ReferenceColorConverter.CrossProduct(q, v2) / ReferenceColorConverter.CrossProduct(v1, v2); double t = ReferenceColorConverter.CrossProduct(v1, q) / ReferenceColorConverter.CrossProduct(v1, v2); if ((s >= 0.0f) && (t >= 0.0f) && (s + t <= 1.0f)) { return(true); } else { return(false); } }
public void CompareColorConversionWithReference() { // Use a consistent seed for test reproducability Random r = new Random(0); for (int trial = 0; trial < 1000; trial++) { double red = r.NextDouble(); double green = r.NextDouble(); double blue = r.NextDouble(); var referenceXy = ReferenceColorConverter.XyFromColor(red, green, blue); // LCT001 uses Gamut B, which is the gamut used in the reference implementation. var actualXy = HueColorConverter.RgbToXY(new RGBColor(red, green, blue), "LCT001"); AssertAreEqual(referenceXy, actualXy, 0.0001); } }
public void ColorConversionRoundtripInsideGamut() { // Use a consistent seed for test reproducability Random r = new Random(0); for (int trial = 0; trial < 1000; trial++) { CIE1931Point originalXy; // Randomly generate a test color that is at a valid CIE1931 coordinate. do { originalXy = new CIE1931Point(r.NextDouble(), r.NextDouble()); }while (originalXy.x + originalXy.y >= 1.0 || !ReferenceColorConverter.CheckPointInLampsReach(originalXy) || !CIE1931Gamut.PhilipsWideGamut.Contains(originalXy)); RGBColor rgb = HueColorConverter.XYToRgb(originalXy, "LCT001"); var xy = HueColorConverter.RgbToXY(rgb, "LCT001"); AssertAreEqual(originalXy, xy, 0.0001); } }
/// <summary> /// Get XY from red,green,blue ints /// </summary> /// <param name="red"></param> /// <param name="green"></param> /// <param name="blue"></param> /// <returns></returns> public static CIE1931Point XyFromColor(double red, double green, double blue) { double r = (red > 0.04045f) ? Math.Pow((red + 0.055f) / (1.0f + 0.055f), 2.4f) : (red / 12.92f); double g = (green > 0.04045f) ? Math.Pow((green + 0.055f) / (1.0f + 0.055f), 2.4f) : (green / 12.92f); double b = (blue > 0.04045f) ? Math.Pow((blue + 0.055f) / (1.0f + 0.055f), 2.4f) : (blue / 12.92f); //double X = r * 0.4360747f + g * 0.3850649f + b * 0.0930804f; //double Y = r * 0.2225045f + g * 0.7168786f + b * 0.0406169f; //double Z = r * 0.0139322f + g * 0.0971045f + b * 0.7141733f; double X = r * 0.664511f + g * 0.154324f + b * 0.162028f; double Y = r * 0.283881f + g * 0.668433f + b * 0.047685f; double Z = r * 0.000088f + g * 0.072310f + b * 0.986039f; double cx = X / (X + Y + Z); double cy = Y / (X + Y + Z); if (Double.IsNaN(cx)) { cx = 0.0f; } if (Double.IsNaN(cy)) { cy = 0.0f; } //Check if the given XY value is within the colourreach of our lamps. CIE1931Point xyPoint = new CIE1931Point(cx, cy); bool inReachOfLamps = ReferenceColorConverter.CheckPointInLampsReach(xyPoint); if (!inReachOfLamps) { //It seems the colour is out of reach //let's find the closes colour we can produce with our lamp and send this XY value out. //Find the closest point on each line in the triangle. CIE1931Point pAB = ReferenceColorConverter.GetClosestPointToPoint(Red, Lime, xyPoint); CIE1931Point pAC = ReferenceColorConverter.GetClosestPointToPoint(Blue, Red, xyPoint); CIE1931Point pBC = ReferenceColorConverter.GetClosestPointToPoint(Lime, Blue, xyPoint); //Get the distances per point and see which point is closer to our Point. double dAB = ReferenceColorConverter.GetDistanceBetweenTwoPoints(xyPoint, pAB); double dAC = ReferenceColorConverter.GetDistanceBetweenTwoPoints(xyPoint, pAC); double dBC = ReferenceColorConverter.GetDistanceBetweenTwoPoints(xyPoint, pBC); double lowest = dAB; CIE1931Point closestPoint = pAB; if (dAC < lowest) { lowest = dAC; closestPoint = pAC; } if (dBC < lowest) { lowest = dBC; closestPoint = pBC; } //Change the xy value to a value which is within the reach of the lamp. cx = closestPoint.x; cy = closestPoint.y; } return(new CIE1931Point(cx, cy)); }