HCL - это очень общее название, есть много способов получить оттенок, цветность и яркость. Например, в Chroma.js есть нечто, что он называет HCL, который представляет собой Lab с преобразованием полярных координат (если вы посмотрите на реальный код). Другие реализации, даже связанные с того же сайта, используют Polar Luv. Поскольку вы можете просто позаимствовать L-фактор и получить оттенок путем преобразования в полярные координаты, оба эти способа являются допустимыми для получения этих трех элементов. Гораздо лучше называть их Polar Lab и Polar Luv из-за путаницы.
M. Алгоритм Sarifuddin (2005) не является Polar Luv или Polar Lab и более прост в вычислительном отношении (вам не нужно сначала выводить пространство Lab или Luv), и на самом деле может быть лучше. Есть некоторые вещи, которые кажутся неправильными в газете. Например, применение евклидова расстояния к цветовому пространству CIE L * C * H *. Использование Hue означает, что оно обязательно круглое, и простое замешивание этого числа в A² + B² + C² вызовет у вас проблемы. То же самое верно для применения цветового пространства на основе оттенков к D94 или D00, поскольку это алгоритмы расстояния со встроенными коррекциями, специфичными для цветового пространства Lab. Если бы я не пропустил что-то там, я бы проигнорировал цифры 6-8. И я подвергаю сомнению отклонения отклонения в графике. Вы можете установить более низкий порог и добиться большего успеха, а числа между цветовыми пространствами не нормализуются. В любом случае, несмотря на некоторые кажущиеся недостатки в статье, описанный алгоритм стоит попробовать. Возможно, вы захотите сделать евклидово на RGB, если это не имеет большого значения. Но, если вы ходите по магазинам вокруг алгоритмов цветового расстояния, то вы идете.
Вот HCL, предоставленный М. Сарифуддином, реализованным на Java. Прочитав эту статью несколько раз, я не могу избежать вывода о том, что она масштабирует расстояние с коэффициентом от 0,16 до 180,16 с учетом изменения оттенка в процедуре distance_hcl. Это настолько серьезный фактор, что он почти не может быть правильным. И делает соответствие цвета отстой. Я закомментировал строку статьи и использую строку только с коэффициентом Al. Масштабирование люминесценции с постоянным коэффициентом ~ 1,4 не сделает его непригодным для использования. Без масштабного коэффициента он оказывается идентичным циклическому сопротивлению.
http://w3.uqo.ca/missaoui/Publications/TRColorSpace.zip исправлена и улучшена версия статьи.
static final public double Y0 = 100;
static final public double gamma = 3;
static final public double Al = 1.4456;
static final public double Ach_inc = 0.16;
public void rgb2hcl(double[] returnarray, int r, int g, int b) {
double min = Math.min(Math.min(r, g), b);
double max = Math.max(Math.max(r, g), b);
if (max == 0) {
returnarray[0] = 0;
returnarray[1] = 0;
returnarray[2] = 0;
return;
}
double alpha = (min / max) / Y0;
double Q = Math.exp(alpha * gamma);
double rg = r - g;
double gb = g - b;
double br = b - r;
double L = ((Q * max) + ((1 - Q) * min)) / 2;
double C = Q * (Math.abs(rg) + Math.abs(gb) + Math.abs(br)) / 3;
double H = Math.toDegrees(Math.atan2(gb, rg));
/*
//the formulae given in paper, don't work.
if (rg >= 0 && gb >= 0) {
H = 2 * H / 3;
} else if (rg >= 0 && gb < 0) {
H = 4 * H / 3;
} else if (rg < 0 && gb >= 0) {
H = 180 + 4 * H / 3;
} else if (rg < 0 && gb < 0) {
H = 2 * H / 3 - 180;
} // 180 causes the parts to overlap (green == red) and it oddly crumples up bits of the hue for no good reason. 2/3H and 4/3H expanding and contracting quandrants.
*/
if (rg < 0) {
if (gb >= 0) H = 90 + H;
else { H = H - 90; }
} //works
returnarray[0] = H;
returnarray[1] = C;
returnarray[2] = L;
}
public double cycldistance(double[] hcl1, double[] hcl2) {
double dL = hcl1[2] - hcl2[2];
double dH = Math.abs(hcl1[0] - hcl2[0]);
double C1 = hcl1[1];
double C2 = hcl2[1];
return Math.sqrt(dL*dL + C1*C1 + C2*C2 - 2*C1*C2*Math.cos(Math.toRadians(dH)));
}
public double distance_hcl(double[] hcl1, double[] hcl2) {
double c1 = hcl1[1];
double c2 = hcl2[1];
double Dh = Math.abs(hcl1[0] - hcl2[0]);
if (Dh > 180) Dh = 360 - Dh;
double Ach = Dh + Ach_inc;
double AlDl = Al * Math.abs(hcl1[2] - hcl2[2]);
return Math.sqrt(AlDl * AlDl + (c1 * c1 + c2 * c2 - 2 * c1 * c2 * Math.cos(Math.toRadians(Dh))));
//return Math.sqrt(AlDl * AlDl + Ach * (c1 * c1 + c2 * c2 - 2 * c1 * c2 * Math.cos(Math.toRadians(Dh))));
}