RGB to photoshop HSY?

683 views
Skip to first unread message

Mathieu Leclaire

unread,
Jul 17, 2008, 6:16:27 PM7/17/08
to X...@softimage.com
OK, I've been asked if I could do a blend shader that would do the same thing as a Photoshop Color Blend.
 
Let's say you have image A blended with image B to get image C, I've read that the result would become Hc Sc Lc = Ha Sa Yb... From what I'm understanding, the final result in HSL color space comes from the photoshop HSY color space. I've found how to convert RGB in HSL but I'm not sure I'm using the right technique to convert them to the HSY format.
 
I've googled a few word combinations to try and find out, but nothing I've found seems to give me the same result as a Photoshop Color blend would give me.
 
One guy says that to convert RGB to HSY, you have to use the following:
 
H = rgb2hsl(r,g,b,0); //0 as the last parameters makes the function extract only the Hue
S = max(r, max(g,b)) - min(r, min(g,b));
Y = r*0.30 + g*0.59 + b*0.11;
 
So my function puts the HSL hue H and photoshop saturation S of the foreground with the luminance Y of the background in a HSL color that I then convert back to rgb.
 
I use 2 images to test the results: the foreground is a grayscale noise image and the background is uniform red. In photoshop, when blended together, the result is a noised red to white image but when I use my function, it gives me a uniform dark gray color. Then I try switching the foreground and background for fun, it now gives me the noise pattern but where photoshop has red, mine gives black and where photoshop has white, mine gives red.
 
There's obviously something that I'm doing wrong. Anyone has any idea where I might be mistaken? Anyone know a website that explains the phenomenon better? Or is there simply a much simpler way to simulate a photoshop color blend in the render tree that I'm not aware of?
 
Any help would be greatly appreciated.
 
Thanks.
 
 
Mathieu Leclaire
R&D Programmer
Hybride Technologies
 

Thomas Helzle

unread,
Jul 17, 2008, 6:55:36 PM7/17/08
to X...@softimage.com
Sounds like some kind of mixup to me?
Any chance that you inverted some values by accident?

Seems like you get the inverted results?

Cheers,

Thomas Helzle

Tim Leydecker

unread,
Jul 18, 2008, 1:47:09 PM7/18/08
to X...@softimage.com
What´s the Y in that? Luminancevalue, e.g. v?

I thought it´s hue/saturation/value e.g. HSV,
first entry setting color off a spectralgradient,
then saturation 0-100, the last one actually being
a greylevel value not a color value?

According to that the function you have for Y:

Y = r*0.30 + g*0.59 + b*0.11

Seems like an adoption of converting colorinformation
from discrete RGB channels based on a human eyes´
range of perception?

While nonbiased one would probably expect Y = (R+G+B)/3

Oh, I don´t know.

But from you getting a red result where you shouldn´t
sounds like you either missed a channelinterpretation
as "grayscale", like feeding the correct values the
wrong slot, here R instead of something like A (RGBA)
or missing to add the other two channels to get back
a uniform value, e.g. feed all three channels the value
you get as in the above formula Y = (R+G+B)/3 if you
don´t know for sure it´s a color value or a luminance value.


Using your formula Y = r*0.30 + g*0.59 + b*0.11 instead
would distort the color for anything other R=G=B

Oh, I don´t know.

Solved it?

Cheers

tim

---
Unsubscribe? Mail Majo...@Softimage.COM with the following text in body:
unsubscribe xsi

Mathieu Leclaire

unread,
Jul 18, 2008, 2:43:50 PM7/18/08
to X...@softimage.com
Nope, I still can't figure it out. From what I can make out of all I have
read on the subject, photoshop converts the colors to his own proprietary
color space (HSY = hue, saturation and luminance).

The only information that I've been able to find on the web about that color
space is that the H in HSY is the same H as the one in HSL color space. The
S is the difference between the max and min values of RGB and the Y = r*0.30
+ g*0.59 + b*0.11. I found that information here:
http://www.retouchpro.com/forums/software/12807-filtermeister-color-theory-c
onversions.html

Then in another document
(http://www.simpelfilter.de/en/basics/mixmods.html), it says Hc Sc Lc = Ha
Sa Yb where a is the foreground layer, b the background layer and c the
composite layer.

And here is my shader code (not on it's cleanest form but still...):

//===================================================

#include <shader.h>

typedef struct
{
miColor Color1;
miColor Color2;
} PhotoshopColorBlend_t;

miScalar MathMax(miScalar val1, miScalar val2)
{
if (val2>val1)
return val2;
else return val1;
}
miScalar MathMin(miScalar val1, miScalar val2)
{
if (val2<val1)
return val2;
else return val1;
}
miBoolean RGB_2_HSL(miColor iRGB, miColor * oHSL)
{
miScalar HLSMAX = 360;
miScalar RGBMAX = 255;
miScalar cMax,cMin,R,G,B,H,L,S; /* max and min RGB values */
miScalar Rdelta,Gdelta,Bdelta; /* intermediate value: % of spread from max
*/

R = iRGB.r*RGBMAX;
G = iRGB.g*RGBMAX;
B = iRGB.b*RGBMAX;

/* calculate lightness */
cMax = MathMax( MathMax(R,G), B);
cMin = MathMin( MathMin(R,G), B);
L = (((cMax+cMin) * HLSMAX) + RGBMAX ) / (2 * RGBMAX);

if (cMax == cMin)
{/* r=g=b --> achromatic case */
S = 0; /* saturation */
H = 0; /* hue */
}
else
{/* chromatic case */
/* saturation */
if (L <= (HLSMAX/2))
S = ( ((cMax-cMin)*HLSMAX) + ((cMax+cMin)/2) ) / (cMax+cMin);
else
S = ( ((cMax-cMin)*HLSMAX) + ((2*RGBMAX-cMax-cMin)/2) ) /
(2*RGBMAX-cMax-cMin);

/* hue */
Rdelta = ( ((cMax-R)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin);
Gdelta = ( ((cMax-G)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin);
Bdelta = ( ((cMax-B)*(HLSMAX/6)) + ((cMax-cMin)/2) ) / (cMax-cMin);

if (R == cMax)
H = Bdelta - Gdelta;
else if (G == cMax)
H = (HLSMAX/3) + Rdelta - Bdelta;
else /* B == cMax */
H = ((2*HLSMAX)/3) + Gdelta - Rdelta;

if (H < 0)
H += HLSMAX;
if (H > HLSMAX)
H -= HLSMAX;
}

oHSL->r = H;
oHSL->g = S;
oHSL->b = L;
return( miTRUE );
}

/* utility routine for HLStoRGB */
miScalar HueToRGB(miScalar n1, miScalar n2, miScalar hue)
{
miScalar HLSMAX = 360;
/* range check: note values passed add/subtract thirds of range */
if (hue < 0)
hue += HLSMAX;

if (hue > HLSMAX)
hue -= HLSMAX;

/* return r,g, or b value from this tridrant */
if (hue < (HLSMAX/6))
return ( n1 + (((n2-n1)*hue+(HLSMAX/12))/(HLSMAX/6)) );
if (hue < (HLSMAX/2))
return ( n2 );
if (hue < ((HLSMAX*2)/3))
return ( n1 + (((n2-n1)*(((HLSMAX*2)/3)-hue)+(HLSMAX/12))/(HLSMAX/6)));
else
return ( n1 );
}

miBoolean HSL_2_RGB(miColor iHSL, miColor * oRGB)
{
miScalar HLSMAX = 360;
miScalar RGBMAX = 255;
miScalar R,G,B,H,L,S;
H = iHSL.r;
S = iHSL.g;
L = iHSL.b;
float Magic1, Magic2; /* calculated magic numbers (really!) */

if (S == 0)
{/* achromatic case */
R=G=B=(L*RGBMAX)/HLSMAX;
}
else
{/* chromatic case */
/* set up magic numbers */
if (L <= (HLSMAX/2))
Magic2 = (L*(HLSMAX + S) + (HLSMAX/2))/HLSMAX;
else
Magic2 = L + S - ((L*S) + (HLSMAX/2))/HLSMAX;

Magic1 = 2*L-Magic2;

/* get RGB, change units from HLSMAX to RGBMAX */
R = (HueToRGB(Magic1,Magic2,H+(HLSMAX/3)) * RGBMAX + (HLSMAX/2))/HLSMAX;
G = (HueToRGB(Magic1,Magic2,H) * RGBMAX + (HLSMAX/2)) / HLSMAX;
B = (HueToRGB(Magic1,Magic2,H-(HLSMAX/3)) * RGBMAX + (HLSMAX/2))/HLSMAX;
}

oRGB->r = R/RGBMAX;
oRGB->g = G/RGBMAX;
oRGB->b = B/RGBMAX;
return( miTRUE );
}

extern "C" DLLEXPORT miBoolean
PhotoshopColorBlend
(
miColor *result,
miState *state,
PhotoshopColorBlend_t *params
)
{
miColor inRGB1, inRGB2, HSL1, outHSL;

inRGB1 = *mi_eval_color(&params->Color1);
inRGB2 = *mi_eval_color(&params->Color2);
RGB_2_HSL(inRGB1, &HSL1);
outHSL.r = HSL1.r;
outHSL.g = MathMax(inRGB1.r*255, MathMax(inRGB1.g*255,inRGB1.b*255) ) -
MathMin(inRGB1.r*255, MathMin(inRGB1.g*255,inRGB1.b*255) );
outHSL.b = inRGB2.r*255*0.30 + inRGB2.g*255*0.59 + inRGB2.b*255*0.11;
HSL_2_RGB(outHSL, result);

return( miTRUE );
}

extern "C" DLLEXPORT void
PhotoshopColorBlend_init
(
miState *state,
PhotoshopColorBlend_t *params,
miBoolean *inst_init_req
)
{
if( params == NULL )
{
// TODO: Shader global initialization code goes here (if needed)

// Request a per-instance shader initialization as well (set to miFALSE if
not needed)
*inst_init_req = miTRUE;
}
else
{
// TODO: Shader instance-specific initialization code goes here (if
needed)
}
}


extern "C" DLLEXPORT void
PhotoshopColorBlend_exit
(
miState *state,
PhotoshopColorBlend_t *params
)
{
if( params == NULL )
{
// TODO: Shader global cleanup code goes here (if needed)
}
else
{
// TODO: Shader instance-specific cleanup code goes here (if needed)
}
}


extern "C" DLLEXPORT int
PhotoshopColorBlend_version( )
{
return( 1 );
}

//========================================================

I don't know if anyone can help me see the errors of my ways with this?
Doing such a shader seemed pretty simple at first glance but it turns out to
be causing-me multiple headaches.


Mathieu Leclaire
R&D Programmer
Hybride Technologies

Tim Leydecker

unread,
Jul 18, 2008, 3:36:56 PM7/18/08
to X...@softimage.com
Hi Mathieu,

your shader is way above my horizon in terms of coding.


What I can tell you is that Photoshop internally works
in CIELab mode:

L*,luminance 0 is pure black 100 is pure white
a*, red-green axis, minus128=green, positive127=red
b*,yellow-blue axis, minus128=blue, positive127=yellow

Did you try to find the function of XSI in any spdl that
is responsible for converting colorswatches between modes?

It is not exact (>rounding errors) but might help anyway?

Luc-Eric Rousseau might also be able to help you,
I had forwared a feature request for a LAB mode node
for the XSI7 fxtree, maybe it came through and Luc-Eric
actually had some fun time with those colormodes recently?

Reply all
Reply to author
Forward
0 new messages