Implementação do CIEDE2000 em Java
| Número de visitas | 641 |
|---|---|
| Número de arquivos visualizados | 690 + 308 |
Esta página apresenta uma implementação de referência da fórmula de diferença de cor CIEDE2000 em Java. Se desejar obter uma correspondência exacta com implementações de terceiros até 10 casas decimais, poderá ter de fazer algumas alterações ao código-fonte, em particular comentando e descomentando algumas linhas, que podem ser aplicadas automaticamente através da ligação abaixo.
A função ΔE2000 em Java
Consideremos a mais comum e académica (Sharma, 2005) das duas formulações.
// This function written in Java is not affiliated with the CIE (International Commission on Illumination),
// and is released into the public domain. It is provided "as is" without any warranty, express or implied.
// The classic CIE ΔE2000 implementation, which operates on two L*a*b* colors, and returns their difference.
// "l" ranges from 0 to 100, while "a" and "b" are unbounded and commonly clamped to the range of -128 to 127.
static double ciede_2000(final double l_1, final double a_1, final double b_1, final double l_2, final double a_2, final double b_2) {
// Working in Java with the CIEDE2000 color-difference formula.
// k_l, k_c, k_h are parametric factors to be adjusted according to
// different viewing parameters such as textures, backgrounds...
final double k_l = 1.0, k_c = 1.0, k_h = 1.0;
double n = (Math.sqrt(a_1 * a_1 + b_1 * b_1) + Math.sqrt(a_2 * a_2 + b_2 * b_2)) * 0.5;
n = n * n * n * n * n * n * n;
// A factor involving chroma raised to the power of 7 designed to make
// the influence of chroma on the total color difference more accurate.
n = 1.0 + 0.5 * (1.0 - Math.sqrt(n / (n + 6103515625.0)));
// Application of the chroma correction factor.
final double c_1 = Math.sqrt(a_1 * a_1 * n * n + b_1 * b_1);
final double c_2 = Math.sqrt(a_2 * a_2 * n * n + b_2 * b_2);
// atan2 is preferred over atan because it accurately computes the angle of
// a point (x, y) in all quadrants, handling the signs of both coordinates.
double h_1 = Math.atan2(b_1, a_1 * n), h_2 = Math.atan2(b_2, a_2 * n);
h_1 += 2.0 * Math.PI * Boolean.compare(h_1 < 0.0, false);
h_2 += 2.0 * Math.PI * Boolean.compare(h_2 < 0.0, false);
n = Math.abs(h_2 - h_1);
// Cross-implementation consistent rounding.
if (Math.PI - 1E-14 < n && n < Math.PI + 1E-14)
n = Math.PI;
// When the hue angles lie in different quadrants, the straightforward
// average can produce a mean that incorrectly suggests a hue angle in
// the wrong quadrant, the next lines handle this issue.
double h_m = (h_1 + h_2) * 0.5, h_d = (h_2 - h_1) * 0.5;
if (Math.PI < n) {
h_d += Math.PI;
// 📜 Sharma’s formulation doesn’t use the next line, but the one after it,
// and these two variants differ by ±0.0003 on the final color differences.
h_m += Math.PI;
// h_m += h_m < Math.PI ? Math.PI : -Math.PI;
}
final double p = 36.0 * h_m - 55.0 * Math.PI;
n = (c_1 + c_2) * 0.5;
n = n * n * n * n * n * n * n;
// The hue rotation correction term is designed to account for the
// non-linear behavior of hue differences in the blue region.
final double r_t = -2.0 * Math.sqrt(n / (n + 6103515625.0))
* Math.sin(Math.PI / 3.0 * Math.exp(p * p / (-25.0 * Math.PI * Math.PI)));
n = (l_1 + l_2) * 0.5;
n = (n - 50.0) * (n - 50.0);
// Lightness.
final double l = (l_2 - l_1) / (k_l * (1.0 + 0.015 * n / Math.sqrt(20.0 + n)));
// These coefficients adjust the impact of different harmonic
// components on the hue difference calculation.
final double t = 1.0 + 0.24 * Math.sin(2.0 * h_m + Math.PI * 0.5)
+ 0.32 * Math.sin(3.0 * h_m + 8.0 * Math.PI / 15.0)
- 0.17 * Math.sin(h_m + Math.PI / 3.0)
- 0.20 * Math.sin(4.0 * h_m + 3.0 * Math.PI / 20.0);
n = c_1 + c_2;
// Hue.
final double h = 2.0 * Math.sqrt(c_1 * c_2) * Math.sin(h_d) / (k_h * (1.0 + 0.0075 * n * t));
// Chroma.
final double c = (c_2 - c_1) / (k_c * (1.0 + 0.0225 * n));
// Returning the square root ensures that dE00 accurately reflects the
// geometric distance in color space, which can range from 0 to around 185.
return Math.sqrt(l * l + h * h + c * c + c * h * r_t);
}
// GitHub Project : https://github.com/michel-leonard/ciede2000-color-matching
// Online Tests : https://michel-leonard.github.io/ciede2000-color-matching
// L1 = 24.8 a1 = 36.7 b1 = -3.4
// L2 = 23.9 a2 = 31.4 b2 = 4.1
// CIE ΔE00 = 4.9864120463 (Bruce Lindbloom, Netflix’s VMAF, ...)
// CIE ΔE00 = 4.9863986991 (Gaurav Sharma, OpenJDK, ...)
// Deviation between implementations ≈ 1.3e-5
// See the source code comments for easy switching between these two widely used ΔE*00 implementation variants.Precisão e fiabilidade do código fonte
A diferença entre as formulações de Sharma e Lindbloom nunca excede ±0,0003 no ΔE2000 final, o que corresponde à diferença habitual medida entre duas implementações de 32 bits e é imperceptível ao olho humano. Nossas implementações de 64 bits, todas consistentes entre si, garantem pelo menos 10 casas decimais corretas, de modo que a escolha de uma formulação em vez de outra depende principalmente da interoperabilidade desejada. A formulação que aparece por defeito nesta página é a mais utilizada (a sua microvantagem reside na sua ancoragem comunitária e na sua maior leveza do que a do seu análogo quando vectorizado).
✎ Se encontrar um comentário no código-fonte que não corresponda a outra língua, informe o autor do sítio, que estudará a sua sugestão e a incorporará no código-fonte.
Como é que se convertem cores RGB em L*a*b*?
Terá de utilizar o espaço de cor intermédio XYZ para a conversão e, se precisar de ajuda, o código fonte é fornecido no final desta página (utilizando o ponto branco D65 formalizado em 1964).
Intervalos de valores no CIELAB e interpretação do ΔE2000
No espaço de cor CIELAB, o componente L* representa a luminosidade e normalmente varia de 0 (preto) a 100 (branco). Os componentes a* e b* representam os eixos de cor: a* vai do verde ao vermelho, enquanto b* vai do azul ao amarelo. Na prática, os valores de a* e b* costumam estar entre -128 e +127, embora possam ultrapassar ligeiramente esses limites dependendo da conversão de cor.
| Cor 1 | Cor 2 | Valor de ΔE2000 |
|---|---|---|
| 1 | ||
| 2 | ||
| 3 |
| Cor 1 | Cor 2 | Valor de ΔE2000 |
|---|---|---|
| 5 | ||
| 10 | ||
| 15 |
Parâmetros k_l, k_c e k_h
Os parâmetros k_l, k_c e k_h são fatores de ponderação aplicados aos termos de luminosidade (ΔL*), croma (ΔC*) e matiz (ΔH*) na fórmula CIEDE2000. O seu valor padrão é 1, o que corresponde às condições de observação padrão recomendadas pela Comissão Internacional de Iluminação. Na prática, estes coeficientes são ajustados para refletir condições específicas: por exemplo, k_l = 2 é por vezes usado para dar mais peso às diferenças de luminosidade (comum em impressão), enquanto k_c ou k_h podem ser reduzidos para aumentar a tolerância a variações de saturação ou matiz conforme as exigências do controlo de qualidade. Dependendo do contexto, estes coeficientes variam tipicamente entre 0,5 e 2.
ΔE2000 (CIEDE2000) mede a diferença perceptível entre duas cores: 0 significa cores idênticas, e valores maiores (até cerca de 185 em casos extremos) indicam uma diferença mais significativa. Por exemplo, um valor ΔE2000 em torno de 5 indica cores próximas, enquanto em torno de 15 indica cores claramente diferentes.
Exemplo de utilização em Java
// Compute the Delta E (CIEDE2000) color difference between two L*a*b* colors in Java
// Color 1: l1 = 6.3 a1 = 39.4 b1 = 3.6
// Color 2: l2 = 6.5 a2 = 33.4 b2 = -2.0
double deltaE = ciede_2000(l1, a1, b1, l2, a2, b2);
System.out.println(deltaE);
// .................................................. This shows a ΔE2000 of 3.9368581959
// As explained in the comments, compliance with Gaurav Sharma would display 3.9368724643Resultados dos testes
O driver escrito na linguagem C99, com 250 testes estáticos precisos, provou que esta função Java é interoperável com a função CIEDE2000 disponível noutras linguagens de programação.
CIEDE2000 Verification Summary :
First Verified Line : 93.6,-78,-117.9,12,-93,-7.72,86.22963867911595000
Duration : 59.55 s
Successes : 10000000
Errors : 0
Average Delta E : 62.9317
Average Deviation : 5.3488200396634159e-15
Maximum Deviation : 2.8421709430404007e-13Ficheiros para descarregar
Pode utilizar livremente estes ficheiros disponibilizados pelo Michel, mesmo para fins comerciais.
| Arquivo | Tamanho | Número de cliques |
|---|---|---|
| ciede-2000.java | 4 KB | 85 |
| ciede-2000-driver.java | 6 KB | 79 |
| ciede-2000-random.java | 6 KB | 78 |
| compare-hex-colors.java | 10 KB | 78 |
| compare-rgb-colors.java | 10 KB | 80 |
| stdin-verifier.java | 7 KB | 80 |
| test-java.yml | 3 KB | 70 |
| vs-openimaj.yml | 4 KB | 74 |
| vs-openjdk.yml | 5 KB | 66 |
| reference-dataset.txt | 4 KB | 308 |
| Clique em java.zip para baixar todos estes arquivos em um arquivo. | ||
Comunidade
Se quiser deixar a sua opinião sobre este código fonte Java ou sobre o CIEDE2000 em geral, o livro de visitas já contém 1 mensagens em português, e 9 mensagens no total, por isso diga-nos o que pensa.