C语言中快速、优化且准确的RGB <-> HSB转换代码

3
我正在寻找一种快速、准确的RGB到HSB和HSB到RGB的纯C实现。请注意,我特别寻找色相、饱和度、亮度,而不是HSL(亮度)。
当然,我已经进行了广泛的谷歌搜索,但速度是最重要的,我正在寻找任何可靠、快速、可靠的代码的具体建议。

除非由于某种外部要求而必须使用HSB,否则请放弃它。HSB(以及HSL)是一种基本上有缺陷的颜色模型,与现实无关,并且会导致可怕的事情,例如当您更改颜色的色调时,颜色的强度也会发生变化。(从数学上讲,转换为灰度不符合色调轮旋转的交换律。) - R.. GitHub STOP HELPING ICE
4个回答

6
这是一个标准C语言的简单实现。
在没有更多上下文信息的情况下,这已经足够好了。也许您可以提供更多的信息:
- 您如何存储RGB样本(首先是每像素的位数)? - 您如何存储像素数据(如果要高效地转换较大的缓冲区,组织方式是什么)? - 您希望如何表示输出(我现在假设使用浮点数)?
我可以提供进一步优化的版本(也许可以很好地利用SSE4指令……)。
尽管如此,当进行优化编译时,这个实现并不差。
#include <stdio.h>
#include <math.h>

typedef struct RGB_t { unsigned char red, green, blue; } RGB;
typedef struct HSB_t { float hue, saturation, brightness; } HSB;

/*
 * Returns the hue, saturation, and brightness of the color.
 */
void RgbToHsb(struct RGB_t rgb, struct HSB_t* outHsb)
{
    // TODO check arguments

    float r = rgb.red / 255.0f;
    float g = rgb.green / 255.0f;
    float b = rgb.blue / 255.0f;
    float max = fmaxf(fmaxf(r, g), b);
    float min = fminf(fminf(r, g), b);
    float delta = max - min;
    if (delta != 0)
    {
        float hue;
        if (r == max)
        {
            hue = (g - b) / delta;
        }
        else
        {
            if (g == max)
            {
                hue = 2 + (b - r) / delta;
            }
            else
            {
                hue = 4 + (r - g) / delta;
            }
        }
        hue *= 60;
        if (hue < 0) hue += 360;
        outHsb->hue = hue;
    }
    else
    {
        outHsb->hue = 0;
    }
    outHsb->saturation = max == 0 ? 0 : (max - min) / max;
    outHsb->brightness = max;
}

典型用法和测试:

int main()
{
    struct RGB_t rgb = { 132, 34, 255 };
    struct HSB_t hsb;

    RgbToHsb(rgb, &hsb);

    printf("RGB(%u,%u,%u) -> HSB(%f,%f,%f)\n", rgb.red, rgb.green, rgb.blue,
           hsb.hue, hsb.saturation, hsb.brightness);
    // prints: RGB(132,34,255) -> HSB(266.606354,0.866667,1.000000)

    return 0;
}

这是sRGB还是线性RGB? - AldaronLau
1
找到答案了,https://en.wikipedia.org/wiki/List_of_color_spaces_and_their_uses#HSV_and_HSL 上写着:HSV 基于 sRGB 颜色空间。 - AldaronLau

3

首先

HSB 和 HLS 是在用户需以数字来规定颜色时开发的,用于指定色相、饱和度和亮度(或者是色相、明度和饱和度)。然而,这些通常的 HSB 和 HLS 公式与人类色觉特性的不同之处存在缺陷。现在用户可以通过视觉选择颜色,或选择与其他媒体相关的颜色(例如 PANTONE),或使用基于感知的系统(如 L*u*v* 和 L*a*b*),因此应该放弃使用 HSB 和 HLS。【来源】

查看开源 Java 实现 这里

Boost 库(我知道,是 C++)曾经似乎包含 HSB 转换,但现在我只能找到亮度转换(这里


1

快速RGB到HSV浮点转换来自lolengine.net,它采用了“常见”的RGB2HSV实现,并做出以下观察:

只有色调偏移K会改变。现在的想法是:

  • 使用比较对三元组(r,g,b)进行排序
  • 在排序三元组时构建K
  • 执行最终计算

我们注意到,最后一次交换有效地改变了K和g-b的符号。由于两者都被添加并传递给fabs(),因此可以实际上省略符号反转。

最后一步看起来像C代码,但它们的最终形式是C++,可以轻松转换为C:

static void RGB2HSV(float r, float g, float b,
                    float &h, float &s, float &v)
{
    float K = 0.f;

    if (g < b)
    {
        std::swap(g, b);
        K = -1.f;
    }

    if (r < g)
    {
        std::swap(r, g);
        K = -2.f / 6.f - K;
    }

    float chroma = r - std::min(g, b);
    h = fabs(K + (g - b) / (6.f * chroma + 1e-20f));
    s = chroma / (r + 1e-20f);
    v = r;
}

1
我建议使用查找表来存储HSB和RGB值。首先将RGB值(假设每个组件为8位)转换为16位值(每个组件5位)。 HSB值也是16位值,可以通过相同的方式进行转换,这里,色调组件应该使用比饱和度和亮度更多的位,可能是每个组件8位,而饱和度和亮度各4位。当然,在从HSB转换为RGB时,反过来适用相同的规则。

优化策略方面提供了很好的提示。然而,所做出的权衡是无法争辩的;原帖中的要求过于模糊(快速、_准确_实现)。 - sehe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接