vb.net 如何去饱和颜色?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13328029/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to Desaturate a Color?
提问by test
I might not be using the correct color terminology but I want to basically be able to scale colors similar to the picture attached. I have been searching for saturation to do this, as it appears the right version is just a must less saturated version of the left.
我可能没有使用正确的颜色术语,但我希望基本上能够缩放类似于所附图片的颜色。我一直在寻找饱和度来做到这一点,因为看起来正确的版本只是左边的饱和度较低的版本。


I was trying this (which I found) but it is not looking correct at all:
我正在尝试这个(我发现),但它看起来根本不正确:
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
Does anyone know of some algorithm that can do this?
有谁知道一些可以做到这一点的算法?
采纳答案by Fabian Tamp
As @Brad mentioned in the comments to your post, your first step is to convert the colours from RGB to either HSL or HSV. From there, reducing the saturation is trivial - just subtract or divide the saturation by a value to reduce it.
正如@Brad 在您帖子的评论中提到的,您的第一步是将颜色从 RGB 转换为HSL 或 HSV。从那里,降低饱和度是微不足道的 - 只需将饱和度减去或除以一个值即可降低饱和度。
After that, convert your HSL/HSV color back into RGB and it's ready for use.
之后,将您的 HSL/HSV 颜色转换回 RGB,即可使用。
How to change RGB color to HSV?has a good example of how to do this, as does Manipulating colors in .net.
如何将RGB颜色更改为HSV?有一个很好的例子来说明如何做到这一点,就像在 .net中操作颜色一样。
回答by Alec Jacobson
For those that want to avoid converting everything to HSL/HSV and back, this works reasonably well (if not correctly depending on what one thinks the "correct" desaturated image is):
对于那些想要避免将所有内容转换为 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);
回答by Neolisk
It appears by experiment that just reducing saturation is not enough to get the result shown in the picture. I used the colors from OP's question in the code shown below. If you just reduce saturation, here is what you get:
实验表明,仅仅降低饱和度并不足以得到如图所示的结果。我在下面显示的代码中使用了来自 OP 问题的颜色。如果你只是降低饱和度,这就是你得到的:


If you also reduce alpha/opacity of the new color, you can achieve a better result:
如果您还降低新颜色的 alpha/opacity,则可以获得更好的结果:


I am assuming if you play with parameters, you should be able to get a perfect match. Try changing alphafor reducedSaturation2(currently =40) and GetSaturationdivider (currently =1.3)
我假设如果你玩参数,你应该能够得到一个完美的匹配。尝试更改alpha为reducedSaturation2(当前 =40)和GetSaturation分频器(当前 =1.3)
Here is my code sample:
这是我的代码示例:
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
回答by Andi
Here is my formula for changing the saturation of a given Colorin C#. The result is equal to applying the CSS-effect filter: saturate(...), because this is the formula used by the W3C spec.
这是我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));
}

