20170806

どちらが正しいRGBか。(matplotlibでcmapをいじる)

 

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

20170805-05.png

 

中段と下段、二種類のRGBの表現方法があることに気づいた。
ディスプレイ上で、RGBを正しく表現しているのは、中段と下段のどちらか。(RGBAではない。)

答えは下段…だと自分は思う。
ただ、写真的には、中段だと思う。

pythonで画像を表示する。

pythonで画像を表示するとき、自分は、matplotlibかpqtgraphを使う。(ほかにもいろいろ方法はある)
両方とも、数値をプロットしたりするときに使うソフト。

詳しい使い方は、ここにある。使う度に毎回参照している。多分一生覚えられない。

例えば、以下のようなコードを実行したとき、
ファイルダイアログが開いて、任意のファイルを開き、画像を表示する。

# coding: Shift_JIS

import matplotlib.pyplot as plt
# 画像表示用の関数1
import matplotlib.image as mpimg
# 画像表示用の関数2
import tkinter.filedialog as tkfd
# ファイルダイアログ用の関数。

f, (ax1) = plt.subplots(1)
# 作図
filename = tkfd.askopenfilename()
#ファイルダイアログを出し、選んだファイルを変数に代入
img1 = mpimg.imread(filename)
#画像
ax1.imshow(img1)
plt.show()

20170805-00.png

これを、RGB別に分けて表示するには、直感的にはRGBの情報が入った配列(np.array)をこうやってとりだしたい。

img[:,:,0]

上記を使って、下記のようなコードを実行すると、

import numpy as np
# 数値計算ライブラリ
import matplotlib.pyplot as plt
# 画像表示用の関数1
import matplotlib.image as mpimg
# 画像表示用の関数2
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()

こんな感じになる。

20170805-01.png

色が付いている。
これは、カラーマップが、良くない。カラーマップがjetというやつだから、こうなった。

cmapとは

前の例を、カラーマップを指定すると、こんな感じにできる。

import numpy as np 
# 数値計算ライブラリ
import matplotlib.pyplot as plt
# 画像表示用の関数1
import matplotlib.image as mpimg
# 画像表示用の関数2
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。

20170805-02.png

ぱっと見は、これで完成しているように見えるが…
これじゃない。こうじゃないんだよ!

まず

  1. 色が濃いはずの部分が、薄くなっている!!
  2. 色が赤青緑ではない!!!!!!!!!!!

白→赤ないし、黒→赤みたいになってないとダメ。できあいのカラーマップじゃダメ。

なので、任意の二色のグラデーションを作りたい。

matplotlibでの解決方法

公式ではcmapの作り方はここら辺を参考にできる
が、cdictの中身の意味はここを見る必要があるし、公式よりもここの方が参考になるかもしれない。

import matplotlibimport numpy as np 
# 数値計算ライブラリ
import matplotlib.pyplot as plt
# 画像表示用の関数1
import matplotlib.image as mpimg
# 画像表示用の関数2
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()

20170805-03.png

黒なんか指定した覚えはない。
白い紙に、絵の具を置くと、こうなるでしょ!?
という人は、こっちがいいかも…

import matplotlibimport numpy as np 
# 数値計算ライブラリ
import matplotlib.pyplot as plt
# 画像表示用の関数1
import matplotlib.image as mpimg
# 画像表示用の関数2
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()

20170805-04.png

 

gifアニメで説明すると、

cdictの中身の意味は前述のここを見る必要がある

作り方のコードは、あえて載せない。
理由は、説明が面倒だから。
(matplotlibが、imagmagicを参照していて、それのバージョンやらインストールする場所とか…が面倒だから、説明しにくい。)

クリックすると、若干画像の質がアップするので、クリックされたし。
ani07.gifani07.gif
ani07.gif
背景白の方は、数値が減ると赤以外の色の値が減少(データが小さいと、RGB揃って、全体が白に近づく。Rは一定、G,Bが減少する。)
背景黒の方は、数値が大きくなると、赤色の値が大きくなる。

赤がない部分は、ディスプレイのLEDが消えているので黒。こう考えると、背景黒の方が、赤の増加を数値で表現しているという点で、正しい。

自分は、「白い紙に色を塗る派」なので、背景白が正としたい所だが…

どちらが正しいのか

黒→赤とかが、本来の表現だが…
なぜならば、PCやら、携帯やらをonしていない時、そのディスプレイは、大抵黒。
off時に、黒以外の色になるディスプレイなんて、ブラウン管TVが灰色だったり、GBAとかワンダースワン以来、お目にかかっていない。
ここに、3色のLEDとか液晶とか何かが光って、画面を表示している。
3色全部つくと、白くなる。この光の強さと、値の大きさを対応させているから、黒→色が正しい表現。

しかし、学校とかでは、絵を描く時に、白い紙を配られて、そこに色を置いた。つまり、何もないところは白で、色があるところは赤。
この考え方で行くと、白い紙の上では、白→色が正しい表現になる。

紙と、ディスプレイで、表現の方法が違う。

紙の場合は、光っていない。
ディスプレイの場合は光っている。
この差は大きい。

ただ、PCはディスプレイで見るとはいえ、紙的な表現を心掛けた方がいいと思っている。
なぜならば、印刷時のインク消費量が上がるから。

import matplotlibimport numpy as np
# 数値計算ライブラリ
import matplotlib.pyplot as plt
# 画像表示用の関数1
import matplotlib.image as mpimg
# 画像表示用の関数2
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()
この画像は、トップにのせた。



もうすぐ、新しいアニメが出せそうな予感がする。
今度は、フーリエ変換ではなく、クロソイド曲線についてアニメーションする。
plt-00588-20170731212136.png
その後で、二次元フーリエ変換についてもやる。
空いている部分に、行列の掛け算のアニメを入れる。
「行列を使った一次方程式の解き方」のやつを入れる。

それでも余った場合は、何かそれっぽいものを入れる。
posted by yuchan at 07:00 | Comment(0) | python
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント: