将RGB三元组列表排序成光谱
我有一组RGB颜色值,想把它们画出来,形成一个像光谱一样的效果。
我把这些颜色值转换成了HSV格式,这似乎是大家推荐的做法。
from PIL import Image, ImageDraw
import colorsys
def make_rainbow_rgb(colors, width, height):
"""colors is an array of RGB tuples, with values between 0 and 255"""
img = Image.new("RGBA", (width, height))
canvas = ImageDraw.Draw(img)
def hsl(x):
to_float = lambda x : x / 255.0
(r, g, b) = map(to_float, x)
h, s, l = colorsys.rgb_to_hsv(r,g,b)
h = h if 0 < h else 1 # 0 -> 1
return h, s, l
rainbow = sorted(colors, key=hsl)
dx = width / float(len(colors))
x = 0
y = height / 2.0
for rgb in rainbow:
canvas.line((x, y, x + dx, y), width=height, fill=rgb)
x += dx
img.show()
不过,结果看起来并不像一个漂亮的彩虹光谱。我怀疑我需要换一种颜色空间,或者以不同的方式处理HSL颜色值。
有没有人知道我该怎么做才能让这些数据看起来像彩虹呢?
更新:
我在玩希尔伯特曲线的时候又想到了这个问题。把RGB值(两张图片中的颜色是一样的)按照它们在希尔伯特曲线上的位置排序,得到了一个有趣的结果(虽然还是不完全满意):
5 个回答
4
这是我最近做的一些彩虹,你可以根据这个想法来做你想做的事情。
from PIL import Image, ImageDraw # pip install pillow
import numpy as np
from matplotlib import pyplot as plt
strip_h, strip_w = 100, 720
strip = 255*np.ones((strip_h,strip_w,3), dtype='uint8')
image_val = Image.fromarray(strip)
image_sat = Image.fromarray(strip)
draw0 = ImageDraw.Draw(image_val)
draw1 = ImageDraw.Draw(image_sat)
for y in range(strip_h):
for x in range(strip_w):
draw0.point([x, y], fill='hsl(%d,%d%%,%d%%)'%(x%360,y,50))
draw1.point([x, y], fill='hsl(%d,%d%%,%d%%)'%(x%360,100,y))
plt.subplot(2,1,1)
plt.imshow(image_val)
plt.subplot(2,1,2)
plt.imshow(image_sat)
plt.show()
6
你应该是在按色相(也就是 H)排序吧?如果 S 和 L(或者 V)保持不变,这样排序的结果会很好看。但是如果 S 和 L(或 V)是独立变化的,那结果就会有点乱了!
12
你正在尝试把三维空间的颜色转换成一维的颜色。正如Oli所说,这样做并不能保证你能得到一个好看的彩虹。
你可以把颜色分成几类,依据饱和度和明度来分类,然后在每一类里面再进行排序,这样就能得到几个独立的渐变。例如,先处理高饱和度的颜色,形成经典的彩虹,然后是中等饱和度和高明度的颜色(像是粉色调),最后是低饱和度的颜色(像灰色)。
另外,如果你只想要彩虹效果,可以把颜色转换成hsl格式,然后把饱和度调到1.0,明度调到0.5,再转换回rgb格式,最后用这个颜色来替代原来的颜色。