11

我可能没有使用正确的颜色术语,但我希望基本上能够缩放类似于所附图片的颜色。我一直在寻找饱和度来做到这一点,因为看起来右边的版本只是左边的饱和度较低的版本。

在此处输入图像描述

我正在尝试这个(我发现)但它看起来根本不正确:

Public Shared Function GetDesaturatedColor(color As Color) As Color
    Const kValue As Double = 0.01R

    Dim greyLevel = (color.R * 0.299R) + _
                    (color.G * 0.587R) + _
                    (color.B * 0.144R)

    Dim r = greyLevel * kValue + (color.R) * (1 - kValue)
    Dim g = greyLevel * kValue + (color.G) * (1 - kValue)
    Dim b = greyLevel * kValue + (color.B) * (1 - kValue)

    ' ColorUtils.ToByte converts the double value 
    ' to a byte safely
    Return color.FromArgb(255, _
                          ColorUtils.ToByte(r), _
                          ColorUtils.ToByte(g), _
                          ColorUtils.ToByte(b))
End Function

有谁知道一些可以做到这一点的算法?

4

4 回答 4

17

对于那些想要避免将所有内容都转换为 HSL/HSV 并返回的人来说,这工作得相当好(如果不正确,取决于人们认为“正确”的去饱和图像是什么):

f = 0.2; // desaturate by 20%
L = 0.3*r + 0.6*g + 0.1*b;
new_r = r + f * (L - r);
new_g = g + f * (L - g);
new_b = b + f * (L - b);

这是使用绿色、红色和蓝色分别对应于图像降低比例的亮度的共同假设将 r、g、b 转换为灰度。所以 L 是灰度图像,然后 f 只是在输入 RGB 图像和该灰度图像之间进行线性插值。

于 2013-12-28T23:52:27.723 回答
4

正如@Brad 在您帖子的评论中提到的,您的第一步是将颜色从 RGB 转换为HSL 或 HSV。从那里开始,降低饱和度是微不足道的 - 只需将饱和度减去或除以一个值即可降低它。

之后,将您的 HSL/HSV 颜色转换回 RGB,即可使用。

如何将 RGB 颜色更改为 HSV?有一个很好的例子来说明如何做到这一点,就像在 .net 中操纵颜色一样。

于 2012-11-11T02:32:12.163 回答
2

实验表明,仅仅降低饱和度并不足以得到图中所示的结果。我在下面显示的代码中使用了 OP 问题中的颜色。如果你只是降低饱和度,你会得到:

在此处输入图像描述

如果还降低新颜色的 alpha/opacity,则可以获得更好的结果:

在此处输入图像描述

我假设如果你使用参数,你应该能够得到一个完美的匹配。尝试更改alphareducedSaturation2当前 =40)和GetSaturation除法器(当前 =1.3)

这是我的代码示例:

Public Function HSVToColor(ByVal H As Double, ByVal S As Double, ByVal V As Double) As Color
  Dim Hi As Integer = (H / 60) Mod 6
  Dim f As Double = H / 60 Mod 1
  Dim p As Integer = V * (1 - S) * 255
  Dim q As Integer = V * (1 - f * S) * 255
  Dim t As Integer = V * (1 - (1 - f) * S) * 255
  Select Case Hi
    Case 0 : Return Color.FromArgb(V * 255, t, p)
    Case 1 : Return Color.FromArgb(q, V * 255, p)
    Case 2 : Return Color.FromArgb(p, V * 255, t)
    Case 3 : Return Color.FromArgb(p, V * 255, q)
    Case 4 : Return Color.FromArgb(t, p, V * 255)
    Case 5 : Return Color.FromArgb(V * 255, q, p)
  End Select
End Function

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
  Dim normalSaturation As Color = Color.FromArgb(255, 216, 53, 45)
  Me.CreateGraphics.FillRectangle(New SolidBrush(normalSaturation), 100, 0, 100, 100)
  Dim reducedSaturation As Color = HSVToColor(normalSaturation.GetHue, normalSaturation.GetSaturation / 1.3, normalSaturation.GetBrightness)
  Dim reducedSaturation2 As Color = Color.FromArgb(40, reducedSaturation)
  Me.CreateGraphics.FillRectangle(New SolidBrush(reducedSaturation2), 0, 0, 100, 100)
End Sub
于 2012-11-11T03:21:19.770 回答
1

Color这是我在 C#中更改给定饱和度的公式。结果等同于应用 CSS-effect filter: saturate(...),因为这是 W3C 规范使用的公式。

private static Color Saturate(Color c, double saturation) {
   // Values from: https://www.w3.org/TR/filter-effects-1/#feColorMatrixElement , type="saturate"
   var s = saturation;
   Func<double, int> clamp = i => Math.Min(255, Math.Max(0, Convert.ToInt32(i)));
   return Color.FromArgb(255,
      clamp((0.213 + 0.787 * s) * c.R + (0.715 - 0.715 * s) * c.G + (0.072 - 0.072 * s) * c.B),
      clamp((0.213 - 0.213 * s) * c.R + (0.715 + 0.285 * s) * c.G + (0.072 - 0.072 * s) * c.B),
      clamp((0.213 - 0.213 * s) * c.R + (0.715 - 0.715 * s) * c.G + (0.072 + 0.928 * s) * c.B));
}
于 2020-02-11T20:17:13.290 回答