Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

code optimisation (RGB to HSV)

2 views
Skip to first unread message

Matthew Haley

unread,
Jun 16, 1999, 3:00:00 AM6/16/99
to

Richard Browne wrote in message <3767CE4D...@pobox.com.au>...
>My experience is that on Intel processors, float is faster than double..
>simply because a float is 4 bytes as opposed to 8 bytes for a double.

IIRC, some compilers promote floats to doubles anyway.

>This is Intel dependent of course.
>
>Delayen Laurent wrote:
>>
>> I'm currently writing RGB <-> HSV transformation routines.
>> I'd like to find some ways to improve that code because it's very very
slow.
>> But i'd also like to keep good precision.
>>
>> And i also would like to know if Double is faster than float ? or is it
the
>> same?
>>
<<snip>>


Delayen Laurent

unread,
Jun 17, 1999, 3:00:00 AM6/17/99
to
I'm currently writing RGB <-> HSV transformation routines.
I'd like to find some ways to improve that code because it's very very slow.
But i'd also like to keep good precision.

And i also would like to know if Double is faster than float ? or is it the
same?

If anybody could help me with this....

thanks for your time,

Laurent Delayen.

here's the main code:

(...)
pixel.rgba = *src_temp;
r = pixel.r;
g = pixel.g;
b = pixel.b;
a = pixel.a;

// HSV
rgb_to_hsv(r, g, b, &h, &s, &v);

// New HSV intensities
rt = m_RGB_H;
gt = m_RGB_S;
bt = m_RGB_V;

// Alpha channel handling
if (m_RGB_H_A)
{
if (m_RGB_H_AI)
rt = (rt * (255 - a)) / 255;
else
rt = (rt * a) / 255;
}
if (m_RGB_S_A)
{
if (m_RGB_S_AI)
gt = (gt * (255 - a)) / 255;
else
gt = (gt * a) / 255;
}
if (m_RGB_V_A)
{
if (m_RGB_V_AI)
bt = (bt * (255 - a)) / 255;
else
bt = (bt * a) / 255;
}

h += (((float) rt) / 360);
s += (((float) gt) / 500);
v += (((float) bt) / 500);

hsv_to_rgb(h, s, v, &rb, &gb, &bb);

r = rb;
g = gb;
b = bb;
(...)


and here are the 2 functions:

void hsv_to_rgb(float h, float s, float v, byte *r, byte *g, byte *b)
{
// parameters
// h (float) : Hue : angle (0-1) (0-359 degrees)
// s (float) : Saturation : intensity (0-1) (0 - max)
// v (float) : Value : intensity (0-1) (0 - max)
// r (byte) : R channel : intensity (0-255)
// g (byte) : G channel : intensity (0-255)
// b (byte) : B channel : intensity (0-255)

int i;
float aa, bb, cc, f;
float rt, gt, bt;

while (h < 0.0)
h += 1.0;

while (h >= 1.0)
h -= 1.0;

if (s < 0.0)
s = 0.0;

if (s > 1.0)
s = 1.0;

if (v < 0.0)
v = 0.0;

if (v > 1.0)
v = 1.0;

if (s == 0)
// grayscale
*r = *g = *b = floor(v*255);
else
{
h *= 6.0;
i = floor(h);
f = h - i;
aa = v*(1 - s);
bb = v*(1 - (s * f));
cc = v*(1 - (s * (1 - f)));

switch (i)
{
case 0 : rt = v;
gt = cc;
bt = aa;
break;
case 1 : rt = bb;
gt = v;
bt = aa;
break;
case 2 : rt = aa;
gt = v;
bt = cc;
break;
case 3 : rt = aa;
gt = bb;
bt = v;
break;
case 4 : rt = cc;
gt = aa;
bt = v;
break;
case 5 : rt = v;
gt = aa;
bt = bb;
break;

}

*r = floor(rt * 255);
*g = floor(gt * 255);
*b = floor(bt * 255);
}
} // hsv_to_rgb

void rgb_to_hsv(byte r, byte g, byte b, float *h, float *s, float *v)
{
// parameters
// h (float) : Hue : angle (0-1) (0-359 degrees)
// s (float) : Saturation : intensity (0-1) (0 - max)
// v (float) : Value : intensity (0-1) (0 - max)
// r (byte) : R channel : intensity (0-255)
// g (byte) : G channel : intensity (0-255)
// b (byte) : B channel : intensity (0-255)
float rf = ((float) r) / 255, gf = ((float) g) / 255, bf = ((float) b) /
255;
float max = MAX(rf, MAX(gf, bf)), min = MIN(rf, MIN(gf, bf));
float delta = max - min;

*v = max;

if (max != 0.0)
*s = delta / max;
else
*s = 0.0;

if (*s == 0.0)
*h = -1.0;
else
{
if (rf == max)
*h = (gf - bf) / delta;
else if (g == max)
*h = 2 + (bf - rf) / delta;
else
*h = 4 + (rf - gf) / delta;

*h *= 60.0;

while (*h < 0)
*h += 360.0;

*h /= 360.0;
}
} // rgb_to_hsv

Richard Browne

unread,
Jun 17, 1999, 3:00:00 AM6/17/99
to
My experience is that on Intel processors, float is faster than double..
simply because a float is 4 bytes as opposed to 8 bytes for a double.
This is Intel dependent of course.

Jukka Liimatta

unread,
Jun 17, 1999, 3:00:00 AM6/17/99
to
> IIRC, some compilers promote floats to doubles anyway.

That would break a lot of existing code, say, we have a struct:

// C++'ish usage
struct
{
int a;
float foo;
int other;
};

If we had library written by one compiler, and used by other ( linking in
the .lib / .a file ), result would be crash. You maybe meant that
internally, the default accuracy is 80bits ( long double ) with X86 based
fpu? 8^)

The accuracy can be changed, for example, by using the <float.h> which comes
with most X86 based compilers. Atleast Borland builder, VC and Watcom seem
to carry it.


Regards,
Jukka

Jace / TBL

unread,
Jun 17, 1999, 3:00:00 AM6/17/99
to

Delayen Laurent <del...@club-internet.fr> wrote in message news:7k97im$rij$1...@front1m.grolier.fr...

>I'm currently writing RGB <-> HSV transformation routines.
>I'd like to find some ways to improve that code because it's very very slow.
>But i'd also like to keep good precision.
>
>And i also would like to know if Double is faster than float ? or is it the
>same?

floats (which are 32 bit) are faster than doubles (which are 64 bit).

Internally, the fpu always works with 80 bit floats, so the speed
difference is only depending on memory access - and of course,
reading and writing 64 bits is slower than 32 bits.

Jace / tBL


Andrew Younger

unread,
Jun 17, 1999, 3:00:00 AM6/17/99
to

just having a very quick look at the code I can see a lot of possible
speed losses.

2 main points.
+ divides are very slow (more so on integers than on floats),
+ conversions from floating point numbers to integers are also
very slow

so basically if you move all the calcs to be floating point, replacing
as many of the divides as you can with multiplications by 1 over the
divisor, and only convert from floats to integers at the end, this
should help a lot.

There are some nice hacks you can do if you are dealling with IEEE
numbers to speed this up more, but I will leave this out for now...

anyway no time, as I've got to get back to work..

Andy.


> -----Original Message-----
> From: Delayen Laurent [mailto:del...@club-internet.fr]
> Posted At: Wednesday, June 16, 1999 11:16 PM
> Posted To: algorithms
> Conversation: code optimisation (RGB to HSV)
> Subject: code optimisation (RGB to HSV)
>
>
> I'm currently writing RGB <-> HSV transformation routines.
> I'd like to find some ways to improve that code because it's
> very very slow.
> But i'd also like to keep good precision.
>
> And i also would like to know if Double is faster than float
> ? or is it the
> same?
>

Jace / TBL

unread,
Jun 17, 1999, 3:00:00 AM6/17/99
to

Delayen Laurent <del...@club-internet.fr> wrote in message news:7k97im$rij$1...@front1m.grolier.fr...
>I'm currently writing RGB <-> HSV transformation routines.
>I'd like to find some ways to improve that code because it's very very slow.
>But i'd also like to keep good precision.
>
>here's the main code:
> [...lotsa code...]

Just some hints:

either stick with floats or ints, but don't mess 'em up (I tend to keep
my color information as ints ranging from 0..255, this doesn't really
reduce the precision).

your alpha applying seems quite horrible, instead of using
R=R*(255-a)/255 or R=R*a/255 I'd rather use R=(R*(256-a))>>8
or R=(R*(a+1))>>8 which gives the same result.

I've written a quite fast HSV<->RGB transformation in assembler
once, I'll see if I can dig it up somewhere.

greetinx,

Rogier "Jace / TBL" Eijkelhof

Matthew Haley

unread,
Jun 17, 1999, 3:00:00 AM6/17/99
to

Jukka Liimatta wrote in message <7ka3er$90g$1...@news.kolumbus.fi>...

Thank you for the correction.


Delayen Laurent

unread,
Jun 18, 1999, 3:00:00 AM6/18/99
to
> Just some hints:
>
> either stick with floats or ints, but don't mess 'em up (I tend to keep
> my color information as ints ranging from 0..255, this doesn't really
> reduce the precision).
>
> your alpha applying seems quite horrible, instead of using
> R=R*(255-a)/255 or R=R*a/255 I'd rather use R=(R*(256-a))>>8
> or R=(R*(a+1))>>8 which gives the same result.
>
> I've written a quite fast HSV<->RGB transformation in assembler
> once, I'll see if I can dig it up somewhere.
>
> greetinx,
>
> Rogier "Jace / TBL" Eijkelhof

Thanks a lot. i'll be pleased to take a look at your code.

btw: is TBL The Black Lotus, the amiga demo group that recently moved to PC?
(well recently 2 years or 3 ago).

- Shag

Jace / TBL

unread,
Jun 18, 1999, 3:00:00 AM6/18/99
to

Delayen Laurent <del...@club-internet.fr> wrote in message news:7kc3qk$moo$1...@front4.grolier.fr...

>
>Thanks a lot. i'll be pleased to take a look at your code.
>
>btw: is TBL The Black Lotus, the amiga demo group that recently moved to PC?
>(well recently 2 years or 3 ago).

yepz, that's the one. I'm one of the pc coders.
TBL is still both amiga and pc, btw.

Anyway, I've been digging in my code, and I think the one in asm is on my
other pc at home. Right here is one that I once made in C/C++. It's not as
fast as the asm version, but I think it will do. Note that you get the result
in the parameters that you pass, so if you do this:

int r = pixel.red,
g = pixel.green,
b = pixel.blue;
RGBtoHSI(r,g,b);

Then r will contain the hue, g the saturation, b the intensity - all ranging from 0 to 255.

Hope this helps ya!

greetinx,

Jace / the Black Lotus
http://www.tbl.org
Jace...@pmail.net


##########################################

void RGBtoHSI (int &r, int &g, int &b)
{
int max,med,min;

// split colors
if (r>=g)
{ // r > g
if (r>=b)
{ // r > g,b
if (g>=b)
{ // r > g > b
max = r;
med = g;
min = b;
r = 0;
}
else
{ // r > b > g
max = r;
med = b;
min = g;
r = 5;
}
}
else
{ // b > r > g
max = b;
med = r;
min = g;
r = 4;
}
} else
{ // g > r
if (g>=b)
{ // g > r,b
if (r>=b)
{ // g > r > b
max = g;
med = r;
min = b;
r = 1;
}
else
{ // g > b > r
max = g;
med = b;
min = r;
r = 2;
}
}
else
{ // b > g > r
max = b;
med = g;
min = r;
r = 3;
}
}
// colors are split into max,med,min and base h.
if (min==max) { r=0; g=0; return; } // gray -> no defined hue, sat = 0.
g = 255 - ((min<<8)/max);
b = max;
med = max - (max * (max-med))/(max-min);
min = (med<<8)/max; // 0..256
if (r&1) min = 256-min;
r = (((r<<8)+min)/6) & 255;
}


void HSItoRGB (int &r, int &g, int &b)
{
int max,med,min,h;
h = 6*r;
max = b;
min = (max*(256-g))>>8;
med = (((h&255)+1)*max)>>8;
if (h&256) med = max-med;
med = max-(((max-med)*(g+1))>>8);
h>>=8;
switch(h)
{
case 0: r=max; g=med; b=min; break;
case 1: r=med; g=max; b=min; break;
case 2: r=min; g=max; b=med; break;
case 3: r=min; g=med; b=max; break;
case 4: r=med; g=min; b=max; break;
case 5: r=max; g=min; b=med; break;
}
}


Delayen Laurent

unread,
Jun 18, 1999, 3:00:00 AM6/18/99
to
thanks a lot i will check that.

and keep up the good work !
I can remember quite good demos from TBL on the amiga. (goa, captured
dreams...).
But i'm a bit disapointed about the PC demos (not just TBL ones).
Ok, the effects are impressive, but there are no more design, no more story
etc.. just effects over music.
I had quit the scene 3 years ago because of university, and i was curious to
see how demos had evolved. But i'm quite disapointed. nothing really new
since the big amiga demos (the ones from TBL, and many from Virtual dreams /
BOMB etc...).
What would be nice would be to use some more 3D cards power (not just
texture antialisaing), and write some real stories / short movies. not just
3D effects with techno over it.
I think the PC has enough power to be more creative than just XXXX polygons
in real time etc... (fast processors, 3D cards, 3D sounds with the sb live,
etc...)
GODS had a great idea with their Incoming Future demo. but the result is
quite ugly. Colors / objects / sounds really really suck. But at least they
made something more orignal.

And i miss the funny Melon demos too :)

Anyway, thanks a lot for your help.

greetz,

-Shag

Bill Tuttle

unread,
Jun 18, 1999, 3:00:00 AM6/18/99
to

Delayen Laurent <del...@club-internet.fr> wrote in message
news:7k97im$rij$1...@front1m.grolier.fr...
> I'm currently writing RGB <-> HSV transformation routines.
> I'd like to find some ways to improve that code because it's very very
slow.
> But i'd also like to keep good precision.

Not withstanding your last request, I have some old byte based code.

/*
* These two functions RGBtoHSV and HSVtoRGB are refinements of the Pascal
* functions provided in Computer Graphics 2nd edition(Addison Wesley)
* pages 592-593. These functions convert 24 bit RGB to 24 bit HSV.
* NOTE: Hue range is 0 - 256, 0 == 360, Sat = 0 - 255, and Val = 0 - 255.
* This code has been tested with both 16 and 32 bit compilers.
*
* The resulting code is fixed point integer based which allows efficent
operation on
* processors without floating point hardware. However, even though there
* is no loss of computational precision, output is limited to 8 bit
values.
* While this gives accurate results in each direction, when combined the
* +- 0.5 error in both directions will result in round off errors.
*/

#define MAX(a,b) ((a>b)?a:b)
#define MIN(a,b) ((a<b)?a:b)

#define MAXIMUM(a,b,c) ((a>b)?MAX(a,c):MAX(b,c))
#define MINIMUM(a,b,c) ((a<b)?MIN(a,c):MIN(b,c))

void RGBtoHSV(unsigned char *rgb, unsigned char *hsv, int count) {

int pel, dif, col;
int red, grn, blu;
int sat, val;
long hue;

for (pel = 0; pel < count; pel++) {
red = *rgb++;
grn = *rgb++;
blu = *rgb++;

if (val = MAXIMUM(red, grn, blu)) {
dif = val - MINIMUM(red, grn, blu);
if (sat = ((dif * 255U + val/2) / val)) {
if (red == val) { /* magenta < red > yellow
*/
hue = 6 << 8; /* use 6 instead of 0, col > 0
*/
col = grn - blu; /* will cause > 360 wrap
*/
}
else if (grn == val) { /* yellow < green > cyan */
hue = 2 << 8; /* normalize all hue values */
col = blu - red; /* to 0 - 256 */
}
else /* (blu == val) */ { /* cyan < blue > magenta */
hue = 4 << 8;
col = red - grn;
}
hue *= dif; /* normalize hue */
hue += (long)col << 8; /* add color shift */
hue += dif * 3; /* rounding value */
hue /= dif * 6; /* hue = 0 - 256 */
}
else
hue = 0; /* hue = undefined, use 0 */
}
else {
hue = sat = 0;
}
*hsv++ = (unsigned char)hue;
*hsv++ = (unsigned char)sat;
*hsv++ = (unsigned char)val;
}
}


void HSVtoRGB(unsigned char *hsv, unsigned char *rgb, int count) {

int pel;
long hue, sat, val;
long i, f, p, q, t;

for (pel = 0; pel < count; pel++) {
hue = *hsv++;
sat = *hsv++;
val = *hsv++;

/* Hue 1 = 256 0 == 360 f 1 = 256, Sat 1 = 255, and Val 1 = 255 */
/* 1 - f == 256 - f, 1 - sat * f == 255 * 256 - sat * f */
if (sat) {
i = hue * 6 >> 8; /* hue integer */
f = (unsigned char)(hue * 6); /* hue fraction */
p = (val * (0xFF - sat) + 0x7F) / 0xFF;
q = (val * (0xFF00 - sat * f) + 0x7F80) / 0xFF00;
t = (val * (0xFF00 - sat * (256 - f)) + 0x7F80) / 0xFF00;

switch (i) {
case 0 : /* red */
*rgb++ = (unsigned char)val;
*rgb++ = (unsigned char)t;
*rgb++ = (unsigned char)p;
break;

case 1 : /* yellow */
*rgb++ = (unsigned char)q;
*rgb++ = (unsigned char)val;
*rgb++ = (unsigned char)p;
break;

case 2 : /* green */
*rgb++ = (unsigned char)p;
*rgb++ = (unsigned char)val;
*rgb++ = (unsigned char)t;
break;

case 3 : /* cyan */
*rgb++ = (unsigned char)p;
*rgb++ = (unsigned char)q;
*rgb++ = (unsigned char)val;
break;

case 4 : /* blue */
*rgb++ = (unsigned char)t;
*rgb++ = (unsigned char)p;
*rgb++ = (unsigned char)val;
break;

case 5 : /* magenta */
*rgb++ = (unsigned char)val;
*rgb++ = (unsigned char)p;
*rgb++ = (unsigned char)q;
break;
}
}
else {
*rgb++ = (unsigned char)val;
*rgb++ = (unsigned char)val;
*rgb++ = (unsigned char)val;
}
}
}


Phil McRevis

unread,
Jun 19, 1999, 3:00:00 AM6/19/99
to
"Matthew Haley" <mhal...@homemail.com> spake the secret code
<400a3.28187$Ma1....@news.uswest.net> thusly:

>IIRC, some compilers promote floats to doubles anyway.

This only happens for expressions; never for things like declarations
and structs. For instance, conversion from float to double is
automatic when the argument of a procedure takes a double and you
provide a float. (Functions like floor(), for instance.)
--
http://www.xmission.com/~legalize Legalize Adulthood!
lega...@xmission.com
``Ain't it funny that they all fire the pistol, <URL: http://
at the wrong end of the race?''--PDBT www.eden.com/~thewho>

Phil McRevis

unread,
Jun 19, 1999, 3:00:00 AM6/19/99
to
There is also a "graphic gem" about fast RGB<->HSV conversion, you
should look for that to compare.
0 new messages