matplotlibのカラーマップを自分で作成する時に起こった問題。

中段と下段、二種類のRGBの表現方法があることに気づいた。
ディスプレイ上で、RGBを正しく表現しているのは、中段と下段のどちらか。(RGBAではない。)
答えは下段…だと自分は思う。
ただ、写真的には、中段だと思う。
pythonで画像を表示する。
pythonで画像を表示するとき、自分は、matplotlibかpqtgraphを使う。(ほかにもいろいろ方法はある)
両方とも、数値をプロットしたりするときに使うソフト。
詳しい使い方は、ここにある。使う度に毎回参照している。多分一生覚えられない。
例えば、以下のようなコードを実行したとき、
ファイルダイアログが開いて、任意のファイルを開き、画像を表示する。
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import tkinter.filedialog as tkfd
f, (ax1) = plt.subplots(1)
filename = tkfd.askopenfilename()
img1 = mpimg.imread(filename)
ax1.imshow(img1)
plt.show()

これを、RGB別に分けて表示するには、直感的にはRGBの情報が入った配列(np.array)をこうやってとりだしたい。
img[:,:,0]
上記を使って、下記のようなコードを実行すると、
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import tkinter.filedialog as tkfd
f, ((ax11,ax12,ax13,), (ax21,ax22,ax23,)) = plt.subplots(2,3)
ax11.axis("off")
ax13.axis("off")
filename = tkfd.askopenfilename()
img1 = mpimg.imread(filename)
ax12.imshow(img1)
ax21.imshow(img1[:,:,0])
ax22.imshow(img1[:,:,1])
ax23.imshow(img1[:,:,2])
plt.show()
こんな感じになる。

色が付いている。
これは、カラーマップが、良くない。カラーマップがjetというやつだから、こうなった。
cmapとは
前の例を、カラーマップを指定すると、こんな感じにできる。
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import tkinter.filedialog as tkfd
f, ((ax11,ax12,ax13,), (ax21,ax22,ax23,)) = plt.subplots(2,3)
ax11.axis("off")
ax13.axis("off")
filename = tkfd.askopenfilename()
img1 = mpimg.imread(filename)
ax12.imshow(img1)
ax21.imshow(img1[:,:,0], cmap="hot")
ax22.imshow(img1[:,:,1], cmap="summer")
ax23.imshow(img1[:,:,2], cmap="winter")
ax21.set_title("hot")
ax22.set_title("summer")
ax23.set_title("winter")
plt.show()
下側の、図の、タイトルが、cmap。

ぱっと見は、これで完成しているように見えるが…
これじゃない。こうじゃないんだよ!
まず
- 色が濃いはずの部分が、薄くなっている!!
- 色が赤青緑ではない!!!!!!!!!!!
白→赤ないし、黒→赤みたいになってないとダメ。できあいのカラーマップじゃダメ。
なので、任意の二色のグラデーションを作りたい。
matplotlibでの解決方法
公式ではcmapの作り方はここら辺を参考にできる
が、cdictの中身の意味はここを見る必要があるし、公式よりもここの方が参考になるかもしれない。
import matplotlibimport numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import tkinter.filedialog as tkfd
cdict = {'red': ((0.0, 0.0, 0.0),(1.0, 1.0, 1.0)),
'green': ((0.0, 0.0, 0.0),(1.0, 0.0, 0.0)),
'blue': ((0.0, 0.0, 0.0),(1.0, 0.0, 0.0))
}
cmap_RtoBRK = matplotlib.colors.LinearSegmentedColormap('my_colormap',cdict,256)
cdict2 = {'red': ((0.0, 0.0, 0.0),(1.0, 0.0, 0.0)),
'green': ((0.0, 0.0, 0.0),(1.0, 1.0, 1.0)),
'blue': ((0.0, 0.0, 0.0),(1.0, 0.0, 0.0))
}
cmap_GtoBRK = matplotlib.colors.LinearSegmentedColormap('my_colormap',cdict2,256)
cdict3 = {'red': ((0.0, 0.0, 0.0),(1.0, 0.0, 0.0)),
'green': ((0.0, 0.0, 0.0),(1.0, 0.0, 0.0)),
'blue': ((0.0, 0.0, 0.0),(1.0, 1.0, 1.0))
}
cmap_BtoBRK = matplotlib.colors.LinearSegmentedColormap('my_colormap',cdict3,256)
f, ((ax11,ax12,ax13,), (ax21,ax22,ax23,)) = plt.subplots(2,3)
ax11.axis("off")
ax13.axis("off")
filename = tkfd.askopenfilename()
img1 = mpimg.imread(filename)
ax12.imshow(img1)
ax21.imshow(img1[:,:,0], cmap=cmap_RtoBRK)
ax22.imshow(img1[:,:,1], cmap=cmap_GtoBRK)
ax23.imshow(img1[:,:,2], cmap=cmap_BtoBRK)
plt.show()

黒なんか指定した覚えはない。
白い紙に、絵の具を置くと、こうなるでしょ!?
という人は、こっちがいいかも…
import matplotlibimport numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import tkinter.filedialog as tkfd
cdict = {'red': ((0.0, 1.0, 1.0),(1.0, 1.0, 1.0)),
'green': ((0.0, 1.0, 1.0),(1.0, 0.0, 0.0)),
'blue': ((0.0, 1.0, 1.0),(1.0, 0.0, 0.0))
}
cmap_RtoBRK = matplotlib.colors.LinearSegmentedColormap('my_colormap',cdict,256)
cdict2 = {'red': ((0.0, 1.0, 1.0),(1.0, 0.0, 0.0)),
'green': ((0.0, 1.0, 1.0),(1.0, 1.0, 1.0)),
'blue': ((0.0, 1.0, 1.0),(1.0, 0.0, 0.0))
}
cmap_GtoBRK = matplotlib.colors.LinearSegmentedColormap('my_colormap',cdict2,256)
cdict3 = {'red': ((0.0, 1.0, 1.0),(1.0, 0.0, 0.0)),
'green': ((0.0, 1.0, 1.0),(1.0, 0.0, 0.0)),
'blue': ((0.0, 1.0, 1.0),(1.0, 1.0, 1.0))
}
cmap_BtoBRK = matplotlib.colors.LinearSegmentedColormap('my_colormap',cdict3,256)
f, ((ax11,ax12,ax13,), (ax21,ax22,ax23,)) = plt.subplots(2,3)
ax11.axis("off")
ax13.axis("off")
filename = tkfd.askopenfilename()
img1 = mpimg.imread(filename)
ax12.imshow(img1)
ax21.imshow(img1[:,:,0], cmap=cmap_RtoBRK)
ax22.imshow(img1[:,:,1], cmap=cmap_GtoBRK)
ax23.imshow(img1[:,:,2], cmap=cmap_BtoBRK)
plt.show()

gifアニメで説明すると、
作り方のコードは、あえて載せない。
理由は、説明が面倒だから。
(matplotlibが、imagmagicを参照していて、それのバージョンやらインストールする場所とか…が面倒だから、説明しにくい。)
クリックすると、若干画像の質がアップするので、クリックされたし。
背景白の方は、数値が減ると赤以外の色の値が減少(データが小さいと、RGB揃って、全体が白に近づく。Rは一定、G,Bが減少する。)
背景黒の方は、数値が大きくなると、赤色の値が大きくなる。
赤がない部分は、ディスプレイのLEDが消えているので黒。こう考えると、背景黒の方が、赤の増加を数値で表現しているという点で、正しい。
自分は、「白い紙に色を塗る派」なので、背景白が正としたい所だが…
どちらが正しいのか
黒→赤とかが、本来の表現だが…
なぜならば、PCやら、携帯やらをonしていない時、そのディスプレイは、大抵黒。
off時に、黒以外の色になるディスプレイなんて、ブラウン管TVが灰色だったり、GBAとかワンダースワン以来、お目にかかっていない。
ここに、3色のLEDとか液晶とか何かが光って、画面を表示している。
3色全部つくと、白くなる。この光の強さと、値の大きさを対応させているから、黒→色が正しい表現。
しかし、学校とかでは、絵を描く時に、白い紙を配られて、そこに色を置いた。つまり、何もないところは白で、色があるところは赤。
この考え方で行くと、白い紙の上では、白→色が正しい表現になる。
紙と、ディスプレイで、表現の方法が違う。
紙の場合は、光っていない。
ディスプレイの場合は光っている。
この差は大きい。
ただ、PCはディスプレイで見るとはいえ、紙的な表現を心掛けた方がいいと思っている。
なぜならば、印刷時のインク消費量が上がるから。
import matplotlibimport numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import tkinter.filedialog as tkfd
cdict = {'red': ((0.0, 1.0, 1.0),(1.0, 1.0, 1.0)),
'green': ((0.0, 1.0, 1.0),(1.0, 0.0, 0.0)),
'blue': ((0.0, 1.0, 1.0),(1.0, 0.0, 0.0))
}
cmap_RtoBRK = matplotlib.colors.LinearSegmentedColormap('my_colormap',cdict,256)
cdict2 = {'red': ((0.0, 1.0, 1.0),(1.0, 0.0, 0.0)),
'green': ((0.0, 1.0, 1.0),(1.0, 1.0, 1.0)),
'blue': ((0.0, 1.0, 1.0),(1.0, 0.0, 0.0))
}
cmap_GtoBRK = matplotlib.colors.LinearSegmentedColormap('my_colormap',cdict2,256)
cdict3 = {'red': ((0.0, 1.0, 1.0),(1.0, 0.0, 0.0)),
'green': ((0.0, 1.0, 1.0),(1.0, 0.0, 0.0)),
'blue': ((0.0, 1.0, 1.0),(1.0, 1.0, 1.0))
}
cmap_BtoBRK = matplotlib.colors.LinearSegmentedColormap('my_colormap',cdict3,256)
cdict12 = {'red': ((0.0, 0.0, 0.0),(1.0, 1.0, 1.0)),
'green': ((0.0, 0.0, 0.0),(1.0, 0.0, 0.0)),
'blue': ((0.0, 0.0, 0.0),(1.0, 0.0, 0.0))
}
cmap_RtoBRK2 = matplotlib.colors.LinearSegmentedColormap('my_colormap',cdict12,256)
cdict22 = {'red': ((0.0, 0.0, 0.0),(1.0, 0.0, 0.0)),
'green': ((0.0, 0.0, 0.0),(1.0, 1.0, 1.0)),
'blue': ((0.0, 0.0, 0.0),(1.0, 0.0, 0.0))
}
cmap_GtoBRK2 = matplotlib.colors.LinearSegmentedColormap('my_colormap',cdict22,256)
cdict32 = {'red': ((0.0, 0.0, 0.0),(1.0, 0.0, 0.0)),
'green': ((0.0, 0.0, 0.0),(1.0, 0.0, 0.0)),
'blue': ((0.0, 0.0, 0.0),(1.0, 1.0, 1.0))
}
cmap_BtoBRK2 = matplotlib.colors.LinearSegmentedColormap('my_colormap',cdict32,256)
f, ((ax11,ax12,ax13), (ax21,ax22,ax23), (ax31,ax32,ax33)) = plt.subplots(3,3)
ax11.axis("off")
ax13.axis("off")
filename = tkfd.askopenfilename()
img1 = mpimg.imread(filename)
ax12.imshow(img1)
ax21.imshow(img1[:,:,0], cmap=cmap_RtoBRK)
ax22.imshow(img1[:,:,1], cmap=cmap_GtoBRK)
ax23.imshow(img1[:,:,2], cmap=cmap_BtoBRK)
ax31.imshow(img1[:,:,0], cmap=cmap_RtoBRK2)
ax32.imshow(img1[:,:,1], cmap=cmap_GtoBRK2)
ax33.imshow(img1[:,:,2], cmap=cmap_BtoBRK2)
plt.show()