4
4

More than 1 year has passed since last update.

Python でカラー処理する colour-science のメモ

Last updated at Posted at 2020-06-25

スペクトルから 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'] で取得できる.

これを畳み込むのは 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

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4