2014年9月18日木曜日

RGB←→CIELAB色空間の相互変換

減色処理や固定パレットの環境とかで2色間の距離がほしいとき、RGB色空間よりCIELAB色空間を使った方が目で見て感覚的に近い感じになるっぽい(均等色空間)。

というわけでRGB色空間とCIELAB色空間の相互変換。
流れとしては、RGB → リニアRGB → XYZ → CIELAB と地味にめんどくさい…。

double r; // 0以上1以下の値。
double g;
double b;

double lr = r <= 0.04045d ? r / 12.92d : Math.pow((r + 0.055d) / 1.055d, 2.4d);
double lg = g <= 0.04045d ? g / 12.92d : Math.pow((g + 0.055d) / 1.055d, 2.4d);
double lb = b <= 0.04045d ? b / 12.92d : Math.pow((b + 0.055d) / 1.055d, 2.4d);

double x = 0.4124d * lr + 0.3576d * lg + 0.1805d * lb;
double y = 0.2126d * lr + 0.7152d * lg + 0.0722d * lb;
double z = 0.0193d * lr + 0.1192d * lg + 0.9505d * lb;

double xn = x / 0.95047d;
double yn = y / 1.00000d;
double zn = z / 1.08883d;

double fx = xn > FD ? Math.pow(xn, 1d / 3d) : FK * xn + FV;
double fy = yn > FD ? Math.pow(yn, 1d / 3d) : FK * yn + FV;
double fz = zn > FD ? Math.pow(zn, 1d / 3d) : FK * zn + FV;

double l = 116d * fy - 16d;
double a = 500d * (fx - fy);
double b = 200d * (fy - fz);

double yn = (l + 16d) / 116d;
double xn = yn + a / 500d;
double zn = yn - b / 200d;

double fxn = xn > TD ? Math.pow(xn, 3d) : TK * (xn + TV);
double fyn = yn > TD ? Math.pow(yn, 3d) : TK * (yn + TV);
double fzn = zn > TD ? Math.pow(zn, 3d) : TK * (zn + TV);

double x = fxn * 0.95047d;
double y = fyn * 1.00000d;
double z = fzn * 1.08883d;

double lr =   3.24062547732005470d * x - 1.53720797221031910d * y - 0.49862859869824794d * z;
double lg = - 0.96893071472931970d * x + 1.87575606088524200d * y + 0.04151752384295397d * z;
double lb =   0.05571012044551063d * x - 0.20402105059848677d * y + 1.05699594225438860d * z;

double r = lr <= 0.0031308d ? lr * 12.92d : Math.pow(lr, 1d / 2.4d) * 1.055d - 0.055d;
double g = lg <= 0.0031308d ? lg * 12.92d : Math.pow(lg, 1d / 2.4d) * 1.055d - 0.055d;
double b = lb <= 0.0031308d ? lb * 12.92d : Math.pow(lb, 1d / 2.4d) * 1.055d - 0.055d;

http://en.wikipedia.org/wiki/SRGB
http://en.wikipedia.org/wiki/Illuminant_D65
http://en.wikipedia.org/wiki/Lab_color_space

0 件のコメント:

コメントを投稿