Implementación de CIEDE2000 en C#

Versión de la función: v1.0.0
Estadísticas del sitio
Número de visitas741
Número de archivos consultados539 + 373

Esta página presenta una implementación de referencia de la fórmula de diferencia de color CIEDE2000 en C#. Si desea garantizar una compatibilidad perfecta (hasta el décimo decimal) con algunas implementaciones de terceros, es posible que tenga que modificar los comentarios del código fuente. Para facilitarlo, el siguiente enlace automatiza esta operación.

Diagrama de la fórmula CIEDE2000 completa con los componentes L*a*b* y los ajustes

La función ΔE2000 en C#

Consideremos la más común y académica (Sharma, 2005) de las dos formulaciones.

// Esta función escrita en C# es de dominio público y no
// está afiliada a la CIE (Comisión Internacional de Iluminación).

// La implementación clásica de CIEDE2000 que recibe dos colores L*a*b* y devuelve su diferencia.
// El componente "L" varía de 0 a 100. "a" y "b" normalmente se proyectan entre -128 y 127.
static double ciede_2000(double l_1, double a_1, double b_1, double l_2, double a_2, double b_2) {
	// Ejecuta el cálculo de diferencia de color CIEDE2000 en C# (.NET Core).
	// k_l, k_c y k_h son factores paramétricos a ajustar según
	// sus necesidades de visualización (texturas, fondos).
	const 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;
	// Un factor que implica la croma elevada a la potencia 7,
	// diseñado para tener más en cuenta la influencia de la croma.
	n = 1.0 + 0.5 * (1.0 - Math.Sqrt(n / (n + 6103515625.0)));
	// Aplicación del factor de corrección de la croma para compensar su no linealidad.
	double c_1 = Math.Sqrt(a_1 * a_1 * n * n + b_1 * b_1);
	double c_2 = Math.Sqrt(a_2 * a_2 * n * n + b_2 * b_2);
	// La función atan2 es preferible a atan porque calcula el ángulo de un
	// punto (x, y) en todos los cuadrantes, teniendo en cuenta el signo de x e y.
	double h_1 = Math.Atan2(b_1, a_1 * n), h_2 = Math.Atan2(b_2, a_2 * n);
	if (h_1 < 0.0) h_1 += 2.0 * Math.PI;
	if (h_2 < 0.0) h_2 += 2.0 * Math.PI;
	n = Math.Abs(h_2 - h_1);
	// Evita que la rama dependa del RoundingMode del lenguaje de programación.
	if (Math.PI - 1E-14 < n && n < Math.PI + 1E-14)
		n = Math.PI;
	// Cuando los ángulos de tono se encuentran en diferentes cuadrantes,
	// la media aritmética simple puede dar un ángulo incorrecto, las
	// líneas siguientes aplican la corrección angular necesaria.
	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;
		// 📜 La formulación de Sharma no utiliza la línea siguiente, sino la que le sigue.
		// Nota: estas dos variantes sólo difieren en ±0,0003 en la diferencia de color final.
		h_m += Math.PI;
		// if (h_m < Math.PI) h_m += Math.PI; else h_m -= Math.PI;
	}
	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;
	// El término de corrección de la rotación del tono mejora la precisión
	// del algoritmo, especialmente cuando la comparación se refiere a azules.
	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);
	//  Luminosidad .
	double l = (l_2 - l_1) / (k_l * (1.0 + 0.015 * n / Math.Sqrt(20.0 + n)));
	// Estos coeficientes se utilizan para modular la influencia de
	// los componentes armónicos en el cálculo de la diferencia de tono.
	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;
	// Tono.
	double h = 2.0 * Math.Sqrt(c_1 * c_2) * Math.Sin(h_d) / (k_h * (1.0 + 0.0075 * n * t));
	// Croma.
	double c = (c_2 - c_1) / (k_c * (1.0 + 0.0225 * n));
	// Devolver la raíz cuadrada garantiza que dE00 representa una distancia
	// geométrica (que va de 0 a aproximadamente 185) en el espacio CIELAB.
	return Math.Sqrt(l * l + h * h + c * c + c * h * r_t);
}

//    Proyecto GitHub : https://github.com/michel-leonard/ciede2000-color-matching
//   Pruebas en línea : https://michel-leonard.github.io/ciede2000-color-matching

// L1 = 32.3   a1 = 41.7   b1 = -1.7
// L2 = 32.2   a2 = 35.7   b2 = 1.6
// CIE ΔE00 = 2.8793148397 (Bruce Lindbloom, Netflix’s VMAF, ...)
// CIE ΔE00 = 2.8793013851 (Gaurav Sharma, OpenJDK, ...)
// Desviación entre implementaciones ≈ 1.3e-5

// Consulte los comentarios del código fuente para pasar de una de estas variantes de implementación ΔE*00 a la otra.

Parámetros k_l, k_c y k_h

Los parámetros k_l, k_c y k_h en CIEDE2000 son factores de ponderación aplicados a los términos brillo (ΔL*), croma (ΔC*) y tono (ΔH*). Se definen como constantes en el código fuente. Su valor por defecto es 1, que corresponde a las condiciones de visualización estándar recomendadas por la Comisión Internacional de Iluminación (CIE). En la práctica, puede ser necesario ajustar estos coeficientes para reflejar condiciones específicas: por ejemplo, k_l = 2 se utiliza a veces para dar más peso a las diferencias de brillo (algo habitual en la industria textil), mientras que k_c o k_h pueden reducirse para aumentar la tolerancia a las variaciones de saturación o tono, según los requisitos. Según el contexto, estos coeficientes suelen oscilar entre 0,5 y 2.

Precisión y fiabilidad del código fuente

La diferencia entre la formulación académica de Sharma y la simplificada de Lindbloom no supera ±0,0003 en el ΔE2000 final. Esto corresponde a la diferencia que suele medirse entre dos implementaciones de 32 bits y es imperceptible para el ojo humano. Nuestras implementaciones de 64 bits, todas coherentes entre sí, garantizan al menos 10 decimales correctos, por lo que la elección de una formulación sobre la otra es un detalle técnico. La fórmula por defecto de esta página es la que se presenta con más frecuencia en la comunidad, es ligeramente más fácil de vectorizar.

Si observáis que los comentarios del código fuente no coinciden con los comentarios en inglés, por favor, informad al autor de la página para que pueda corregirlo.

¿Cómo se convierten los colores RGB a L*a*b*?

Vaya a la página AWK, C, Dart, Java, JavaScript, Kotlin, Lua, PHP, Python, Ruby o Rust, donde ya está implementado dicho conversor (que utiliza el iluminante D65), además de la función de comparación de colores.

Rangos de valores en CIELAB e interpretación del ΔE2000

En el espacio de color CIELAB, el componente L* representa la luminosidad y suele variar de 0 (negro) a 100 (blanco). Los componentes a* y b* definen los ejes de color: a* va del verde al rojo, y b* del azul al amarillo. En la práctica, a* y b* se encuentran normalmente entre -128 y +127, aunque pueden superar ligeramente estos límites según la conversión de color.

Ejemplo de dos colores que presentan una diferencia apenas perceptible (JND) según CIEDE2000
Color 1Color 2Valor de ΔE2000
1
2
3
Ejemplos de valores CIEDE2000 calculados entre dos colores distintos
Color 1Color 2Valor de ΔE2000
5
10
15

ΔE2000 (CIEDE2000) cuantifica la diferencia perceptible entre dos colores: 0 significa que son idénticos, y valores más altos (hasta aproximadamente 185 en casos extremos) indican una diferencia más notable. Por ejemplo, un ΔE2000 alrededor de 5 indica colores cercanos, mientras que alrededor de 15 indica colores claramente distintos.

Ejemplo de uso en C#

// Compute the Delta E (CIEDE2000) color difference between two L*a*b* colors in C# (.NET Core)

double l1 = 95.3,  a1 = 39.2,  b1 = -1.7;
double l2 = 94.8,  a2 = 45.0,  b2 = 2.1;

double deltaE = ciede_2000(l1, a1, b1, l2, a2, b2);
Console.WriteLine(deltaE);

// .................................................. This shows a ΔE2000 of 2.8916930349
// As explained in the comments, compliance with Gaurav Sharma would display 2.8917067928

Los resultados de las pruebas

El controlador escrito en lenguaje C99, con 250 pruebas estáticas precisas, ha demostrado que esta función C# es interoperable con la función CIEDE2000 disponible en otros lenguajes de programación.

CIEDE2000 Verification Summary :
  First Verified Line : 65,44.1,69,8.3,-46.8,-22.9,72.86971426109767
             Duration : 32.12 s
            Successes : 10000000
               Errors : 0
      Average Delta E : 62.9416
    Average Deviation : 4.2567882330146744e-15
    Maximum Deviation : 1.1368683772161603e-13

Archivos para descargar

Siéntase libre de utilizar estos archivos puestos a disposición por Michel, incluso con fines comerciales.

Estadísticas del sitio : descargas de archivos
ArchivoTamañoNúmero de clics
ciede-2000.cs4 KB112
ciede-2000-driver.cs5 KB103
ciede-2000-random.cs6 KB100
ciede-2000-single-precision.cs5 KB100
test-cs.yml3 KB61
vs-masuit-tools.yml5 KB63
reference-dataset.txt4 KB373
Haga clic en cs.zip para descargar todos estos archivos en un archivo.

Comunidad

¿Qué opina de este código fuente o de CIEDE2000? Su opinión es importante para nosotros. El libro de visitas ya contiene 9 mensajes - incluyendo 1 en español. Eche un vistazo y comparta su opinión.