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>>
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
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
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
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?
>
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
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;
}
}
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
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;
}
}
}
>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>