ciede2000ColorDifference method

bool ciede2000ColorDifference(
  1. LABColor color, {
  2. double tolerance = 2.3,
  3. double kc = 1.0,
  4. double kh = 1.0,
  5. double kl = 1.0,
})

Compute color differences using the ciede2000 algorithm.

@color: color is a color of type LAB.

@tolerance: tolerance is the threshold for judging whether there is a difference.

@kc: kc refers to the influence coefficient of the degree of chromaticity change on chromatic aberration. The value range of kC is between 1.0 and 2.0. The role of kC is to reduce the influence on chromatic aberration in the low-saturation area (both C1 and C2 are relatively small), and increase the influence on chromatic aberration in the high-saturation area (both C1 and C2 are relatively large).

@kh: kh refers to the influence coefficient of the sampling interval of the light source on the color difference, which is used to adjust the influence of the light source change in the color difference. The function of kh is to adjust the error generated when measuring color difference under different light source conditions, so that the color difference measured under different light sources is more consistent. The value range of kh is between 1.0 and 1.3.

@kl: kl is the tuning parameter of the photometric reflectance weighting function. kL is mainly used to control the influence of brightness on chromatic aberration, and the value range of kL is between 1.0 and 2.0.

Implementation

bool ciede2000ColorDifference(
  LABColor color, {
  double tolerance = 2.3,
  double kc = 1.0,
  double kh = 1.0,
  double kl = 1.0,
}) {
  final double deltaL = l - color.l;
  final double averageL = (l + color.l) * 0.5;
  final double c1X = sqrt(pow(a, 2) + pow(b, 2));
  final double c2X = sqrt(pow(color.a, 2) + pow(color.b, 2));
  final double averageCx = (c1X + c2X) * 0.5;
  final double factor =
      sqrt(pow(averageCx, 7) / (pow(averageCx, 7) + pow(25, 7)));
  final double a1P = a + a * 0.5 * (1 - factor);
  final double a2P = color.a + color.a * 0.5 * (1 - factor);
  final double c1P = sqrt(pow(a1P, 2) + pow(b, 2));
  final double c2P = sqrt(pow(a2P, 2) + pow(color.b, 2));
  final double averageCP = (c1P + c2P) * 0.5;
  final double deltaCP = c1P - c2P;
  double deltaHP = 0;
  double averageHP = 0;
  if (c1P != 0 && c2P != 0) {
    final double h1P = atan2(b, a1P).range(min: 0, max: 360);
    final double h2P = atan2(color.b, a2P).range(min: 0, max: 360);
    final double deltaH = (h1P - h2P).abs();

    /// deltaHP
    if (deltaH <= 180) {
      deltaHP = h2P - h1P;
    }
    if (deltaH > 180 && h2P <= h1P) {
      deltaHP = h2P - h1P + 360;
    }
    if (deltaH > 180 && h2P > h1P) {
      deltaHP = h2P - h1P - 360;
    }

    /// averageH
    if (deltaH > 180) {
      averageHP = (h1P + h2P + 360) * 0.5;
    }
    if (deltaH <= 180) {
      averageHP = (h1P + h2P) * 0.5;
    }
  }
  final double deltaDHP = 2 * sqrt(c1P * c2P) * sin(deltaHP * 0.5);
  final double t = 1 -
      0.17 * cos(averageHP - 30) +
      0.24 * cos(2 * averageHP) +
      0.32 * cos(3 * averageHP + 6) -
      0.2 * cos(4 * averageHP - 63);
  final double sl =
      1 + (0.015 * pow(averageL - 50, 2)) / sqrt(20 + pow(averageL - 50, 2));
  final double sc = 1 + 0.045 * averageCP;
  final double sh = 1 + 0.015 * averageCP * t;
  final double rt =
      -2 * factor * sin(60 * exp(-pow((averageHP - 275) / 25, 2)));
  final double deltaE = sqrt(
    pow(deltaL / (kl * sl), 2) +
        pow(deltaCP / (kc * sc), 2) +
        pow(deltaDHP / (kh * sh), 2) +
        rt * (deltaCP / (kc * sc)) * (deltaDHP / (kh * sh)),
  );
  return deltaE > tolerance;
}