如何插入一个颜色序列

How to interpolate a color sequence?

本文关键字:一个 颜色 插入 何插入      更新时间:2023-10-16

我需要插入或逐渐改变颜色序列,所以它从colorA到colorB到colorC再到colorD,然后再回到colorA,这需要基于以毫秒为单位的时间,任何帮助将非常感激(算法,伪代码将是伟大的)。

请注意,我正在使用RGB,它可以是0-255或0.0-1.0范围。

这是我目前所做的,我需要改变每一个"timePeriod"的颜色,然后我计算经过的时间百分比并改变颜色,这段代码的问题是当它从a到B再到B到C时有一个跳跃,等等

int millisNow = ofGetElapsedTimeMillis();
int millisSinceLastCheck = millisNow - lastTimeCheck;
if ( millisSinceLastCheck > timePeriod ) {
    lastTimeCheck = millisNow;
    millisSinceLastCheck = 0;
    colorsIndex++;
    if ( colorsIndex == colors.size()-1 ) colorsIndex = 0;
    cout << "color indes: " << colorsIndex << endl;
    cout << "color indes: " << colorsIndex + 1 << endl;
}
timeFraction = (float)(millisSinceLastCheck) / (float)(timePeriod);
float p = timeFraction;
colorT.r = colors[colorsIndex].r * p + ( colors[colorsIndex+1].r * ( 1.0 - p ) );
colorT.g = colors[colorsIndex].g * p + ( colors[colorsIndex+1].g * ( 1.0 - p ) );
colorT.b = colors[colorsIndex].b * p + ( colors[colorsIndex+1].b * ( 1.0 - p ) );
colorT.normalize();

Thanks in advance

你的代码大部分是正确的,但你正在做反向插值:即你是插值B->A,然后C->B,然后D->C,等等。这将导致切换颜色时的不连续性。

你应该替换这个:

colorT.r = colors[colorsIndex].r * p + ( colors[colorsIndex+1].r * ( 1.0 - p ) );

:

colorT.r = colors[colorsIndex].r * (1.0 - p) + ( colors[colorsIndex+1].r * p );

,其他行也一样。

另外,正如其他人所说,使用不同于RGB的颜色空间可以提供更好的效果。

有两种处理颜色插值的方法。一个是快速和简单的(你正在做的),另一个稍微慢一点,但在某些情况下看起来更好。

第一个是(x * s) + (y * (1-s))的明显、简单的方法,它是纯线性插值,顾名思义。然而,在某些颜色对(比如绿色和橙色)上,你会在中间得到一些令人讨厌的颜色(脏棕色)。这是因为你在帮助每个组件(R, G和B),并且有些组合是不愉快的。如果你只需要最基本的lerp,那么这就是你想要的方法,你的代码是正确的。

如果你想要一个更好看但稍微慢一点的效果,你会想要在HSL色彩空间中插入。由于色调,饱和度和亮度都是内插的,所以你可以得到你想要的颜色,并且可以避免大多数难看的颜色。由于颜色通常是在某种轮中绘制的,因此该方法意识到这一点(基本RGB lerp的行为就像它与3条离散的线一起工作)。

要使用HSL lerp,您需要转换RGB值,在结果之间进行lerp,然后再转换回来。这个页面有一些公式,可能是有用的,这一个有PHP代码来处理它。

插入R、G和B组件将生成工作代码。一个缺点是,您生成的步骤不一定看起来相同,即使它们在数学上是相等的。

如果这让你感到困扰,你可以将值从RGB转换为L*a*b*之类的东西(旨在更接近人类感知),对这些值进行插值,然后将每个插值值转换回RGB以供显示

你已经得到的看起来很好,但我想简化一下数学:

int millisNow = ofGetElapsedTimeMillis();
int millisSinceLastCheck = millisNow % timerPeriod;
int colorsIndex = (millisNow / timerPerod) % (colors.size() - 1);

float p = (float)(millisSinceLastCheck) / (float)(timePeriod);
colorT.r = colors[colorsIndex+1].r * p + ( colors[colorsIndex].r * ( 1.0 - p ) );
colorT.g = colors[colorsIndex+1].g * p + ( colors[colorsIndex].g * ( 1.0 - p ) );
colorT.b = colors[colorsIndex+1].b * p + ( colors[colorsIndex].b * ( 1.0 - p ) );
colorT.normalize();

我们正在做一个项目。我们只是单独处理R, G, B值,并根据中间有多少"步骤"从color1过渡到color2。我们有离散值,所以我们有一个查找表的方法,但你可以对浮点做同样的事情,只是动态计算RGB值。

如果你还有问题,我可以贴一些Java代码。

分离三个组件(RBG)并分别插入分别使用经典插值算法。