【问题标题】:HSL to RGB color conversion problemsHSL 到 RGB 颜色转换问题
【发布时间】:2012-08-25 14:08:21
【问题描述】:

我喜欢随机生成 - 和随机颜色 - 所以我决定将它们结合起来制作一个简单的 2d 景观生成器。我的想法是,根据方块的高度(是的,地形是由方块组成的)使其更亮或更暗,靠近顶部的东西更亮,靠近底部的东西更暗。我让它在灰度下工作,但正如我发现的那样,你不能真正使用基本的 RGB 颜色并使其更亮,因为 RGB 值之间的比率或任何类似的值似乎无法使用。解决方案? HSL。或者也许是 HSV,老实说我仍然不知道其中的区别。我指的是 H 0-360,S & V/L = 0-100。虽然...嗯,360 = 0,所以是 360 的值,但如果你真的有 0-100,那就是 101。真的是 0-359 和 1-100(或 0-99?),但是颜色选择编辑器(目前指的是 GIMP...MS 画图有超过 100 的饱和度)允许您输入这样的值吗?

无论如何,我找到了 HSL->RGB 转换的公式(here & here。据我所知,最终公式是相同的,但我还是会提供代码(注​​意这是来自后者easyrgb.com链接):

Hue_2_RGB

float Hue_2_RGB(float v1, float v2, float vH)             //Function Hue_2_RGB
{
if ( vH < 0 )
    vH += 1;

if ( vH > 1 )
    vH -= 1;

if ( ( 6 * vH ) < 1 )
    return ( v1 + ( v2 - v1 ) * 6 * vH );

if ( ( 2 * vH ) < 1 )
    return ( v2 );

if ( ( 3 * vH ) < 2 )
    return ( v1 + ( v2 - v1 ) * ( ( 2 / 3 ) - vH ) * 6 );

return ( v1 );
}

还有另一段代码:

float var_1 = 0, var_2 = 0;

        if (saturation == 0)                       //HSL from 0 to 1
        {
           red = luminosity * 255;                      //RGB results from 0 to 255
           green = luminosity * 255;
           blue = luminosity * 255;
        }
        else
        {
            if ( luminosity < 0.5 )
                var_2 = luminosity * (1 + saturation);
            else
                var_2 = (luminosity + saturation) - (saturation * luminosity);

            var_1 = 2 * luminosity - var_2;

            red = 255 * Hue_2_RGB(var_1, var_2, hue + ( 1 / 3 ) );
            green = 255 * Hue_2_RGB( var_1, var_2, hue );
            blue = 255 * Hue_2_RGB( var_1, var_2, hue - ( 1 / 3 ) );
        }

抱歉,不确定修复这些空白的好方法。

我用我自己的名字、色调、饱和度和亮度替换了 H、S、L 值。我回头看了看,但除非我遗漏了什么,否则我会正确替换它。但是,除了 C++ 所需的部分之外,hue_2_RGB 函数完全未经编辑。 (例如变量类型)。我也曾经对所有东西都有整数 - R、G、B、H、S、L - 然后我想到了...... HSL 是公式的浮点数 - 或者至少,它看起来应该是。所以我使用变量(var_1,var_2,所有的v,R,G,B,色调,饱和度,亮度)来浮动。所以我不相信这是某种数据丢失错误。此外,在输入公式之前,我有色相 /= 360、饱和度 /= 100 和亮度 /= 100。请注意,在此之前,我有色相 = 59、饱和度 = 100 和亮度 = 70。我相信我得到了色调正确为 360 以确保 0-1,但尝试 /= 100 也没有解决它。

所以,我的问题是,为什么公式不起作用?感谢您的帮助。

编辑:如果问题不清楚,请发表评论。

【问题讨论】:

  • 如果它是随机的,而且你使用 rgb,为什么你不使用单通道?你也总是以这种方式获得随机值......
  • 不知道为什么你认为你不能为此使用 RGB。只需选择一个起始 RGB 颜色(如果您愿意,您可以随机分配所有 3 个颜色),然后将它们全部乘以一个标量常数。如果常数大于1,它会变得更亮。如果小于 1 会变暗。
  • 不知道你的意思,丹尼尔。你能试着重申一下吗? @ user1118321 这会产生与单独改变亮度相同的颜色吗?感觉会有些许变化。它会变得更轻,但我的色调和饱和度控制较少,更不用说其他光线问题了,尽管如果没有其他方法,IO 可能不得不尝试一下。不过说实话,如果能找到公式的问题,我认为HSL会很容易使用。这个公式在我见过的地方似乎是一样的(至少四次),它一定对某些人有用。你知道为什么它不起作用
  • 它不能保证你得到与只改变亮度相同的结果,但听起来这对于这种情况来说并不重要。如果是,我建议改用 Y'CbCr。请参阅我的answer here 了解更多信息。
  • 看过那些。不幸的是,我很容易承认,我完全迷失了你指给我的方法是如何工作的。 (使用色度)。因此,我决定尝试您的其他方法,据我所知,它产生了令人惊讶的令人满意的结果,所以如果所有其他方法都失败了,我可能会使用它。虽然,您似乎很了解颜色系统。即使您可能不推荐它,您能否推断出它为什么不起作用?一件整洁的事情是,您不仅可以调整光线,还可以调整色调和饱和度。我不确定饱和度何时会非常有用,但我认为色调和-

标签: c++ colors rgb hsl


【解决方案1】:

你的前提是错误的。您可以缩放 RGB 颜色。例如,Java 中的 Color 类包括名为 .darker() 和 .brighter() 的命令,这些命令使用 0.7 倍,但您可以使用任何您想要的。

public Color darker() {
    return new Color(Math.max((int)(getRed()  *FACTOR), 0),
                     Math.max((int)(getGreen()*FACTOR), 0),
                     Math.max((int)(getBlue() *FACTOR), 0),
                     getAlpha());
}

public Color brighter() {
    int r = getRed();
    int g = getGreen();
    int b = getBlue();
    int alpha = getAlpha();

    /* From 2D group:
     * 1. black.brighter() should return grey
     * 2. applying brighter to blue will always return blue, brighter
     * 3. non pure color (non zero rgb) will eventually return white
     */
    int i = (int)(1.0/(1.0-FACTOR));
    if ( r == 0 && g == 0 && b == 0) {
        return new Color(i, i, i, alpha);
    }
    if ( r > 0 && r < i ) r = i;
    if ( g > 0 && g < i ) g = i;
    if ( b > 0 && b < i ) b = i;

    return new Color(Math.min((int)(r/FACTOR), 255),
                     Math.min((int)(g/FACTOR), 255),
                     Math.min((int)(b/FACTOR), 255),
                     alpha);
}

简而言之,将所有三种颜色乘以相同的静态因子,您将获得相同的颜色比例。这是一个有损操作,您需要确保卷曲颜色以保持在范围内(这比舍入误差更有损)。

坦率地说,任何从 RGB 到 HSV 的转换都只是数学运算,而更改 HSV V 因子只是数学运算,而将其改回则更数学运算。你不需要这些。你可以做数学。这将使最大分量颜色更大,而不会弄乱颜色之间的比例。

--

如果问题更具体,而您只是想要更好的结果。有更好的方法来计算这个。您可以转换为亮度组件,而不是静态缩放亮度(L 不是指亮度)。基本上以特定方式加权。色彩科学和计算与人类观察者打交道,它们比实际数学更重要。为了解释这些人类的一些怪癖,需要“修复”以更类似于普通人类的感知。亮度缩放如下:

Y = 0.2126 R + 0.7152 G + 0.0722 B

这同样反映在权重 30、59、11 中,这些权重被错误地认为是好的颜色距离权重。这些权重是颜色对人类对亮度的感知的贡献。例如,人类认为最亮的蓝色非常暗。而黄色(与蓝色完全相反)被视为如此明亮,以至于您甚至无法在白色背景下辨认出来。 Y'CbCr 包含的许多色彩空间通过缩放来解释这些亮度感知的差异。然后你可以改变那个值,当你缩小它时它会再次被缩放。

导致不同的颜色,这应该更类似于人类所说的相同颜色的“较浅”版本。这个人类系统有越来越好的近似值,因此使用更好、更奇特的数学来解释它通常会给你带来越来越好的结果。

获取有关这些问题的良好概述。 http://www.compuphase.com/cmetric.htm

【讨论】:

  • 感谢您的回答。我的问题不在于解决方案的准确性,您在您的观点中提出的很好,而在于如何达到效果。简单的静态缩放有效,但不适用于我的灯光系统。例如,在我的实现中,我们计算给定渐变的特定光线范围,您可以说,然后将要显示的光线除以将要显示的图层。但是,它没有考虑到已经有的基础颜色。仍然不确定如何,除非那是 0 光,但这并不好。这带来了另一个问题... ...
  • 我喜欢 HSL 的一个原因是它从色调和饱和度开始。我对此的填充是基色,但它很难说明全范围的光线,并且不知道如何进行饱和度,我需要弄清楚如何限制两者。如果照明有效,那么选择色调似乎比基色容易得多。因此,为什么我想尝试 HSL。如果你明白我的意思,我不想让颜色更亮,我想用亮度来做。您知道如何通过静态缩放来实现这一点吗?
  • 重温旧问题。我也从来没有让这个工作,(好吧,我让标量乘法工作得很好)。当时,我不喜欢这个解决方案,因为我只是想弄清楚为什么这个公式不起作用,因为我只是想使用它,这对我的目的来说很有效,并且从更亮/更暗的色调角度来看是有意义的,对我来说,频道没有。不过,我认为您的回答显示了努力,并且当我(相当有信心)重新审视这个问题时,可能会证明是一种宝贵的资源。所以,我回来给你接受。
  • 好吧,如果您重新访问,请注意线性缩放颜色样本正是 HSV 或 RGB 执行该操作所需的。因此,要想做得更好,唯一的方法就是以人眼可以更好地看到差异的方式来做。这意味着您要将其转换为 YCbCr 颜色空间或 Lab 颜色空间,然后缩放 Y 或 L 因子并转换回 RGB。这些都具有非线性和基于眼睛的色调校正以及您从操作开始的基色。
  • 不过,请确保您经济地利用您的时间。尝试将 Color Inspector 3D 作为 ImageJ 的插件,因为它可以让您加载图像并在各种颜色空间中查看它并独立调整每个组件。这样你就可以知道在开始编码之前你会对结果感到满意。您最终可能需要更合适的照明算法,而不是基于高度的伽马校正变化。
猜你喜欢
  • 2011-01-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-25
  • 1970-01-01
  • 2015-10-15
  • 2011-03-29
相关资源
最近更新 更多