ディスプレイの色校正について


2021/04/16
鯉田孝和 (豊橋技科大) koida@tut.jp

 視覚心理物理実験や神経生理実験、画像評価実験では画像を正しく表示することが重要である。正しくと言うのは、計画通りの色と輝度をコンピューターディスプレイに表示することである。それには、画面の測光と、少しややこしい計算が必要となる。この測定と計算の作業をまとめて、ディスプレイのキャリブレーション、測光、色校正などと呼ぶ。本ドキュメントでは、ディスプレイを用いた際のキャリブレーションの手続きについて説明する。
 ここでは一般的なwindowsパソコンとディスプレイを用いることを前提に説明する。

キャリブレーションの計算は、以下の二つの手続きから成り立っている。


名称の定義: 

 Digit(ディジット)
 R=0~255 の入力値のこと。
 RGB
画像データやディスプレイの基本構成光であるRed, Green, Blueのこと。
 X, Y, Z, Lum, x, y
CIE(1931)の三刺激値XYZと輝度と色度xy。大文字のXと小文字のxは異なることに注意。
 L, M, S
人間のL,M,S錐体の感度を基にした刺激値。

(1) 対応付け

Rの値を0~255まで順番に増やしていっても、輝度は線形には増加しない。暗いところではゆっくり明るくなっていき、明るいところは急激に変化している(上図参照)。これは人の目に見分けがつく諧調変化としておおよそ等間隔になるような特性を持たせているからである。特性に国際規格はあるが、ディスプレイごとに個体差があって正確には測定するほかない。

 究極的にはR, G, Bの各phosphorごとに、0~max まで、全階調で輝度を測定すればよい。そして、必要な輝度(例えば20cd/m2とか)に対して最も近い輝度を与えるdigitを読みとればよい。この方式をルックアップテーブル形式と呼んだりする。

 全階調の測定には手間と時間が掛かることから、実際は適当に階調を区切って測定する事が多い。256階調に対して8もしくは16刻みで測定すれば良いだろう。測定は少し間を置いて3回程度繰り返して平均すると良い。理想的には測定の順番をランダムにした方が良い。これは昨今のディスプレイはコンテンツに応じて光の強度を変える特性があるからである。測定時には全画面の色を変えるのではなく、周辺に灰色を表示し、測定する中央部のみ諧調を変えて測定するとさらに良い。周辺の灰色は実際の実験時に用いる背景色に近づけておけば良いだろう。

 離散的に測定した場合、区間をどのように補間するかにはいくつかの方法がある。

1.1 リニア補間によるルックアップテーブル作成 

簡単で実効性が高い。一般的なディスプレイでも輝度とdigitの両方で対数を取ってから線形近似すればさらに良い。注意点としては、digitに対して測定された輝度が単調増加になっていることを確認すること。特に暗い値では装置の問題や測定誤差によって値が上下することがよくある。単調増加していないケースでは必要な輝度に対して入力するdigitが一意に決まらないことになってしまう。そのようなディスプレイは実験に用いないか、単調増加する範囲のみで画像を表示するべできである。

1.2 べき関数フィッティング

一般的な(理想的な)パソコンの環境では、Digitと輝度の間に、次のべき乗関係式がある。

    Lum = Digitγ    ※ただしLum=0~1、Digit=0~1とノーマライズする。

このγがsRGB規格だとγ=2.2程度となる。ただし本来のsRGB規格はもうすこし複雑である(Wikipedia) sRGB)。
γというのべき乗の係数のことであり、数学のガンマ関数とは関係ない。

べき乗関係式は、両対数グラフにプロットするとわかりやすくなる。
logを取ると、
  log(Lum) = log( Digitγ )

  log(Lum) = γ ・ log( Digit )

つまり、y = γ・x という直線の式なのである。
しかし実際には直線では近似が悪いため、二次式で近似することが多い。

  log(Lum) = a ・ (log( Digit ))2 + b ・ log( Digit )

matlab等の多項式フィッティングで係数のa,bを求めればよいだろう。y切片が0であることに注意。polyfitではy切片を0にできない(と思う)ので差分の最小2乗で微分して極値を求めればよい。計算すると以下のようになる。

a= (sum(x.^2)*sum(x.^2.*y) - sum(x.^3.*sum(x.*y))) / (sum(x.^4)*sum(x.^2) - sum(x.^3)*sum(x.^3));
b= (-a.*sum(x.^3) + sum(x.*y)) / sum(x.^2);
ただしx=log10(digit),y=log10(luminance)である。 また、Digitにゼロを入力するとlog(Digit)がマイナス∞になってしまうい取り扱いが困るので、ゼロは近似に用いない。

ちなみに正確なsRGBの定義に従った輝度は下図のようになる(青点)。ここにγ2.2のべき乗曲線(赤線)と両対数二次関数フィット曲線(緑)を重ねる。線形輝度軸ではどちらでも似たようなものだが、両対数軸では二次関数のほうがフィットしていることがわかるだろう。暗いところで差が顕著なのは対数軸-1以下で、線形なら0.1以下、255諧調でいうなら25以下である。この暗い領域のズレが問題になるのは暗い刺激と鮮やかな刺激である。


図(左)digit-輝度の線形グラフ。(中)片対数グラフ。(右)両対数グラフ。
青点がsRGB、赤線がγ2.2のべき関数、緑線が両対数二次関数近似式。

 これらの近似式、あるいは近似式から求めた対応表を用いて、必要な輝度に対応するDigitを読み出せるようにすればよい。



(2) RGBをいかに混ぜればよいのか

 CRTディスプレイはR,G,Bの光を混ぜ合わすと、加法混色が起こる。10cd/m2のRと、20cd/m2のGとを混ぜれば、30cd/m2の黄色っぽい色になる。このような線形加算性は色の三刺激値,X, Y, Zで有効である。つまり、


加法混色した X = (Redから出るX) + (Greenから出るX) + (Blueから出るX)
加法混色した Y = (Redから出るY) + (Greenから出るY) + (Blueから出るY)          (式1)
加法混色した Z = (Redから出るZ) + (Greenから出るZ) + (Blueから出るZ)

 この線形関係のおかげで、欲しい輝度・色度(に対応するX,Y,Z)を出すためのR,G,Bの各強度を求めることができる。ポイントは、Rのx,yは一定、Gのx,yは一定、Bのx,yは輝度によらず一定ということ。


 以下に、実際の計算方法を説明する。まず基本である三刺激値の変換式を以下に示す。

 三刺激値の変換:
x = X / (X+Y+Z)   
y = Y / (X+Y+Z)
Luminance = Y
X = Lum * x/y
Y = Lum
Z = Lum * (1-x-y)/y

 例えばRedの強さだけを変えると(G,Bはゼロとする)、明るさは変わるが色は変わらない。これを正確に言うと輝度は変わるが色度は変わらない。ここでRedの輝度をLumred、一定な色度をxred、yredと記述することにする。上記の三刺激値の変換式(右側)に代入すると、red由来の三刺激値(Xred, Yred, Zred)は以下のように表せる。

 
Xred = Lumred * xred / yred
Yred = Lumred
Zred = Lumred * (1 - xred - yred) / yred

 xred、yred は、RのDigit=maxとしたときの色度から求めればよい。同様にxgreen、ygreen についても、GのDigit=maxにして測定すればよい。xblue、yblue もBのDigit=maxにして測定すればよい。

 求めたRGBそれぞれの三刺激値を式1に代入する。


目的の X = Lumred * xred / yred  + Lumgreen * xgreen / ygreen  + Lumblue * xblue / yblue
目的の Y = Lumred       +  Lumgreen       +  Lumblue
目的の Z = Lumred * zred / yred  + Lumgreen * zgreen / ygreen  + Lumblue * zblue / yblue
             ※ここで、z = (1 - x - y) とした。(書きやすさのため)

 ここまでくれば、三つの式に変数が三つ(Lumred, Lumgreen, Lumgreen )なので、がんばって連立方程式として解くことができる。

 というのも大変なので、実際はこの方程式を行列に置き換えて、逆行列を求めることが多い。上記の式を変形すると、(ここで縦ベクトルの分離を;で示す)

目的の X = ( xred / yred , xgreen / ygreen , xblue / yblue) * (Lumred; Lumgreen; Lumblue )
目的の Y = (1 , 1 , 1) * (Lumred; Lumgreen; Lumblue)
目的の Z = (zred / yred , zgreen / ygreen , zblue / yblue ) * (Lumred; Lumgreen; Lumblue )

さらに行列の乗算に変形

[ 目的の X
目的の Y
目的の Z
] = [ xred / yred ,  xgreen / ygreen ,  xblue / yblue
1 , 1 , 1
zred / yred ,  zgreen / ygreen ,  zblue / yblue
] * [ Lumred
Lumgreen
Lumblue
]

ここで 3x3行列 の部分は輝度によらない定数であることに着目する。すると逆行列が求められるので、


 [X; Y; Z] = [行列] * [ Lumred; Lumgreen; Lumblue]     

 inv([行列]) * [X; Y; Z] = [ Lumred; Lumgreen; Lumblue]  

 この式を用いれば、目的のXYZを代入するだけで、混ぜ合わせるべきRGBの輝度が計算できる。輝度が分かれば、上記の(1)の対応表を用いてDigitを求める。これで完了。




(3) 精度を上げるための手続き

 以上で原理の説明は終わりだが、いくつか精度を上げる手法がある。

 

ゲタを引く

 RGB=(0 0 0)のときの光は、完全に0cd/m2ではない。わずかに発光している。たとえば RGB=(0 0 0) のときの輝度が1cd/m2であるディスプレイを用いて赤10cd/m2、緑10cd/m2、青10cd/m2を混ぜたとする。30cd/m2の光が呈示されるかと思いきや、実際には28cd/m2である。これはゲタの1cd/m2をRGBの3回分足そうとしているからである。このゲタによるずれは低輝度刺激のときに深刻になる。
 そこで、あらかじめ目的の値からゲタ相当分を差し引いてから、上記の(1)(2)を行う必要がある。(1)ではDigit 0での輝度を差し引いてカーブフィッティングおよび数値読み出しをする。(2)では目的の輝度からゲタ相当分を引いたものを代入する。上記のディスプレイの例で30cd/m2を出したい場合、黒1cd/m2に、赤は9.67 cd/m2、緑9.67 cd/m2、青9.67 cd/m2を足し合わせて、合計30cd/m2を得ることになる。


図(左)MS surface(6th gen)のガンマを測定した例。(右)0付近を拡大した図。

上記の図はRGBをそれぞれ表示した際の輝度と、R=G=Bのグレーを表示した際の輝度を測定した例である。RGBを分けて測定したものを加算(ただしゲタ0.93 cd/m2 の補正済み)した結果をピンク色の点線で示す。黒と紫は重なっており、このディスプレイの加算特性は極めて良いことが分かる。


加算特性の悪さを克服する

加算特性とは、黒、赤、緑、青を個別に表示して測定した輝度と、それぞれを足し合わせて白などを表示した輝度がどれだけ一致するか、という特徴である。あらかじめ測定の段階で、RGBを同じ値にした灰色(wとする)を表示して測定、wとR+G+B(ゲタ補正)を重ねてプロット比較してみると良い。加算特性が悪い場合はキャリブレーションは少し難しくなる。いくつかの解決策を以下に示す。

一つの方法は、R:0~255 を測定する際にG,Bを0にするのではなく、G,B=128あたりを表示することである。緑と青の光が常に重ねられていることになるが、これはR=0の時の輝度を差し引けば消えて、純粋なRの特性を測定できることになる。刺激で中間色を呈示する際にはGB=0であることは少ないので比較的マシになる。その際に上記のゲタの補正は行わないほうが良い。

さらなる方法は、R=0:16:255 × G=0:16:255 × B=0:16:255 の合計4096点をすべて測定する方法もある。これはRGBの独立性、加法性を用いずに三次元的なルックアップテーブルを用意する方法である。測定を自動化してていれば測定は実行可能である。ただし三次元的にルックアップテーブルを参照するのは計算コストが高い。何かシンプルな多項式フィッティングができればいいのだが私は知らない。計算コストはかかるが、単一パッチ等の色刺激であれば毎回参照しても問題は無いだろう。

コード作成での注意

・エラー処理
 表示可能な輝度より大きい輝度を表示しようとしても不可能である。もちろんマイナス輝度も不可能である。また極端に彩度の高い色(gamutの外にあると言う)を表示しようとすると、同じように輝度の制限を超えてしまう。これらのエラー処理方針を決める必要がある。視覚の研究であれば、表示範囲外の色は出さないようにする。関数を定義して限界を超えた場合にエラーコードを返すようにしよう。RGBのそれぞれが0以下なのかmax↑なのかをわかるようにエラーコードを決め、それでも無理やり表示する場合は、digitを0や255にクリップしよう。

課題

以下の輝度、色度のRGB画像を表示して実測する。

Luminance, CIEx, CIEy
10, 0.2, 0.1
10, 0.2, 0.2
10, 0.3, 0.2
10, 0.4, 0.2
10, 0.3, 0.3
10, 0.4, 0.3
10, 0.5, 0.3
10, 0.6, 0.3
10, 0.3, 0.4
10, 0.4, 0.4
10, 0.5, 0.4
10, 0.3, 0.5
10, 0.4, 0.5

上記の色を表示して実測せよ。目的値と実測値を重ねてプロットして、誤差の一貫した傾向がないか探る。CIE xyプロットで測定点が全体的に左下にずれていたら、それは青の輝度が高すぎたことを意味する。つまり青のカーブフィッティングがデータよりも低輝度側にずれていた可能性がある。
 CIExyのスペクトルデータは公開されている。例えばCVRL http://www.cvrl.org/。 私のmatlabコード(スペクトルデータ含む)を利用してもらっても構わない。
code.matlab.zip
zipを開いて drawspectrum を走らすとスペクトルが良い感じに描かれる。上記のデータをプロットすると下のような結果となるだろう。比較のためにsRGB規格のgamutも併せて表示した(水色の線)。




色校正ができるディスプレイ、難しいディスプレイ

CRTや高性能な液晶ディスプレイであれば上記のキャリブレーションで問題なく表示が可能である(2015年現在)。 一般的に普及しているディスプレイで気をつけるべきなのは以下の製品である

プロジェクター
特にDLP型と呼ばれる小型安価タイプは要注意である。DLPとは時間方向でR/G/B(/w)を高速で切り替えながらフルカラー表示するデバイスである。DLPであるかどうかは、真っ白い画面を表示して画面の前で手を振ってみてみれば良い。色づいた影が見えるはずである。 時間方向のわずかな漏れが色チャンネル間の干渉を発生し、さらに白画面の輝度を稼ぐために白チャンネルという困った機能が追加されることがある。RGBの輝度加法性が全く成り立たないのである。
https://ja.wikipedia.org/wiki/DLP
エプソン製の3LED型プロジェクターは無難。RGBが独立で光路が構成されており、良い成績を示すようである。
ハイダイナミックレンジ対応
「ダイナミックコントラスト」機能は要注意である。全画面黒の黒さを表現するために、画面全体が暗いシーンでは光源の輝度を落とし、明るいシーンでは光源を強める操作をしてくれる。真っ暗な画面から輝くシーンまでを表示できることになるので映画鑑賞には好まれる。テレビや映画鑑賞用などに多い。しかし、キャリブレーションのためにはこの機能が仇となる。
T液晶ディスプレイの方式
画面を上から見下ろしたり下から見上げたりすると明るさや色が大きく変わったりするディスプレイがある。多くはTN型と呼ばれる方式の液晶ディスプレイである。液晶ディスプレイにはいくつかの表示形式がある。TN型、VA型、IPS型などがその代表例である。概して、TNは安価・低コントラスト・視野角悪。VAは高速、画質は普通(だが2015年現在、悪くないレベルに達してると思う)。IPSは高コントラスト・低速・広視野角。ディスプレイ形式は公開されてないことが多々あるが、視野角を見ればだいたい予想できる。IPSであれば視野角178度となっている。





21-05-06 ゲタ補正の数値が間違っていることを内川先生に指摘していただきました。修正しました。
もどる