色をシームレスに変化させたい。虹色みたいに。ただそれだけ。
と思っても、実は色についてほとんど知識が無いことに気がつく。RGBは分かるが、それを使ってどう変化させればいいかわからない。RGBのRの値だけを変えても色の赤みが薄くなるか濃くなるかだけで、虹色みたいに変化させるのは難しいのではと思った。
困ったときのウィキペディア。世の中には皆がよく知るRGB以外にも色を表現する方法はあるようだ。というかペイントとかでお世話になっていた。 RGBは赤・緑・青の原色を混ぜ合わせることで色を表現する方法だが、HSV色空間は、Hue(色相)、Saturation(彩度)、Value(明度)の3つのパラメータで表現する方法だ。ウィキペディアを見て、色を連続的に変化させたい = 色相を変化させたい、とやりたいことを明確に言語化できた。 ウィキペディアを見るとHSVからRGBの変換方法まで記載されていたので、そのままhsvからRGBの変換関数を作成してみた。
def hsv\_to\_rgb(h, s, v):
""" Convert hsv color code to rgb color code.
Naive implementation of Wikipedia method.
See https://ja.wikipedia.org/wiki/HSV%E8%89%B2%E7%A9%BA%E9%96%93
Args:
h (int): Hue 0 ~ 360
s (int): Saturation 0 ~ 1
v (int): Value 0 ~ 1
"""
if s < 0 or 1 < s:
raise ValueError("Saturation must be between 0 and 1")
if v < 0 or 1 < v:
raise ValueError("Value must be between 0 and 1")
c = v * s
h_dash = h / 60
x = c * (1 - abs(h_dash % 2 - 1))
rgb_dict = {
0: (c, x, 0),
1: (x, c, 0),
2: (0, c, x),
3: (0, x, c),
4: (x, 0, c),
5: (c, 0, x),
}
default = (0, 0, 0)
rgb = [0, 0, 0]
for i in range(len(rgb)):
rgb[i] = (v - c + rgb_dict.get(int(h_dash), default)[i]) * 255
rgb = map(int, rgb)
return tuple(rgb)
あとはhを0~360までfor文で変化させたものをgifにすればトップの色が変化していく画像ができあがる。
for i in range(60):
color = hsv_to_rgb(i*6, 1, 1)
img = Image.new('RGB', (width, width), (0, 0, 0))
draw = ImageDraw.Draw(img)
draw.rectangle((0, 0, width, width), fill=color)
images.append(img)
images[0].save("./color.gif", save_all=True, append_images=images[1:], optimize=False, duration=5, loop=0)
せっかくだからグラデーションにでもすればもっと見目麗しい画像になった気がする。 あとpillowは簡単にgifが出来て便利。(小並感)