18

我有一个 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()

然而,结果看起来不太像一个漂亮的彩虹-y光谱。我怀疑我需要转换为不同的色彩空间或以不同的方式处理 HSL 三元组。

这看起来不像光谱

有谁知道我需要做什么才能使这些数据看起来大致像彩虹?

更新:

我在玩希尔伯特曲线并重新审视了这个问题。通过沿希尔伯特曲线的位置对 RGB 值(两个图像中的相同颜色)进行排序会产生一个有趣的(如果仍然不完全令人满意)的结果:

RGB 值沿希尔伯特曲线排序。

4

5 回答 5

12

您正在尝试将三维空间转换为一维空间。正如 Oli 所说,不能保证你能从中创造出令人愉悦的彩虹。

您可以做的是根据饱和度和值/亮度将颜色“分桶”到几个不同的类别中,然后在类别中进行排序,以获得几个独立的渐变。例如,经典彩虹首先是高饱和度颜色,然后是中饱和度高价值颜色(粉彩),然后是低饱和度(灰色)。

或者,如果您只关心彩虹,则转换为 hsl,然后将饱和度调整为 1.0 并将值调整为 0.5,然后转换回 rgb 并渲染它而不是原始颜色。

于 2011-06-01T23:59:35.907 回答
6

大概你是按色调(即H)排序的?如果SL(或V )是恒定的,那将给出一个很好的结果,但如果它们独立变化,那么你会有点混乱!

于 2011-06-01T23:50:14.783 回答
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()

在此处输入图像描述

于 2011-06-02T04:43:37.473 回答
4

一种减少色彩空间维数的有趣方法是使用空间填充希尔伯特曲线。两篇相关文章是:

他们都考虑 3d -> 2d 减少,但映射到 1d 曲线的中间步骤可能是您问题的解决方案。

于 2012-04-07T07:09:36.823 回答
1

这似乎不正确。

canvas.line((x, y, x + dx, y), width=height, fill=rgb)

试试这个。

canvas.rectangle([(x, y), (x+dx, y+height)], fill=rgb)
于 2011-06-02T10:05:42.557 回答