color-classifier
Version:
Classify the color along the reference color. using algorithm the CIEDE2000, RGB, HSV.
107 lines (84 loc) • 3.04 kB
JavaScript
import Color from "./color"
import { radians, degrees, hypot, pow2, pow7 } from "./math"
const { abs, atan2, cos, pow, PI, min, exp, sqrt, sin } = Math;
export const AlgorithmTypes = {
CIEDE2000: "CIEDE2000",
HSV: "HSV",
RGB: "RGB"
};
const diffMethodMap = {
[AlgorithmTypes.CIEDE2000]: "ciede2000",
[AlgorithmTypes.HSV]: "hsv",
[AlgorithmTypes.RGB]: "rgb"
};
const kl = 1;
const kc = 1;
const kh = 1;
const pow7_25 = pow7(25);
export default class ColorDiff {
static diff(algorithmType, color1, color2) {
const method = diffMethodMap[algorithmType];
return ColorDiff[method](color1, color2);
}
static ciede2000(color1, color2) {
const a = Color.rgbToLab(color1.rgb);
const b = Color.rgbToLab(color2.rgb);
return ColorDiff._ciede2000(
a.l, a.a, a.b,
b.l, b.a, b.b
);
}
static _ciede2000(l1, a1, b1, l2, a2, b2) {
const c1 = hypot(a1, b1);
const c2 = hypot(a2, b2);
const ac1c2 = (c1 + c2) / 2;
const g = 0.5 * (1 - sqrt(pow7(ac1c2) / (pow7(ac1c2) + pow7_25)));
const a1p = (1 + g) * a1;
const a2p = (1 + g) * a2;
const c1p = sqrt(pow2(a1p) + pow2(b1));
const c2p = sqrt(pow2(a2p) + pow2(b2));
const h1pd = degrees(atan2(b1, a1p));
const h1p = b1 === 0 && a1p === 0 ? 0 : h1pd > 0 ? h1pd : h1pd + 360;
const h2pd = degrees(atan2(b2, a2p));
const h2p = b2 === 0 && a2p === 0 ? 0 : h2pd > 0 ? h2pd : h2pd + 360;
const dlp = l2 - l1;
const dcp = c2p - c1p;
const dhp = 2 * sqrt(c1p * c2p) * sin(radians(c1 * c2 === 0 ? 0 : abs(h2p - h1p) <= 180 ? h2p - h1p : (h2p - h1p) > 180 ? (h2p - h1p) - 360 : (h2p - h1p) + 360) / 2);
const al = (l1 + l2) / 2;
const acp = (c1p + c2p) / 2;
let ahp;
if (c1 * c2 === 0) {
ahp = h1p + h2p;
} else if(abs(h1p - h2p) <= 180) {
ahp = (h1p + h2p) / 2;
} else if (abs(h1p - h2p) > 180 && h1p + h2p < 360) {
ahp = (h1p + h2p + 360) / 2;
} else {
ahp = (h1p + h2p - 360) / 2;
}
const t = 1 - 0.17 * cos(radians(ahp - 30)) + 0.24 * cos(radians(2 * ahp)) + 0.32 * cos(radians(3 * ahp + 6)) - 0.20 * cos(radians(4 * ahp - 63));
const dro = 30 * exp(-(pow2((ahp - 275) / 25)));
const rc = sqrt((pow7(acp)) / (pow7(acp) + pow7_25));
const sl = 1 + ((0.015 * pow2(al - 50)) / sqrt(20 + pow2(al - 50)));
const sc = 1 + 0.045 * acp;
const sh = 1 + 0.015 * acp * t;
const rt = -2 * rc * sin(radians(2 * dro));
return sqrt(pow2(dlp / (sl * kl)) + pow2(dcp / (sc * kc)) + pow2(dhp / (sh * kh)) + rt * (dcp / (sc * kc)) * (dhp / (sh * kh)));
}
static hsv(color1, color2) {
const a = color1.hsv;
const b = color2.hsv;
let h = 0;
if (a.h > b.h) {
h = min(a.h - b.h, b.h - a.h + 360);
} else {
h = min(b.h - a.h, a.h - b.h + 360);
}
return sqrt(pow2(h) + pow2(a.s - b.s) + pow2(a.v - b.v));
}
static rgb(color1, color2) {
const a = color1.rgb;
const b = color2.rgb;
return sqrt(pow2(a.r - b.r) + pow2(a.g - b.g) + pow2(a.b - b.b));
}
}