RGB颜色的色相转移 [英] Shift hue of an RGB Color

查看:611
本文介绍了RGB颜色的色相转移的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图写一个函数来RGB颜色的色调偏移。具体来说,我正在使用它的iOS应用,但数学是普遍的。

I'm trying to write a function to shift the hue of an RGB color. Specifically I'm using it in an iOS app, but the math is universal.

,下图显示如何对R,G,B值相对于该色相发生变化。

The graph below shows how the R, G, and B values change with respect to the hue.

望着那好像它应该是一个相对简单的写一个函数色调没有做任何讨厌的转换到将引入更多的错误不同的颜色格式切换(这可能是,如果继续应用小转移到一个问题一种颜色),我怀疑会比较计算成本。

Looking at that it seems like it should be a relatively simple to write a function to shift the hue without doing any nasty conversions to a different color format which would introduce more error (which could be an issue if continue applying small shifts to a color), and I suspect would be more computationally expensive.

下面是我迄今为止哪种类型的作品。它完美的作品,如果你从纯粹的黄色或青色或紫红色移位,否则它会在某些地方有点squiffy。

Here is what I have so far which sort of works. It works perfectly if you're shifting from pure yellow or cyan or magenta but otherwise it gets a little squiffy in some places.

Color4f ShiftHue(Color4f c, float d) {
    if (d==0) {
        return c;
    }
    while (d<0) {
        d+=1;
    }

    d *= 3;

    float original[] = {c.red, c.green, c.blue};
    float returned[] = {c.red, c.green, c.blue};

    // big shifts
    for (int i=0; i<3; i++) {
        returned[i] = original[(i+((int) d))%3];
    }
    d -= (float) ((int) d);
    original[0] = returned[0];
    original[1] = returned[1];
    original[2] = returned[2];

    float lower = MIN(MIN(c.red, c.green), c.blue);
    float upper = MAX(MAX(c.red, c.green), c.blue);

    float spread = upper - lower;
    float shift  = spread * d * 2;

    // little shift
    for (int i = 0; i < 3; ++i) {
        // if middle value
        if (original[(i+2)%3]==upper && original[(i+1)%3]==lower) {
            returned[i] -= shift;
            if (returned[i]<lower) {
                returned[(i+1)%3] += lower - returned[i];
                returned[i]=lower;
            } else
                if (returned[i]>upper) {
                    returned[(i+2)%3] -= returned[i] - upper;
                    returned[i]=upper;
                }
            break;
        }
    }

    return Color4fMake(returned[0], returned[1], returned[2], c.alpha);
}

我知道你可以用UIColors做到这一点,色调与这样的转变:

I know you can do this with UIColors and shift the hue with something like this:

CGFloat hue;
CGFloat sat;
CGFloat bri;
[[UIColor colorWithRed:parent.color.red green:parent.color.green blue:parent.color.blue alpha:1] getHue:&hue saturation:&sat brightness:&bri alpha:nil];
hue -= .03;
if (hue<0) {
    hue+=1;
}
UIColor *tempColor = [UIColor colorWithHue:hue saturation:sat brightness:bri alpha:1];
const float* components= CGColorGetComponents(tempColor.CGColor);
color = Color4fMake(components[0], components[1], components[2], 1);

但我不是疯了,由于它只能在iOS 5中,并分配了一些颜色对象,并从RGB转换为HSB,然后回之间似乎pretty矫枉过正。

but I'm not crazy about that as It only works in iOS 5, and between allocating a number of color objects and converting from RGB to HSB and then back it seems pretty overkill.

我可能最终使用查找表或pre-计算的颜色在我的应用程序,但我真的很好奇,如果有一种方法可以让我的code的工作。谢谢!

I might end up using a lookup table or pre-calculate the colors in my application, but I'm really curious if there's a way to make my code work. Thanks!

推荐答案

修改每改意见都到可以通过线性近似。结果
修改2 添加偏移量。

Edit per comment changed "are all" to "can be linearly approximated by".
Edit 2 adding offsets.

从本质上讲,你想要的步骤

Essentially, the steps you want are

RBG->HSV->Update hue->RGB

由于这些的可以通过的线性矩阵变换近似(即它们是关联的),你可以在没有任何讨厌的转换或precision损失在一个步骤执行它。你刚才多次变换矩阵对方,并用它来改变你的颜色。

Since these can be approximated by linear matrix transforms (i.e. they are associative), you can perform it in a single step without any nasty conversion or loss of precision. You just multiple the transform matrices with each other, and use that to transform your colors.

有一个快速的步步这里 http://beesbuzz.biz/$c$c /hsv_color_transforms.php

There's a quick step by step here http://beesbuzz.biz/code/hsv_color_transforms.php

下面是C ++的code(带的饱和度和值变换删除):

Here's the C++ code (With the saturation and value transforms removed):

Color TransformH(
    const Color &in,  // color to transform
    float H
)
{
  float U = cos(H*M_PI/180);
  float W = sin(H*M_PI/180);

  Color ret;
  ret.r = (.299+.701*U+.168*W)*in.r
    + (.587-.587*U+.330*W)*in.g
    + (.114-.114*U-.497*W)*in.b;
  ret.g = (.299-.299*U-.328*W)*in.r
    + (.587+.413*U+.035*W)*in.g
    + (.114-.114*U+.292*W)*in.b;
  ret.b = (.299-.3*U+1.25*W)*in.r
    + (.587-.588*U-1.05*W)*in.g
    + (.114+.886*U-.203*W)*in.b;
  return ret;
}

这篇关于RGB颜色的色相转移的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆