如果我有一条从0到1的直线,那么在这条直线上的0处是颜色A(255,0,0),在0.3处是颜色B(20,160,0),在1处是颜色C(0,0,0)。我该如何找到0.7处的颜色?
谢谢。
如果我有一条从0到1的直线,那么在这条直线上的0处是颜色A(255,0,0),在0.3处是颜色B(20,160,0),在1处是颜色C(0,0,0)。我该如何找到0.7处的颜色?
谢谢。
这是一个非常有趣的问题,而且之所以有趣是因为没有“正确”的答案。颜色表示和数据插值可以用许多不同的方式来完成。您需要适当地调整方法以适应您的问题域。由于我们没有得到关于该域的先验信息,因此我们只能探索一些可能性。
颜色业务使事情变得有些复杂,因此让我们暂时将其放在一边,首先考虑简单标量的插值。
假设我们有一些数据点,如下所示:
y
值是多少。也就是说,我们正在寻找一个函数y = f(x)
,使其穿过这些点。我们需要找到一个f(x)
,以便得到所需的y
。根据情况,我们可以使用许多不同的函数,但迄今为止最常用的是使用多项式函数,即:
f(x) = a0 + a1 * x + a2 * x * x + a3 * x * x * x + ....
(x1, y1)
,第二个数据点是(x2, y2)
,那么在任何中间x
处进行线性插值得到的y
值为:y = y1 + (x - x1) * (y2 - y1) / (x2 - x1)
(其他答案中也有类似的变化。)
立方样条曲线在此不便详细讨论,但是谷歌应该可以找到一些不错的参考资料。无论如何,在这种情况下,它们都可能过于复杂,因为您只有三个点。
有了这些基础知识,让我们来看看所描述的问题:
再次强调,这并不是无效的,我们可能有很好的理由以这种方式进行。但在我看来,这比之前的分段线性示例更加超前,因为涉及到外推。
那么在HSV中,这是唯一的方法吗?当然不是。总有更多的选择。
例如,我们可以选择将H和S值设为1.0以最大化线性度,或者我们可以选择将它们设为最小化分段线性插值的变化。碰巧的是,对于S,这两种策略是一致的:两个点都是100,所以我们在最后也将其设为100。这两个线段是共线的。对于H,我们只需在第二个线段上保持不变即可。这样就得到了以下结果:
这个不像之前那个那么可爱,但在我看来似乎更有可能。再一次地,这主要是审美判断。这并不意味着这就是“正确”的答案,就像它也不会使Patrick或其他任何人的答案变得“错误”一样。正如我在一开始所说的那样,没有“正确”的答案。这都是根据你在特定问题中的需求做出选择的问题——并且知道你已经做出了这些选择以及它们如何影响你的结果。
?表示实际上并不重要(因为颜色C只是黑色)。
现在也将颜色B转换为HSV(抱歉,我无法脱口而出),然后选择漂亮的值作为颜色C的色相和饱和度,使得颜色C的色相、亮度和饱和度在HSV空间中处于一条直线上。然后从中减去0.7的颜色。
编辑:使用http://www.csgnetwork.com/csgcolorsel4.html上的RGB-HSV计算器,我计算出以下内容:
现在我们像这样计算颜色C的H和V:
这给了我们0.7时的颜色:
不幸的是,这并不完全符合饱和度,但如果您以这种方式进行插值,将会得到非常接近所需颜色的结果。
看起来你正在尝试在错误的颜色空间中进行插值。首先将其转换为HSV,然后你的颜色就会变成:
RGB -> HSV
255,0,0 -> 0, 255,255
20,160,0 -> 80,255,160
0,0,0 -> 0,255,0
所以现在还是有点困惑,但至少我们可以看到 V 值正在插值为零,H 值仍然有些困惑,但在意识到 HSV 被建模为一个圆柱体后,我们可以看到它实际上只是从 0 插值到 256 模 256,所以它最终会回到零。
因此,你的方程式将是(在 HSV 中)
nH = frac*256 mod 256
nS = 255
nV = (1-frac)*255
如果你将0.7替换为frac,你将在HSV坐标中得到正确的计算结果,如果你需要返回RGB,你应该查看你的库是否提供这样的功能(我知道Java的Color类支持此功能),但如果没有,你可以从这里获取代码。它展示了如何在C中进行颜色空间转换。
祝好运