【问题标题】:What is the best way to average two colors that define a linear gradient?平均定义线性渐变的两种颜色的最佳方法是什么?
【发布时间】:2010-10-13 13:30:23
【问题描述】:

如果我有两种颜色由它们的 RGB 值定义,我可以平均红色、绿色和蓝色值,然后组合定义看起来像这两种颜色的视觉平均值的第三种颜色吗?

即NewColor = (R1+R2)/2,(G1+G2)/2,(B1+B2)/2

EDIT1:感谢所有回复。对于我目前的需求,我只处理颜色相同的颜色对,所以我认为平均它们会起作用。不过,我会尝试转换为 Lab Space,以确保该假设是正确的,并且该技术将在未来派上用场。

EDIT2:这是我的结果 FWIW。 Color1 和 Color2 是我的两种颜色,中间的两列分别是 Lab 空间平均和 RGB 平均的结果。在这种情况下,两种颜色之间没有太大差异,因此平均技术的输出差异很细微。

【问题讨论】:

  • 好问题。有时我自己也想知道这一点。

标签: colors rgb


【解决方案1】:

我不知道从感知的角度来看,对组件进行简单平均是否是“最佳”(这听起来像是心理学家的问题),但这里有几个使用简单组件平均的示例。

红色-芥末-绿色很丑,但插值似乎足够合理。

【讨论】:

  • 我知道一张图片值一千个字,但有时你也可以用一些字
【解决方案2】:

HSL color space 中取平均值可能会产生更好的结果。

【讨论】:

  • 我认为他的意思是亮度、饱和度、色调。我相信它与 HSV / HSL 是一回事 - 试试维基百科中的那些。
【解决方案3】:

看看this question的答案。

基本上,您希望将颜色转换为称为Lab space 的颜色,并在该空间中找到它们的平均值。

实验室空间是一种表示颜色的方式,其中彼此接近的点是那些在人类看来彼此相似的点。

【讨论】:

  • 有趣。到目前为止,我一直在使用简单的 HSL,但 Lab 看起来值得研究。
  • 我可以使用这个实验室空间来表示一个线性值范围,以将值编码为整个颜色范围内的颜色,而不仅仅是灰色阴影或不同的亮度。 stackoverflow.com/questions/7182318/…
  • 换句话说,就人类感知而言,Lab 空间中的颜色比大多数其他颜色空间中的颜色分布更均匀。这就是为什么 Lab 中的平均颜色更能代表颜色的视觉中心,尤其是当色差很大时(例如,Delta E>4)。当色差较小时,可以在任何颜色空间进行平均。
【解决方案4】:

是的。你可以像这样平均两种颜色。这是 OpenGL 用来将颜色混​​合在一起的方法(例如,创建用于渲染远处物体的 mip 贴图,或渲染 50% 透明纹理)。对于许多情况,它快速、简单且“足够好”。然而,它并不完全真实,可能不会用于照片质量的图像。

【讨论】:

  • 显示器的观看环境和属性对色彩感知有很大影响,所以我同意简单的平均对于大多数情况来说已经足够了。
【解决方案5】:

实际上有一个更简单的方法。

  • 将图像缩小到 1px x 1px。

    1px 的颜色是缩放后的平均颜色

【讨论】:

  • 这是一个奇怪的答案,因为它基本上很糟糕(计算效率极低,并且不能从根本上回答问题),但它确实很实用。这在某些情况下完全有效。
  • 好吧,无论如何,这是一个普通的东西。它的平均值完全取决于程序员在编译图像缩放器当天选择使用的任何算法。如果没有编译,波塞冬能帮到你吗……
【解决方案6】:

一些答案​​建议转换为 Lab 颜色空间 - 这可能是更复杂的颜色操作的好方法。

但如果您只是需要一种快速获取两种颜色的平均值的方法,则可以在 RGB 空间中完成。您只需要注意一个警告:您必须在平均 RGB 值之前对其进行平方,然后对结果求根。 (如果只是取平均值,结果往往会太暗。)

像这样:

NewColor = sqrt((R1^2+R2^2)/2),sqrt((G1^2+G2^2)/2),sqrt((B1^2+B2^2)/2)

这是一个很棒的视频,它解释了为什么这种方法是有效的:https://www.youtube.com/watch?v=LKnqECcg6Gw

【讨论】:

  • 啊哈,一个识别图像在图像世界中使用的对数空间的答案!对于加权混合(即 75% 的颜色 A 和 25% 的颜色 B),请使用 NewColor = sqrt(R1^2*w + R2^2*[1 - w]), sqrt(G1^2*w + G2^2*[1 - w]), sqrt(B1^2*w + B2^2*[1 - w]),其中 w 是从 0 到 1 的权重。
  • 这是大多数人通过 Google 提出这个问题的实际答案。
  • 如何将其推广到任意数量的颜色?我仍然为每个频道提供 sqrt(平方和)吗?
  • 对于 3 种颜色,您除以 3 并像往常一样使用 sqrt root。例如NewColorR = sqrt((R1^2+R2^2+R3^2)/3). This is just for red component. Do same for green` 和blue
  • 有谁知道如何使用opencv实现这个操作?
【解决方案7】:

这很难。首先,一组 RGB 值不定义颜色。它们需要根据它们所指的原色(颜色空间)来解释,例如 sRGB、Rec.709、Rec.2020、Adobe RGB (1998) 等。

此外,我们通常遇到的 RGB 值与线性光不成比例:它们是使用非线性函数(伽马)“编码”的。有时(主要在视频应用程序中)“黑色”的值不是零,而是从零偏移,对于 8 位值通常为 16。而“白色”不是 255 而是 235。sRGB 和 Rec.709 共享 RGB 原色,但它们的 gamma 函数不同。

色彩空间转换从删除任何黑色偏移开始,使黑色为零。如果 gamma 函数中有断点(如 sRGB 和 Rec.709),则需要仔细缩放 RGB 值,使“white”为 1.0。

然后,通过对原始伽马函数进行逆运算来“解码”伽马。 (一个答案建议对值进行平方,这是伽马解码的近似值。)现在您在某些颜色空间中具有线性光 RGB 值。此时,您可以从该颜色空间转换为 Lab 空间。大多数从 RGB 到 Lab 的转换都经过一个称为 XYZ 的中间颜色空间。

嵌套函数调用的步骤:

Lab = XYZ2Lab(RGB2XYZ(gamma_decode(offset_and_scale(RGB), gammaFunction), RGB色彩空间))

(实验室空间是在 1976 年开发的,旨在创建标准 CIE XYZ 空间的感知均匀扭曲。(Luv 是另一种尝试。)这个想法是两种颜色之间的欧几里得(直线)距离任何两种颜色的距离都相同(1“JND”)。Lab 中两种颜色之间的距离称为“delta-E”。简单的 delta 欧几里得距离公式现在称为 dE76。见https://en.wikipedia.org/wiki/Color_difference)

在您的情况下,您可以平均两种 Lab 颜色以获得新的 Lab 颜色,然后反转所有转换以在您选择的颜色空间中恢复为 RGB。

这会让您接近,但不能保证,因为“颜色”是人类的感知,而不是物理量,并且众所周知难以可靠地表征。实验室在感知统一方面实际上并没有那么好。因此,他们没有修复 Lab,而是提出了一个新的、更复杂的 delta-E 函数,并内置了另一个 warp:DE94。这更好,但并不完美,因此在 2000 年出现了另一个提议:DE2000。也更好但并不完美。有关更多信息,请参见上面的 Wiki 页面。

如果 DE2000 不够好(或太复杂!),您可以看看 Lab 的替代品 ICtCp,它声称比 Lab 在感知上更统一。

【讨论】:

    【解决方案8】:

    我认为,arntjw 的答案朝着正确的方向发展,并识别了 Dan W 提到的对数底层。但是,正确的几何平均值不是 sqrt((C1^2+C2^2)/2) , 但 sqrt(C1*C2)。所以平均颜色是:

    NewColor = sqrt(R1*R2),sqrt(G1*G2),sqrt(B1*B2)
    

    生成的颜色更接近我们的预期。您可以使用高阶根泛化到更多颜色,并通过向其分量添加指数来加权每种颜色。

    【讨论】:

    • 对于有 0 个分量的颜色要小心使用它。考虑用纯蓝色 (0, 0, 255) 平均纯红色 (255, 0, 0)。当我们真正期望紫色时,平均值将为黑色。
    • 你能解释一下为什么这是正确的意思吗?另外,您将如何处理平均超过 2 种颜色?你会把它们全部相乘,然后求出你有多少种颜色的根吗?
    猜你喜欢
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 2012-02-07
    • 1970-01-01
    • 2019-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多