• Create Account

## colormath: Desaturation

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

15 replies to this topic

### #1genesys  Members

133
Like
0Likes
Like

Posted 02 February 2006 - 06:10 PM

Hi! I want to desaturate my colors in a shader... the question is: What's the most performant way to do desaturation? I thought about converting from RGB to HSV and then back to RGB but the formulas i found on wikipedia look a lil bit complex - so i don't think that this is the best way to do it... Every Hint is appreciated! Thx!

### #2 Anonymous Poster_Anonymous Poster_*   Guests

0Likes

Posted 02 February 2006 - 06:33 PM

I'm not a maths guru but seems to me that you can do something like this:

Greyscale Intensity = 0.3 * red + 0.59 * green + 0.11 * blue

so to desaturate you would just lerp:

new_pixel.R = Intensity * K + old_pixel.R * (1 - K)
new_pixel.G = Intensity * K + old_pixel.G * (1 - K)
new_pixel.B = Intensity * K + old_pixel.B * (1 - K)

so K would range from 0.0 to 1.0 where 0 gives new pixel = old pixel and 1.0 for fully desaturated.

If I'm off the mark then sorry: I was just heading off to bed for a much needed sleep.

(Watch the debate that will follow about the constants 0.3, 0.59, 0.11)

### #3genesys  Members

133
Like
0Likes
Like

Posted 02 February 2006 - 11:42 PM

hmmmm . . . 0.3, 0.59, 0.11 ? i don't understand...

### #4Red_falcon  Members

151
Like
0Likes
Like

Posted 03 February 2006 - 12:09 AM

Just multiply every color component with 0.3 for red, 0.59 for green, 0.11 for blue.

this are the values for color conversion to grayscale. search with google for color conversion and yo will find many other algorithms

http://www.easyrgb.com/math.html
http://astronomy.swin.edu.au/~pbourke/colour/

### #5genesys  Members

133
Like
0Likes
Like

Posted 03 February 2006 - 02:17 AM

sure? how can this be?? if you multiply plain white (1.0,1.0,1.0) with these values you get (0.3,0.59,0.11) which is green!?

### #6Kalidor  Members

1087
Like
0Likes
Like

Posted 03 February 2006 - 02:23 AM

Quote:
 Original post by genesyssure? how can this be?? if you multiply plain white (1.0,1.0,1.0) with these values you get (0.3,0.59,0.11) which is green!?
No, you do a dot product of the color and (0.3, 0.59, 0.11) to get a grayscale intensity value. If you were converting to grayscale you would set each color channel to this intensity. What the AP was suggesting is to get this grayscale intensity and then linear interpolate between it and the original color to get your desaturation.

### #7quasar3d  Members

810
Like
0Likes
Like

Posted 03 February 2006 - 02:35 AM

Quote:
 Original post by genesyssure? how can this be?? if you multiply plain white (1.0,1.0,1.0) with these values you get (0.3,0.59,0.11) which is green!?

1 * .3 = .3
1 * .59 = .59
1 * .11 = .11
----------------+
intensity = .3 + .59 + .11 = 1

r = intensity
g = intensity
b = intensity

427
Like
0Likes
Like

Posted 03 February 2006 - 08:27 AM

if you're just trying to change the image into grayscale, I believe that taking the average of the r,g,b channels and replacing them with it, should work.
m = .33333f*(r+g+b);r=g=b=m;

### #9 Anonymous Poster_Anonymous Poster_*   Guests

0Likes

Posted 03 February 2006 - 09:46 AM

Using the different weights for the red, green, and blue values (.3, .59, .11) might provide better looking results than just averaging the values, and since it is a dot product it might even be possible to calculate it as quickly as the average. The different values for each component reflect the eye's sensitivity to each color. A fully saturated green appears brighter than a fully saturated blue.

### #10genesys  Members

133
Like
0Likes
Like

Posted 03 February 2006 - 01:41 PM

I don't want to desaturate the colors completely! just a lil bit!

### #11Matei  Members

190
Like
0Likes
Like

Posted 03 February 2006 - 04:06 PM

In that case blend a little between the completely desaturated colour and the original colour. Do something like 0.9 * original_color + 0.1 * desaturated_color.

### #12genesys  Members

133
Like
0Likes
Like

Posted 03 February 2006 - 10:01 PM

oh ok! i understand!

taht's working :) thanks!

just one mor question: perhaps there is a less accurate but (for small saturation changes) working formula with less operations?

### #13S1CA  Members

1414
Like
0Likes
Like

Posted 05 February 2006 - 05:15 AM

For more colour manipulation ideas using interpolation/extrapolation, see the following: http://www.sgi.com/misc/grafica/interp/index.html

Quote:
 just one mor question: perhaps there is a less accurate but (for small saturation changes) working formula with less operations?

The linear interpolations posted above can be done with a single pixel shader 1.1 instruction, you won't find much less than 1![smile]

HLSL:
const float3 coef = {0.3, 0.59, 0.11};
out.rgb = lerp(in.rgb, coef.rgb, amount);

PS1.1:
def c0, amount, 0, 0, 0
def c1, 0.3, 0.59, 0.11, 1
lrp r0.rgb, c0.r, r0.rgb, c1.rgb ; r0=input and output

### #14 Anonymous Poster_Anonymous Poster_*   Guests

0Likes

Posted 05 February 2006 - 05:32 AM

Quote:
 The linear interpolations posted above can be done with a single pixel shader 1.1 instruction, you won't find much less than 1!

### #15 Anonymous Poster_Anonymous Poster_*   Guests

0Likes

Posted 05 February 2006 - 05:36 AM

Anonymous Poster: Not one instruction, you forgot to do the dot product:

(Without knowing exact HLSL syntax)

HLSL:
const float3 coef = {0.3, 0.59, 0.11};
out.rgb = lerp(in.rgb, dot3(coef.rgb, in.rgb), amount);

PS1.1:
def c0, amount, 0, 0, 0
def c1, 0.3, 0.59, 0.11, 1
; r0=input and output
dot3 r1.rgb, c1.rgb, r0.rgb
lrp r0.rgb, c0.r, r0.rgb, r1.rgb

### #16S1CA  Members

1414
Like
0Likes
Like

Posted 05 February 2006 - 06:10 AM

Quote:
 Original post by Anonymous PosterAnonymous Poster: Not one instruction, you forgot to do the dot product:(Without knowing exact HLSL syntax)HLSL:const float3 coef = {0.3, 0.59, 0.11};out.rgb = lerp(in.rgb, dot3(coef.rgb, in.rgb), amount);PS1.1:def c0, amount, 0, 0, 0def c1, 0.3, 0.59, 0.11, 1; r0=input and outputdot3 r1.rgb, c1.rgb, r0.rgblrp r0.rgb, c0.r, r0.rgb, r1.rgb

AP: Oops, my bad, yep you're quite right.

OP: So if you don't already have the luminance of the source image elsewhere in your shader, you'll have to dot the input colour against the coefficients to get it.

That said, luminance being scalar does open up some opportunities for co-issuing, so in most non-trivial pixel shaders, I'd still expect the whole desaturation operation to take only 1-1.5 effective instruction slots (or to be able to tag some extra functionality onto the operation to save elsewhere).

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.