public static Color LabToRgb(Lab lab) { XYZ xyz = LabToXyz(lab); Color rgba = XyzToRgb(xyz); return(rgba); }
public static Lab RgbToLab(Color rgba) { XYZ xyz = RgbToXyz(rgba); Lab lab = XyzToLab(xyz); return(lab); }
public static XYZ LabToXyz(Lab lab) { float y = (lab.L + 16f) / 116f; float x = lab.A / 500f + y; float z = y - lab.B / 200f; float f = 16f / 116f; y = (Mathf.Pow(y, 3f) > 0.008856f) ? Mathf.Pow(y, 3f) : (y - f) / 7.787f; x = (Mathf.Pow(x, 3f) > 0.008856f) ? Mathf.Pow(x, 3f) : (x - f) / 7.787f; z = (Mathf.Pow(z, 3f) > 0.008856f) ? Mathf.Pow(z, 3f) : (z - f) / 7.787f; XYZ xyz = new XYZ { X = xyzWhiteRef.X * x, Y = xyzWhiteRef.Y * y, Z = xyzWhiteRef.Z * z, Alpha = lab.Alpha }; return(xyz); }
public static Lab XyzToLab(XYZ xyz) { float x = xyz.X / xyzWhiteRef.X; float y = xyz.Y / xyzWhiteRef.Y; float z = xyz.Z / xyzWhiteRef.Z; float p = 1f / 3f; float f = 16f / 116f; x = (x > 0.008856f) ? Mathf.Pow(x, p) : (7.787f * x) + f; y = (y > 0.008856f) ? Mathf.Pow(y, p) : (7.787f * y) + f; z = (z > 0.008856f) ? Mathf.Pow(z, p) : (7.787f * z) + f; Lab lab = new Lab { L = (116f * y) - 16f, A = 500f * (x - y), B = 200f * (y - z), Alpha = xyz.Alpha }; return(lab); }
private static LCh LabToLCh(Lab lab) { LCh lch = new LCh(); lch.l = lab.L; lch.c = Mathf.Sqrt(lab.A * lab.A + lab.B * lab.B); float h = Mathf.Rad2Deg * Mathf.Atan2(lab.B, lab.A); if (h < 0) { h += 360f; } else if (h >= 360) { h -= 360f; } lch.h = h; lch.alpha = lab.Alpha; return(lch); }
/// <summary> /// Tips: 0.5f (really high contrast shapes, maybe 10+ bit monitors), 1f (high-quality monitors, indoors) 2.0f (else). /// </summary> public static float DeltaEmpfindung00(Lab lab1, Lab lab2, DeltaEWeightType weight = DeltaEWeightType.Graphic) { // Lab to LCh LCh lch1 = LabToLCh(lab1); LCh lch2 = LabToLCh(lab2); // Weight Factors DeltaEWeight weightFactors = Convert.ToBoolean((int)weight) ? weightGraphic : weightTextile; float CX = (lch1.c + lch2.c) / 2f; float GX = 0.5f * (1f - Mathf.Sqrt(Mathf.Pow(CX, 7f) / (Mathf.Pow(CX, 7f) + Mathf.Pow(25f, 7f)))); float NN = (1f + GX) * lab1.A; lch1.c = Mathf.Sqrt(NN * NN + lab1.B * lab1.B); float hue1 = LabToHue(NN, lab1.B); NN = (1f + GX) * lab2.A; lch2.c = Mathf.Sqrt(NN * NN + lab2.B * lab2.B); float hue2 = LabToHue(NN, lab2.B); float deltaLightness = lch2.l - lch1.l; float deltaChroma = lch2.c - lch1.c; float deltaHue; if ((lch1.c * lch2.c) == 0f) { deltaHue = 0f; } else { NN = Mathf.Round((hue2 - hue1) * 1000f) / 1000f; if (Mathf.Abs(NN) <= 180f) { deltaHue = hue2 - hue1; } else { if (NN > 180f) { deltaHue = hue2 - hue1 - 360f; } else { deltaHue = hue2 - hue1 + 360f; } } } deltaHue = 2f * Mathf.Sqrt(lch1.c * lch2.c) * Mathf.Sin((deltaHue / 2f) * Mathf.Deg2Rad); float lightnessAverage = (lch1.l + lch2.l) / 2f; float chromaAverage = (lch1.c + lch2.c) / 2f; float hueNeutralsCompensation; if ((lch1.c * lch2.c) == 0f) { hueNeutralsCompensation = hue1 + hue2; } else { NN = Mathf.Abs(Mathf.Round((hue1 - hue2) * 1000f) / 1000f); if (NN > 180f) { if ((hue2 + hue1) < 360f) { hueNeutralsCompensation = hue1 + hue2 + 360f; } else { hueNeutralsCompensation = hue1 + hue2 - 360f; } } else { hueNeutralsCompensation = hue1 + hue2; } hueNeutralsCompensation /= 2f; } float T = 1f - 0.17f * Mathf.Cos((hueNeutralsCompensation - 30f) * Mathf.Deg2Rad) + 0.24f * Mathf.Cos((2f * hueNeutralsCompensation) * Mathf.Deg2Rad) + 0.32f * Mathf.Cos((3f * hueNeutralsCompensation + 6f) * Mathf.Deg2Rad) - 0.20f * Mathf.Cos((4f * hueNeutralsCompensation - 63f) * Mathf.Deg2Rad); // Compensations float lightnessCompensation = 1f + ((0.015f * ((lightnessAverage - 50f) * (lightnessAverage - 50f))) / Mathf.Sqrt(20f + ((lightnessAverage - 50f) * (lightnessAverage - 50f)))); float chromaCompensation = 1f + weightFactors.kC * chromaAverage; float hueCompensation = 1f + weightFactors.kH * chromaAverage * T; // Rotation float PH = 30f * Mathf.Exp(-((hueNeutralsCompensation - 275f) / 25f) * ((hueNeutralsCompensation - 275f) / 25f)); float RC = 2f * Mathf.Sqrt(Mathf.Pow(chromaAverage, 7f) / (Mathf.Pow(chromaAverage, 7f) + Mathf.Pow(25f, 7f))); float rotationTerm = -Mathf.Sin((2f * PH) * Mathf.Deg2Rad) * RC; // Weights Constants float weightFactorChroma = 1f; float weightFactorHue = 1f; // Corrections deltaLightness = deltaLightness / (weightFactors.kL * lightnessCompensation); deltaChroma = deltaChroma / (weightFactorChroma * chromaCompensation); deltaHue = deltaHue / (weightFactorHue * hueCompensation); float distance = Mathf.Sqrt(Mathf.Pow(deltaLightness, 2f) + Mathf.Pow(deltaChroma, 2f) + Mathf.Pow(deltaHue, 2f) + rotationTerm * deltaChroma * deltaHue); return(distance); }