【问题标题】:Can't convert from HSL to RGB无法从 HSL 转换为 RGB
【发布时间】:2012-11-04 15:15:12
【问题描述】:

我在将颜色从 HSL 转换为 RGB 时遇到问题。我写了以下函数:

struct RGB {
    float r, g, b;
};
RGB hslToRgb( float hue, float saturation, float lightness ) {

    RGB rgb1, rgbResult;

    float chroma = ( 1.0 - (float) abs( 2.0 * lightness - 1.0 ) ) * saturation;
    float h1 = hue / 60.0;
    float x = chroma * ( 1.0 - (float) abs( (float) ( (int) h1 % 2 ) - 1.0 ) );

    if ( ( 0 <= h1 ) && ( h1 < 1 ) ) {

        rgb1.r = chroma;
        rgb1.g = x;
        rgb1.b = 0.0;

    } else if ( ( 1 <= h1 ) && ( h1 < 2 ) ) {

        rgb1.r = x;
        rgb1.g = chroma;
        rgb1.b = 0.0;

    } else if ( ( 2 <= h1 ) && ( h1 < 3 ) ) {

        rgb1.r = 0.0;
        rgb1.g = chroma;
        rgb1.b = x;

    } else if ( ( 3 <= h1 ) && ( h1 < 4 ) ) {

        rgb1.r = 0.0;
        rgb1.g = x;
        rgb1.b = chroma;

    } else if ( ( 4 <= h1 ) && ( h1 < 5 ) ) {

        rgb1.r = x;
        rgb1.g = 0.0;
        rgb1.b = chroma;

    } else if ( ( 5 <= h1 ) && ( h1 < 6 ) ) {

        rgb1.r = chroma;
        rgb1.g = 0;
        rgb1.b = x;

    } else {

        rgb1.r = 0.0;
        rgb1.g = 0.0;
        rgb1.b = 0.0;

    }

    float m = lightness - 0.5 * chroma;

    rgbResult.r = rgb1.r + m;
    rgbResult.g = rgb1.g + m;
    rgbResult.b = rgb1.b + m;

    return rgbResult;

}

这是它的测试:

float cHue = 0.0;
while ( cHue < 360 ) {
    RGB rgb1 = hslToRgb( (int) cHue, 1.0, 0.5 ); // max on saturation and a middle value for lightness
    printf( "r = %f, g = %f, b = %f\n", rgb1.r, rgb1.g, rgb1.b );
    cHue += 1.0;
}

但是当我需要得到这个“整数”之间的所有范围时,我只得到 1.0 和 0.0。

r = 1.000000, g = 0.000000, b = 1.000000
r = 1.000000, g = 0.000000, b = 1.000000
r = 1.000000, g = 0.000000, b = 1.000000
r = 1.000000, g = 0.000000, b = 0.000000
r = 1.000000, g = 0.000000, b = 0.000000
r = 1.000000, g = 0.000000, b = 0.000000

谁能帮我处理这段代码? 公式来自:http://en.wikipedia.org/wiki/HSL_and_HSV

【问题讨论】:

  • ( 1 &lt;= h1 ) 测试是多余且不必要的,因为您使用的是 else if。
  • @Shmiddty,为什么...?例如,如果我们有 h1 == 3.4,它会运行第四个“if”代码块。不是吗?
  • 您可以将其简化为:if (h1 &lt; 1) {...} else if (h1 &lt; 2){...} 等,因为如果h1 &gt;= 11 &lt;= h1 相同,则第一个测试将失败。测试是多余的。

标签: c++ colors rgb hsl


【解决方案1】:

停止在 C++ 代码中使用 C 风格的强制转换(如 (int)(float))。当您需要浮点绝对函数时,请使用fabs。将复杂的公式分解为许多步骤,您不会通过一行完成所有步骤来获得任何效率。

每行进行 1 次计算。将结果存储在您认为需要的类型的变量中,并使用描述性名称。看看你是否可以避免使用int,除非你应该明确地四舍五入。

【讨论】:

  • 而不是fabs,您应该真正使用std::abs,它为每种类型正确重载,尽管在不同的标题中:浮点重载在&lt;cmath&gt;,整数版本在&lt;cstdlib&gt;complexvalarray 模板位于各自的类头中。
【解决方案2】:

使用浮点模 fmodf 为:

float x = chroma * ( 1.0 - (float) abs( fmodf(h1, 2.0) - 1.0 ));

【讨论】:

  • 哇。优秀的解决方案!它工作得很好。我不知道这个功能:) 谢谢!
  • 你也可以使用 fabsf 代替 abs 来避免转换为 double
【解决方案3】:

您的色度值似乎不对。你有它

float chroma = ( 1.0 - (float) abs( 2.0 * lightness - 1.0 ) ) * saturation;

但我认为应该是

float chroma = saturation * lightness;

因为维基百科说,

From HSV

Given a color with hue H ∈ [0°, 360°), saturation SHSV ∈ [0, 1], and value V ∈ [0, 1],
we first find chroma:

C = V \times S_{HSV}

【讨论】:

  • 它用于 HSV,但我处理 HSL :)
【解决方案4】:

在你的线上:

float x = chroma * ( 1.0 - (float) abs( (float) ( (int) h1 % 2 ) - 1.0 ) );

您对模数的(int) 强制转换会导致它删除浮点数的所有小数。从而使它成为一个二元函数。

您需要一个浮点模数函数,例如Michael Sh described

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-29
    • 1970-01-01
    • 2016-08-11
    • 1970-01-01
    • 2017-09-28
    • 1970-01-01
    • 1970-01-01
    • 2014-09-21
    相关资源
    最近更新 更多