Edited at

JavaScriptでCIEDE2000色差計算

More than 1 year has passed since last update.

Color difference(wikipedia)で公開されているCIEDE2000の色差計算式をJavaScriptで書いてみました

wikipediaで公開されている計算式は以下のとおりです。


CIE2000

(「Color difference」(5 Feb 2017, at 02:30. UTC)『ウィキペディア』より引用)


2000というくらいですからきっといちばん新しいのではないかと思うのですがユークリッドCIE76CIE94と比較してかなり複雑な印象を受ける計算式です。実際のプログラムも複雑なものとなりました。


ciede2000

function ciede2000(L1,a1,b1, L2,a2,b2, kL=1,kC=1,kH=1) {

//http://en.wikipedia.org/wiki/Color_difference#CIEDE2000
var radianToDegree = function(radian) {return radian * (180 / Math.PI);};
var degreeToRadian = function(degree) {return degree * (Math.PI / 180);};

var deltaLp = L2 - L1;
var L_ = (L1 + L2) / 2;
var C1 = Math.sqrt(Math.pow(a1, 2) + Math.pow(b1, 2));
var C2 = Math.sqrt(Math.pow(a2, 2) + Math.pow(b2, 2));
var C_ = (C1 + C2) / 2;
var ap1 = a1 + (a1 / 2) *
(1 - Math.sqrt(
Math.pow(C_, 7) /
(Math.pow(C_, 7) + Math.pow(25, 7))
)
);
var ap2 = a2 + (a2 / 2) *
(1 - Math.sqrt(
Math.pow(C_, 7) /
(Math.pow(C_, 7) + Math.pow(25, 7))
)
);
var Cp1 = Math.sqrt(Math.pow(ap1, 2) + Math.pow(b1, 2));
var Cp2 = Math.sqrt(Math.pow(ap2, 2) + Math.pow(b2, 2));
var Cp_ = (Cp1 + Cp2) / 2;
var deltaCp = Cp2 - Cp1;

var hp1;
if (b1 == 0 && ap1 == 0) {
hp1 = 0;
} else {
hp1 = radianToDegree(Math.atan2(b1, ap1));
if (hp1 < 0) {hp1 = hp1 + 360;}
}
var hp2;
if (b2 == 0 && ap2 == 0) {
hp2 = 0;
} else {
hp2 = radianToDegree(Math.atan2(b2, ap2));
if (hp2 < 0) {hp2 = hp2 + 360;}
}

var deltahp;
if (C1 == 0 || C2 == 0) {
deltahp = 0;
} else if (Math.abs(hp1 - hp2) <= 180) {
deltahp = hp2 - hp1;
} else if (hp2 <= hp1) {
deltahp = hp2 - hp1 + 360;
} else {
deltahp = hp2 - hp1 - 360;
}

var deltaHp = 2 * Math.sqrt(Cp1 * Cp2) * Math.sin(degreeToRadian(deltahp) / 2);

var Hp_;
if (Math.abs(hp1 - hp2) > 180) {
Hp_ = (hp1 + hp2 + 360) / 2
} else {
Hp_ = (hp1 + hp2) / 2
};

var T = 1 -
0.17 * Math.cos(degreeToRadian(Hp_ - 30)) +
0.24 * Math.cos(degreeToRadian(2 * Hp_)) +
0.32 * Math.cos(degreeToRadian(3 * Hp_ + 6)) -
0.20 * Math.cos(degreeToRadian(4 * Hp_ - 63));

var SL = 1 + (
(0.015 * Math.pow(L_ - 50, 2)) /
Math.sqrt(20 + Math.pow(L_ - 50, 2))
);
var SC = 1 + 0.045 * Cp_;
var SH = 1 + 0.015 * Cp_ * T;

var RT = -2 *
Math.sqrt(
Math.pow(Cp_, 7) /
(Math.pow(Cp_, 7) + Math.pow(25, 7))
) *
Math.sin(degreeToRadian(
60 * Math.exp(-Math.pow((Hp_ - 275) / 25, 2))
));

return Math.sqrt(
Math.pow(deltaLp / (kL * SL), 2) +
Math.pow(deltaCp / (kC * SC), 2) +
Math.pow(deltaHp / (kH * SH), 2) +
RT * (deltaCp / (kC * SC)) * (deltaHp / (kH * SH))
);
}


CIEDE2000はLabの値が必要となりますので、実際に使うにはJavaScriptでCIE76色差計算と同様にJavaScriptでRGBからLab色空間への変換を使ってRGBからLabへの変換する必要があります。以下のような感じになると思います。

var [L1, a1, b1] = rgbToLab(r1, g1, b1);

var [L2, a2, b2] = rgbToLab(r2, g2, b2);
distance = ciede2000(L1,a1,b1, L2,a2,b2);

または

distance = ciede2000.apply(this, 

rgbToLab(r1,g1,b1).concat(rgbToLab(r2,g2,b2))
)

です。


関連リンク