スペクトルから RGB, XYZ 値へ変換とか
CG 向けには ACES カラー変換とかもあります
インストール
pip で入るので, 手間はありません. Windows もいけます.
pip install colour-science
colour と u が入りますので注意です!
colour だと別パッケージが入るので注意です!
使う
にまとまっています.
スペクトルデータを生成
dict data から作る(key: wavelength)
wavelength, values の配列から作る
colour.SpectralDistribution(values, wavelengths, name="myspectrum")
補間する
interpolate
元の SpectralDistribution の波長領域から外れるところは考慮されない.
たとえば, [380, 480] のデータを, [400, 500, interval=1] で補間しても, [400, 480] だけ処理される.
SpectralDistribution 同士の演算
あまり演算機能はないようです.
一旦 align or trim などで, 波長領域を合わせておき, .values で生データ取得して numpy 処理がよさそうです.
sd0 = ...
sd1 = ...
target = colour.SpectralShape(380, 780, 1)
sd0_aligned = sd0.align(target)
sd1_aligned = sd1.align(target)
numpy.sum(sd0_aligned.values * sd1_aligned.values)
差分
カラーチェッカーを plot する
ドキュメントと, pip で入るバージョン(0.3.15)で引数が違いますので注意です
pip 0.3.15 利用では, text_parameters を使います.
plot_single_colour_checker(
    colour_checker='ColorChecker 2005', text_parameters={'visible': False})
master を見るとドキュメントと同じ(test_kwargs)なので, 将来的には test_kwargs に統一されるでしょう.
plot_multi_colour_checker で, 2つ並べて表示できる.
ただしここでのカラーチェッカーは RGB(XYZ) のみ
スペクトルカラーチェッカー
本来(今後のメイン)は colour.COLOURCHECKER_SDS で取得できるが, 現在(2020/07/27)の pip で入る v0.3.15 では COLOURCHECKERS_SDS と, S をつける必要がある.
BabelColor Average,  ColorChecher N Ohta のふたつのみ.
BabelColor は 730 nm までしかないので注意.
Ohta: 1997 年に計測されたもので, ISO 標準(?)のもの.
X-Rite の ColorChecker の分光反射分布は公開されていないが, 著者らは X-Rite のカラーチェッカーを分光放射輝度計で計測しており,
700~780 あたりの分布が Ohta と大きくことなるケースがあるのを確認している.
塗料によるものと思われる.
X-Rite のカラーチェッカーは, 有害物質関連で 2014 年前とあとで塗料の変更がある.
カラーチェッカーを買うときは製造年を確認しましょう. 今からだと基本 2014 年以降でしょうから, ISO 標準(Ohta)とは結果が異るので正しいです.
スペクトルから sRGB への変換
単一の SpectralDistribution から sRGB へ変換する.
sd = colour.SpectralDistribution(sample_sd_data)
cmfs = colour.STANDARD_OBSERVER_CMFS['CIE 1931 2 Degree Standard Observer']
illuminant = colour.ILLUMINANT_SDS['D65']
# Calculating the sample spectral distribution *CIE XYZ* tristimulus values.
XYZ = colour.sd_to_XYZ(sd, cmfs, illuminant)
print(XYZ)
スペクトル画像から sRGB 画像への変換
とりあえずぱぱっとスペクトル画像を sRGB 画像にしたい場合
[H, W, C] で numpy ndarray を作成し,
cmfs = colour.STANDARD_OBSERVERS_CMFS['CIE 1931 2 Degree Standard Observer']
illuminant = colour.ILLUMINANTS_SDS['D65']
xyz = colour.multi_sds_to_XYZ(ndimage, cmfs, illuminant, method='Integration',
                        shape=colour.SpectralShape(380, 780, 10))
rgb = colour.XYZ_to_sRGB(xyz / 100)
とする.  XYZ が [0, 100], RGB が [0, 1] の範囲での値になるので 100 で割る.
color matching function やスペクトルの範囲は必要に応じて調整ください.
MultiSpectralDistribution 形式の複数スペクトルデータから変換する関数は無さそう.
標準比視感度
colour.PHOTOPIC_LEFS['CIE 1924 Photopic Standard Observer'] で取得できる.
ありがとう標準比視感度 from colour-science https://t.co/yVlAduFRSt pic.twitter.com/SGdQCnrIgb
— Syoyo Fujita 🌸 レイトラ 🐯 2 周年 🎉 (@syoyo) July 28, 2020
これを畳み込むのは luminous_efficacy 関数がある.
サンプル
Debayer(demosaic) する
処理自体は基本 numpy
OpenColorIO 用の LUT table を作る
1D
table = colour.LUT1D.linear_table(4096)
table = colour.gamma_function(table, 1.8)
LUT = colour.LUT1D(table=table)
path = '/content/downloads/LUT1D.spi1'
colour.write_LUT(LUT, path)
3D
table = colour.LUT3D.linear_table(33)
table = colour.gamma_function(table, 1.8)
LUT = colour.LUT3D(table=table)
path = '/content/downloads/LUT3D.cube'
colour.write_LUT(LUT, path)
CSV へエクスポート
ドキュメントではわかりづらいのですが, SpectralDistribution を値に持つ dict を作ります.
CSV では, dict の key が波長データの名前になります.
sds_bora = colour.SpectralDistribution(...)
sds_muda = colour.SpectralDistribution(...)
d = {}
d['bora'] = sds
d['muda'] = sds
colour.write_sds_to_csv_file(d, "bora.csv")
wavelength,bora,muda
380.0,0.113,0.113
385.0,0.131,0.131
390.0,0.15,0.15
395.0,0.169,0.169
400.0,0.183,0.183
405.0,0.193,0.193
...
CVS から読む
read_sds_from_csv_file を使います.
波長データを key とした dict として復元されます.
colour.read_sds_from_csv_file("bora.csv")
OrderedDict([('bora',
              SpectralDistribution([[  3.80000000e+02,   1.13000000e-01],
                                    [  3.85000000e+02,   1.31000000e-01],
                                    [  3.90000000e+02,   1.50000000e-01],
...
JSON は?
標準ではなさそうです. 自前で JSON 変換でしょうか.
SpectralDistribution を dict に変換する
dict から SpectralDistribution は作れますが, 逆は標準では用意されていません.
a = dict((k, v) for k, v in zip(patch_sd.wavelengths, patch_sd.values))
と, wavelengths と values を zip して, wavelength を key として dict を作ることができます.
Tips
スペクトルと, カスタムの color matching function を純粋に積分したい(スペクトルとスペクトルの積分).
sd_to_XYZ で sd, cmfs を指定し method='Integration' を選ぶ.
デフォルトでは定数 illuminant が使われる.
method デフォルトでは ASTM E308 で, 波長のクランプなどが行われる模様.
Integration にすると, 純粋に積分してくれる.
内部的には numpy で処理しているので, 自前で numpy 処理してもよいかもしれません.
その他メモ
カラーチェッカーでキャリブレーション
https://github.com/colour-science/colour/issues/598