HCL是一个非常通用的名称,有很多方法可以得到色相、色度和亮度。例如,Chroma.js有一个称为HCL的东西,它是将极坐标转换为Lab(当您查看实际代码时)。其他实现,甚至是从同一网站链接的实现,使用Polar Luv。由于您可以简单地借用L因子并通过转换为极坐标来推导色相,这两种方法都是获取这三个元素的有效方式。最好称它们为Polar Lab和Polar Luv,以避免混淆。
M. Sarifuddin(2005)的算法不是极坐标Luv或Polar Lab,计算较为简单(无需先导出Lab或Luv空间),可能更好。文中有些地方似乎是错误的,例如在CIE L*C*H*颜色空间应用欧几里得距离。使用色调意味着它必须是圆形的,并且将该数字直接塞入A²+B²+C²中会给您带来问题。同样的道理也适用于在D94或D00上应用基于色调的颜色空间,因为这些都是具有针对Lab颜色空间的内置修正的距离算法。除非我漏掉了什么,否则我会忽略第6-8图。我对图形中的拒绝容限表示怀疑。您可以设置一个更低的阈值并取得更好的效果,而且颜色空间之间的数值没有归一化。无论如何,尽管论文中有一些看似缺陷,但所描述的算法值得一试。如果RGB并不太重要,您可以选择对其进行欧几里得计算。但如果您正在寻找颜色距离算法,那么这里就有了。
这是M. Sarifuddin用Java实现的HCL。反复阅读论文后,我得出结论:在distance_hcl例程中,它将距离按色相变化比例缩放了0.16至180.16倍。这个因素非常深远,几乎完全不正确。这使得颜色匹配很糟糕。我已经注释掉了论文中的那行,并使用只有Al因子的行。通过将亮度缩放1.4倍,它并不会变得无法使用。如果没有任何缩放因子,它最终与cycldistance完全相同。
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));
if (rg < 0) {
if (gb >= 0) H = 90 + H;
else { H = H - 90; }
}
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))));
}
gamma
的值不清楚。 - Alexey Popkov