色空間の変換(sRGBからLab, XYZ, Yxy)

最初に、著者はこの分野にあまり詳しくないので書かれている内容に誤りがある可能性があります。ですので参考程度にしていただければと思います。


ここではRGB値(正確にはsRGB空間)をLab色空間に変換する方法をご紹介します。

大まかには次のような流れになります。

  1. RGB値をガンマ補正が適用される前のデータ(リニアRGB)に戻す。
  2. RGB値をXYZ空間に変換
  3. XYZ空間からLab空間への変換

まず、こちらのサイト「色空間の変換(2)RGB-XYZ変換」が大変分かりやすく著者も参考にしましたのでご紹介しておきます。


手順1のリニアRGBに戻す関数はPTBに備わっています。(上のリンク先の説明と数値が微妙に異なりますが無視できる程度です)

SRGBGammaUncorrect 

を使ってリニアRGBに変換します。

手順2のRGB値をXYZ空間に変換する関数もPTBに備わっています。

SRGBPrimaryToXYZ

手順3のXYZ空間からLab空間への変換については、「色空間の変換(3)XYZ-Lab変換」が参考になります。ここに記載された内容を元に作成したのが次の関数です。

function [XYZ, xyY, Lab]= mySRGBtoColData(SRGBdata, illumiType)
% 引数SRGBdataは、3つの行ベクトルからなり、それぞれの行がRGBの値(0から255)を取ります。
% SRGBのデータは、D65の光源を想定したデータです。
% 引数illumiTypeは、C光源('C')、D50光源('D50')、D65光源('D65')のいずれかです。
% これら以外の光源を使う場合には、http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
% を参考にソースを書き換えてください。
origRGB = SRGBGammaUncorrect(SRGBdata); % ガンマ補正前のデータに戻す(戻り値は、0から1の範囲のデータであることに注意)
XYZdata = SRGBPrimaryToXYZ(origRGB); % 補正前のRGBの値をXYZに変換。
% 光源が変化する場合には、Bradford変換などを用いて、XYZの色データを変換する必要がある。
% もともとのSRGBのデータは光源がD65であることに注意。
switch illumiType
    case 'C'
        bradfordData = [ % D65 -> C
            1.0097785 0.0070419 0.0127971
            0.0123113 0.9847094 0.0032962
            0.0038284 -0.0072331 1.0891639];
        illuminant = transpose([0.98074 1.00000 1.18232]); % illuminant C
    case 'D50'
        bradfordData = [ % D65 -> D50
            1.0478112 0.0228866 -0.0501270
            0.0295424 0.9904844 -0.0170491
            -0.0092345 0.0150436 0.7521316];

illuminant = transpose([0.96422 1.00000 0.82521]); % D50

    case 'D65'
        bradfordData = eye(3); % 変換の必要なし。

illuminant = transpose([0.95047 1.00000 1.08883]);

    otherwise
        error('Invalid illumiType!');
        %return;
end;
XYZdata = bradfordData * XYZdata; % Bradford変換
Lab = XYZToLab(XYZdata, illuminant); % XYZ -> Lab空間への変換
XYZ = XYZdata .* 100;
xyY = XYZToxyY(XYZ); % XYZ -> xyY空間への変換

この関数では、光源が「C」「D50」「D65」に対応しています。そのほかの光源が必要な場合も同様の手続きで問題ないはずです。

一般的に、RGB色空間ではD65の光源が使われ、Lab色空間ではD50の光源が使われます(例えばPhotoshopなど)。そのため、RGBからLabへの変換では、まずXYZ空間において光源をD65からD50に変換する必要があります。そのときに使われる手法がBradford変換です。

Bradford変換を行ったあと、PTBの関数である

XYZToLab

を使って、Lab空間に変換しています。

また上のコードでは、Labと同時にXYZおよびxyY(Yxyと表されることも多い)空間のデータも取得します。

では、具体的に色空間を変換してみましょう。

変換したいRGB値を各行に記述したCSVファイルを用意します。(1列目にRのデータ、2列目にGのデータ、3列目にBのデータを記入しています)

例えば次のようなものです。

46,29,115

83,23,100

113,13,94

128,128,128

このCSVファイル(rgbData.csvとします)はmySRGBtoColDataと同じフォルダに保存してください。

次のように変換します。

clear all;
dataFileName = 'rgbData.csv'; % RGBのカンマ区切りのデータ
illumiType = 'D50'; % Labの光源の情報。一般的にはD50だが、C または D65 にも対応
illumiType = upper(illumiType); % 小文字から大文字へ
colData = csvread(dataFileName); % CSVファイルから読み取り
[pathstr, fileName, exqt] = fileparts(dataFileName); % 拡張子を取り除いたファイル名を取得。
[XYZ, xyY, Lab]= mySRGBtoColData(transpose(colData), illumiType);
csvwrite([fileName '-Lab-' illumiType '.csv'], transpose(Lab));
csvwrite([fileName '-XYZ-' illumiType '.csv'], transpose(XYZ)); % bradford変換後であることに注意

csvwrite([fileName '-xyY-' illumiType '.csv'], transpose(xyY)); % bradford変換後であることに注意

冒頭でも述べましたように著者はこの分野に明るくないのですが、PhotoshopやMacに付属のDigitalColor Meterを使って、SRGBとLabの値を測定し、その結果とここで公開しているコードによる計算結果とが大きく変わらないことは確認しています。また表色系変換サイトもご紹介しておきます。ただしこちらのサイトは光源の変化に対応していないように思われます。

Labの値をSRGBの値に変換したい場合はこちら

xyYの値をSRGBの値に変換したい場合はこちら