息抜き記事です。n番煎じ。
はじめに
ア〇ミカ女史によると、白は200色あるそうです。
Pythonで(約)200色の白を1枚の画像に描写して、それぞれの味わいを語り合いましょう!
コンピュータにおける色の表現の基礎
コンピュータでは、色を(赤,緑,青)
の組み合わせで表現することが一般的です。この表現方法をRGBと呼びます。
これは、人間が判別できる多くの色を赤(Red)緑(Green)青(Blue)の3色の組み合わせで表すことができる、いわゆる「光の三原色」に基づいています。
また、各色は一般的に0~255の範囲で表現されます。0のときはまったく光っておらず、255のとき最高に光っているとイメージしてください。
0~255を16進数で表現すると、0x00~0xFFと表せます。HTML/CSSなどでよく見る#55C500
といったカラーコードも、RGBの表記法の1つです。この場合前から2桁ずつ、0x55=85が赤の強さ、0xC5=197が緑の強さ、0x00=0が青の強さを指しています。
Qiitaではカラーコードの右に小さく色を表示してくれますが、Googleで検索して確認することもできます。
この色は、Qiitaのロゴカラーですね!
「200色の白」ってなんやねん
それでは、コンピュータで「白」をを表現してみましょう。先ほどのWikipediaで「光の三原色」のイラストを見てみると、最高に光っている3色の光が交わる真ん中が白になっているとわかります。白は(255,255,255)
、#FFFFFF
と表すことができます。
しかし、果たして(255,255,255)
だけが白なのでしょうか?ちょっといたずらして、赤を弱めてしまいましょう。(254,255,255)
(#FEFFFF
)ではどうでしょうか?
...ほとんど違いがわからない白色です。それじゃあもう少し大胆に、それぞれの光を同じだけ弱めてみましょう。5ずつ弱めて、(250,250,250)
(#FAFAFA
)ではどうでしょうか?
私の液晶ではちょっぴりくすんだ印象はありますが、まだまだ白と言えそうです。つまり「255から少しいじったぐらいなら、私たちは白色と認識することができる」ということがわかります。
200色の白を作るための値の範囲
では200色の白を作るためには、各色をどれくらい広げる必要があるのか考えてみます。
各色255
~255
の場合、表現できる白色は(255,255,255)
の1色です。
254
~255
の場合は、
(254,254,254)
、(254,254,255)
、(254,255,254)
、(254,255,255)
、(255,254,254)
、(255,254,255)
、(255,255,254)
、(255,255,255)
、すなわち2 ** 3 = 8
色の白色を表現できます(カラーコードで見れば、それぞれちゃんと白に見えることがわかるでしょう)。
この調子で、200色の白を表現するための範囲を考えます。それぞれの色がn階調表現できるとして、n ** 3 >= 200
よりn >= 200 ** (1/3)
、nは整数なので6階調、各色250
~255
もあれば200色の白を表現することができるようです。先ほど(250,250,250)
が白色に見えましたから、大丈夫そうですね。
画像にしてみる
PythonとOpenCVを使って、6 ** 3 = 216
色の白色を1枚の画像に並べましょう。
OpenCVの導入などについては詳しくは説明しませんが、以下のコマンドを実行するとOpenCVをインストールできます。
pip install opencv-python
こちらが実際のコードです。
import numpy as np
import cv2
def main():
SIDE_LENGTH = 32
image = np.zeros((480, 480, 3), dtype=np.uint8)
row = 0
column = 0
for r in range(250, 256):
for g in range(250, 256):
for b in range(250, 256):
cv2.rectangle(image, (column * SIDE_LENGTH, row * SIDE_LENGTH), (column * SIDE_LENGTH + SIDE_LENGTH, row * SIDE_LENGTH + SIDE_LENGTH), (b, g, r), -1)
column += 1
if column == 15:
row += 1
column = 0
cv2.imwrite("result.png", image)
if __name__ == '__main__':
main()
空の画像を用意して、それぞれの色を32 * 32ずつ塗るコードです。216個の白色を並べるための正方形の一辺は、x ** 2 >= 216
よりx >= sqrt(216)
なので15 * 32 = 480
ピクセルとわかります。あとは15個並べたら改行するだけです。
すべて白色に見えるのではないでしょうか。白は本当に200色あったんだ...!
???「白ってn色あんねん」
偽アン〇カが現れて適当な数字を言っても確認できるように、任意の数に対応しましょう。とはいっても、ここまで各数字の導出過程を書いてきたので、これらをソースコードに起こすだけです。
16777216色の白があると主張するアンミカには、こちらのコードで対抗しましょう。色数が多すぎてメモリ使用量がすさまじいことになるため、色を塗るサイズは1ピクセルにしています。
import math
import numpy as np
import cv2
def main():
NUM_WHITE = 16777216
COLOR_RANGE = range(256 - math.ceil(NUM_WHITE ** (1 / 3)), 256)
NUM_WHITE_ACTUAL = len(COLOR_RANGE) ** 3
SIDE_LENGTH = 1
SIDE_COUNT = math.ceil(math.sqrt(NUM_WHITE_ACTUAL))
SIDE_RESULT = SIDE_COUNT * SIDE_LENGTH
image = np.zeros((SIDE_RESULT, SIDE_RESULT, 3), dtype=np.uint8)
row = 0
column = 0
for r in COLOR_RANGE:
for g in COLOR_RANGE:
for b in COLOR_RANGE:
cv2.rectangle(image, (column * SIDE_LENGTH, row * SIDE_LENGTH), (column * SIDE_LENGTH + SIDE_LENGTH, row * SIDE_LENGTH + SIDE_LENGTH), (b, g, r), -1)
column += 1
if column == SIDE_COUNT:
row += 1
column = 0
cv2.imwrite("result.png", image)
if __name__ == '__main__':
main()
こちらが16777216の「白」です。#000000
から#FFFFFF
まであります!
おあとがよろしいようで...