Skip to content

Commit

Permalink
Add ColorUtil.xyToDuv (#4401)
Browse files Browse the repository at this point in the history
Signed-off-by: Cody Cutrer <[email protected]>
  • Loading branch information
ccutrer authored Oct 7, 2024
1 parent d9e5df0 commit ea5480d
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
* @author Holger Friedrich - Transfer RGB color conversion from HSBType, improve RGB conversion, restructuring
* @author Chris Jackson - Added fromRGB (moved from HSBType)
* @author Andrew Fiddian-Green - Extensive revamp to fix bugs and improve accuracy
* @author Cody Cutrer - Added xyToDuv
*/
@NonNullByDefault
public class ColorUtil {
Expand All @@ -45,11 +46,12 @@ public class ColorUtil {
private static final BigDecimal BIG_DECIMAL_120 = BigDecimal.valueOf(120);
private static final BigDecimal BIG_DECIMAL_100 = BigDecimal.valueOf(100);
private static final BigDecimal BIG_DECIMAL_60 = BigDecimal.valueOf(60);
private static final BigDecimal BIG_DECIMAL_50 = BigDecimal.valueOf(50);
private static final BigDecimal BIG_DECIMAL_5 = BigDecimal.valueOf(5);
private static final BigDecimal BIG_DECIMAL_3 = BigDecimal.valueOf(3);
private static final BigDecimal BIG_DECIMAL_2 = BigDecimal.valueOf(2);
private static final BigDecimal BIG_DECIMAL_2_POINT_55 = new BigDecimal("2.55");
private static final double[] CORM_COEFFICIENTS = { -0.00616793, 0.0893944, -0.5179722, 1.5317403, -2.4243787,
1.925865, -0.471106 };

public static final Gamut DEFAULT_GAMUT = new Gamut(new double[] { 0.9961, 0.0001 }, new double[] { 0, 0.9961 },
new double[] { 0, 0.0001 });
Expand Down Expand Up @@ -523,6 +525,39 @@ public static HSBType xyToHsb(double[] xyY, Gamut gamut) throws IllegalArgumentE
return hsb;
}

/**
* Calculate the Duv (Delta u,v) metric from a
* <a href="https://en.wikipedia.org/wiki/CIE_1931_color_space">CIE 1931</a> {@code xy} format color.
*
* Duv describes the distance of a color point from the black body curve. It's useful for calculating
* if a color is near to "white", at any color temperature.
*
* @param xy array of double with CIE 1931 x,y in the range 0.0000 to 1.0000
* @return the calculated Duv metric
* @throws IllegalArgumentException when input array has wrong size or exceeds allowed value range.
*/
public static double xyToDuv(double[] xy) throws IllegalArgumentException {
if (xy.length != 2) {
throw new IllegalArgumentException("xyToDuv() requires 2 arguments");
}

for (int i = 0; i < xy.length; i++) {
if (xy[i] < 0 || xy[i] > 1) {
throw new IllegalArgumentException(
String.format("xyToDuv() argument %d value '%f' out of range [0..1.0]", i, xy[i]));
}
}

double x = xy[0];
double y = xy[1];
double u = 4.0 * x / (-2.0 * x + 12 * y + 3.0);
double v = 6.0 * y / (-2.0 * x + 12 * y + 3.0);
double Lfp = Math.sqrt(Math.pow(u - 0.292, 2) + Math.pow(v - 0.24, 2));
double a = Math.acos((u - 0.292) / Lfp);
double Lbb = polynomialFit(a, CORM_COEFFICIENTS);
return Lfp - Lbb;
}

/**
* Get an array of int from an array of PercentType.
*/
Expand Down Expand Up @@ -1176,4 +1211,25 @@ public static double xyToKelvin(double[] xy) {
double n = (xy[0] - 0.3320) / (0.1858 - xy[1]);
return (437 * Math.pow(n, 3)) + (3601 * Math.pow(n, 2)) + (6861 * n) + 5517;
}

/**
* Calculates a polynomial regression.
*
* This calculates the equation K[4]*x^0 + K[3]*x^1 + K[2]*x^2 + K[1]*x^3 + K[0]*x^4
*
* @param x The independent variable distributed through each term of the polynomial
* @param coefficients The coefficients of the polynomial. Note that the terms are in
* order from largest exponent to smallest exponent, which is the reverse order
* of the usual way of writing it in academic papers
* @return the result of substituting x into the regression polynomial
*/
private static double polynomialFit(double x, double[] coefficients) {
double result = 0.0;
double xAccumulator = 1.0;
for (int i = coefficients.length - 1; i >= 0; i--) {
result += coefficients[i] * xAccumulator;
xAccumulator *= x;
}
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,20 @@ public void testConversionRgbToHsb(int[] hsb, int[] rgb) {
assertTrue(hsbType.closeTo(new HSBType(expected), 0.01));
}

@Test
public void testXyToDuv() {
// Black
assertEquals(-0.0017d, ColorUtil.xyToDuv(new double[] { 0.3227d, 0.3290d }), 0.0001);
// 2700K
assertEquals(0.0000d, ColorUtil.xyToDuv(new double[] { 0.4599d, 0.4106d }), 0.0001);
// 3000K
assertEquals(0.0000d, ColorUtil.xyToDuv(new double[] { 0.4369d, 0.4041d }), 0.0001);
// Red
assertEquals(0.2727d, ColorUtil.xyToDuv(new double[] { 0.6987d, 0.2974d }), 0.0001);
// Yellow
assertEquals(0.0387d, ColorUtil.xyToDuv(new double[] { 0.4442d, 0.5166d }), 0.0001);
}

private void xyToXY(double[] xy, Gamut gamut) {
assertTrue(xy.length > 1);
HSBType hsb = ColorUtil.xyToHsb(xy, gamut);
Expand Down

0 comments on commit ea5480d

Please sign in to comment.