Implementação do CIEDE2000 em bc

Versão da função: v1.0.0
Estatísticas do sítio
Número de visitas667
Número de arquivos visualizados247 + 372

Esta página apresenta uma implementação de referência da fórmula de diferença de cor CIEDE2000 em bc. Se quiser assegurar uma compatibilidade perfeita (até à décima casa decimal) com algumas implementações de terceiros, poderá ter de modificar os comentários no código fonte. Para facilitar isto, a seguinte ligação automatiza esta operação.

Diagrama da fórmula completa do CIEDE2000 com os componentes L*a*b* e os ajustes

A função ΔE2000 em bc

Consideremos a mais comum e académica (Sharma, 2005) das duas formulações.

/* This function written in bc 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. */

m_pi = 0.0

/* 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. */
define ciede_2000(l_1, a_1, b_1, l_2, a_2, b_2) {
	/* Working in Basic Calculator 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... */
	k_l = 1.0
	k_c = 1.0
	k_h = 1.0
	if (m_pi == 0.0) {
		/* Computing pi ... 3.141592653589793238462643383279502884197169399375105820974945
		with arbitrary precision using Machin’s formula proposed in 1706. */
		m_pi =  16.0 * a(0.2) - 4.0 * a(1.0 / 239.0)
	}
	n = (sqrt(a_1 * a_1 + b_1 * b_1) + 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 - sqrt(n / (n + 6103515625.0)))
	/* Application of the chroma correction factor. */
	c_1 = sqrt(a_1 * a_1 * n * n + b_1 * b_1)
	c_2 = sqrt(a_2 * a_2 * n * n + b_2 * b_2)
	/* Using 14 lines to simulate atan2, as bc does not have this built-in. */
	if (0.0 < a_1) {
		h_1 = a(b_1 / (a_1 * n)) + (b_1 < 0.0) * 2.0 * m_pi
	} else if (a_1 < 0.0) {
		h_1 = a(b_1 / (a_1 * n)) + m_pi
	} else {
		h_1 = m_pi + ((b_1 < 0.0) - (0.0 < b_1)) * 0.5 * m_pi
	}
	if (0.0 < a_2) {
		h_2 = a(b_2 / (a_2 * n)) + (b_2 < 0.0) * 2.0 * m_pi
	} else if (a_2 < 0.0) {
		h_2 = a(b_2 / (a_2 * n)) + m_pi
	} else {
		h_2 = m_pi + ((b_2 < 0.0) - (0.0 < b_2)) * 0.5 * m_pi
	}
	/* The atan2 polyfill (customized) is complete. */
	if (h_2 < h_1) { n = h_1 - h_2; } else { n = h_2 - h_1; }
	/* Cross-implementation consistent rounding. */
	if (m_pi - 0.00000000000001 < n && n < m_pi + 0.00000000000001) { n = m_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. */
	h_m = (h_1 + h_2) * 0.5
	h_d = (h_2 - h_1) * 0.5
	if (m_pi < n) {
		h_d = h_d + m_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 = h_m + m_pi
		/* h_m = h_m + ((h_m < m_pi) - (m_pi <= h_m)) * m_pi */
	}
	p = 36.0 * h_m - 55.0 * m_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. */
	r_t = -2.0 * sqrt(n / (n + 6103515625.0)) \
			* s(m_pi / 3.0 * e(p * p / (-25.0 * m_pi * m_pi)))
	n = (l_1 + l_2) * 0.5
	n = (n - 50.0) * (n - 50.0)
	/* Lightness. */
	l = (l_2 - l_1) / (k_l * (1.0 + 0.015 * n / sqrt(20.0 + n)))
	/* These coefficients adjust the impact of different harmonic
	components on the hue difference calculation. */
	t = 1.0 	+ 0.24 * s(2.0 * h_m + m_pi / 2.0) \
			+ 0.32 * s(3.0 * h_m + 8.0 * m_pi / 15.0) \
			- 0.17 * s(h_m + m_pi / 3.0) \
			- 0.20 * s(4.0 * h_m + 3.0 * m_pi / 20.0)
	n = c_1 + c_2
	/* Hue. */
	h = 2.0 * sqrt(c_1 * c_2) * s(h_d) / (k_h * (1.0 + 0.0075 * n * t))
	/* Chroma. */
	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 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 = 30.8   a1 = 22.0   b1 = -4.4
   L2 = 28.1   a2 = 16.4   b2 = 4.3
   CIE ΔE00 = 7.0779305175 (Bruce Lindbloom, Netflix’s VMAF, ...)
   CIE ΔE00 = 7.0779164917 (Gaurav Sharma, OpenJDK, ...)
   Deviation between implementations ≈ 1.4e-5

   See the source code comments for easy switching between these two widely used ΔE*00 implementation variants.
*/

Parâmetros k_l, k_c e k_h

Os parâmetros k_l, k_c e k_h no CIEDE2000 são factores de ponderação aplicados aos termos brilho (ΔL*), croma (ΔC*) e matiz (ΔH*). São definidos como constantes no código fonte. O seu valor predefinido é 1, que corresponde às condições de visualização padrão recomendadas pela Comissão Internacional de Iluminação (CIE). Na prática, pode ser necessário ajustar estes coeficientes para refletir condições específicas: por exemplo, k_l = 2 é por vezes utilizado para dar mais peso a diferenças de brilho (uma ocorrência comum na indústria têxtil), enquanto k_c ou k_h podem ser reduzidos para aumentar a tolerância a variações de saturação ou matiz, dependendo dos requisitos. Estes coeficientes variam normalmente entre 0,5 e 2.

Precisão e fiabilidade do código fonte

A diferença entre a formulação académica de Sharma e a formulação simplificada de Lindbloom não excede ±0,0003 no ΔE2000 final. Isto corresponde à diferença normalmente medida entre duas implementações de 32 bits e é impercetível ao olho humano. As nossas implementações de 64 bits, todas consistentes entre si, garantem pelo menos 10 casas decimais corretas, pelo que a escolha de uma formulação em detrimento de outra é um pormenor técnico. A fórmula predefinida nesta página é a mais frequentemente apresentada na comunidade, é ligeiramente mais fácil de vetorizar.

Se verificar que os comentários no código-fonte não coincidem com os comentários em inglês, informe o autor da página para que tal possa ser corrigido.

Como é que se convertem cores RGB em L*a*b*?

Vá para a página AWK, C, Dart, Java, JavaScript, Kotlin, Lua, PHP, Python, Ruby ou Rust onde esse conversor (utilizando o iluminante D65) já está implementado para além da função de comparação de cores.

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.

Exemplo de duas cores que apresentam uma diferença apenas percetível (JND) de acordo com CIEDE2000
Cor 1Cor 2Valor de ΔE2000
1
2
3
Exemplos de valores CIEDE2000 calculados entre duas cores distintas
Cor 1Cor 2Valor de ΔE2000
5
10
15

Δ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 bc

echo 'scale=50;ciede_2000(13.1, 11.9, 3.8, 13.0, 17.6, -4.9)' | bc -l ciede-2000.bc

# Outputs: 7.37458016458016885544127036110301868134320454640263
# As explained in the comments, compliance with Gaurav Sharma would display ...
# ........ 7.37456659946646273510289154231355556542867583609039

Resultados dos testes

Esta função bc foi testada com o driver Julia de precisão múltipla concebido para este fim.

CIEDE2000 Verification Summary :
  First Verified Line : 27,-123,101,44,42.0000098,-99,70.204734814936909810694644954670527048474482887
             Duration : 18644.34 s
            Successes : 10000000
               Errors : 0
      Average Delta E : 62.9618
    Average Deviation : 4.0e-38
    Maximum Deviation : 2.2e-35

Ficheiros para descarregar

Um ficheiro abaixo suporta cálculos de precisão arbitrária em bc (útil se estiver a lidar com ΔE2000 em metrologia). Pode utilizar livremente estes ficheiros disponibilizados pelo Michel, mesmo para fins comerciais.

Estatísticas do sítio : downloads de ficheiros
ArquivoTamanhoNúmero de cliques
ciede-2000.bc4 KB110
test-bc-arbitrary.yml7 KB76
test-bc-standard.yml5 KB61
reference-dataset.txt4 KB372
Clique em bc.zip para baixar todos estes arquivos em um arquivo.

Comunidade

O que pensa deste código fonte ou do CIEDE2000? A sua opinião é importante para nós! O livro de visitas já contém 9 mensagens - incluindo 1 em português. Dê uma vista de olhos e partilhe a sua opinião.