将 RGB 三元组列表排序为光谱

发布于 2024-11-13 16:40:25 字数 1145 浏览 6 评论 0原文

我有一个 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 值(两个图像中的颜色相同)进行排序会产生一个有趣的(如果仍然不完全令人满意)结果:

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

I have a list of RGB triplets, and I'd like to plot them in such a way that they form something like a spectrum.

I've converted them to HSV, which people seem to recommend.

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()

However, the result doesn't look very much like a nice rainbow-y spectrum. I suspect I need to either convert to a different color space or handle the HSL triplet differently.

this doesn't look like a spectrum

Does anyone know what I need to do to make this data look roughly like a rainbow?

Update:

I was playing around with Hilbert curves and revisited this problem. Sorting the RGB values (same colors in both images) by their position along a Hilbert curve yields an interesting (if still not entirely satisfying) result:

RGB values sorted along a Hilbert curve.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

書生途 2024-11-20 16:40:25

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

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

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

You're trying to convert a three-dimensional space into a one-dimensional space. There's no guarantee that you can make a pleasing rainbow out of it, as Oli says.

What you can do is "bucket" the colors into a few different categories based on saturation and value/lightness, and then sort within the categories, to get several independent gradients. For example, high-saturation colors first for the classic rainbow, then mid-saturation high-value colors (pastels), then low-saturation (grays).

Alternately, if all you care about is the rainbow, convert to hsl, then slam saturation to 1.0 and value to 0.5, convert back to rgb and render that instead of the original color.

潇烟暮雨 2024-11-20 16:40:25

想必您是按色调排序(即 H)?如果SL(或V)是常数,这将给出一个很好的结果,但如果它们独立变化,那么你会得到一个有点乱!

Presumably you are sorting by hue (i.e. H)? That will give a nice result if S and L (or V) are constant, but if they are varying independently, then you will get a bit of a mess!

熊抱啵儿 2024-11-20 16:40:25

降低颜色空间维度的一种有趣方法是使用空间填充希尔伯特曲线。两篇相关文章是:

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

An interesting method for reducing dimensionality of color spaces uses the space-filling Hilbert curve. Two relevant articles are:

They both consider 3d -> 2d reduction, but the intermediate step of mapping to the 1d curve could be a solution to your problem.

彼岸花似海 2024-11-20 16:40:25

这是我最近制作的一些彩虹,你可以修改想法来做你想做的

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()

在此处输入图像描述

Here are some rainbows I made recently, you can modify the idea to do what you want

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()

enter image description here

难以启齿的温柔 2024-11-20 16:40:25

这似乎是不正确的。

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

试试这个。

canvas.rectangle([(x, y), (x+dx, y+height)], fill=rgb)

This seems incorrect.

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

Try this.

canvas.rectangle([(x, y), (x+dx, y+height)], fill=rgb)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文