Skip to main content
gamedev.net
🔒 Locked

Color Conversion...

Started by Lethe 5 replies 600+ views
Original Post
Lethe
Lethe
I've been writting a Video Compression system, and whilst everything is currently going fine, I've hit a problem - my color conversion code works fine, as long as there are no inaccuracies, but the inaccuracies that are introduced by the DCT cause it to go awol on extreme colors, ie black goes pink. The code is as follows...
            
// Lookup tables setup-

for (register int i=0;i<256;i++)
{
 RedCr<i>   = (unsigned char)(1.402*((char)((unsigned char)i)));
 GreenCb<i> = (unsigned char)(0.34414*((char)((unsigned char)i)));
 GreenCr<i> = (unsigned char)(0.71414*((char)((unsigned char)i)));
 BlueCb[i]  = (unsigned char)(1.772*((char)((unsigned char)i)));
}

// Conversion from RGB to Y'CbCr-

 unsigned char * Targ = Data;
for (register unsigned int i=0;i<(640*480);i++)
{
 register unsigned char R = (*(Targ));   //if (R<32) R=32; if (R>248) R=248;
 register unsigned char G = (*(Targ+1)); //if (G<32) G=32; if (G>248) G=248;
 register unsigned char B = (*(Targ+2)); //if (B<32) B=32; if (B>248) B=248; 

 (*Targ) = (unsigned char)((0.299*R+0.587*G+0.114*B));
  Targ++;

 (*Targ) = (unsigned char)((char)((-0.1687*R-0.3313*G+0.5*B)+128));
  Targ++;

 (*Targ) = (unsigned char)((char)((0.5*R-0.4187*G-0.0813*B)+128));
  Targ++;
}

// And conversion from Y'CbCr back to RGB-

 register unsigned char * Targ = Data;
for (register unsigned int i=0;i<(640*480);i++)
{
 register unsigned char Y  = (*(Targ));
 register unsigned char Cb = (char)((*(Targ+1))-128);
 register unsigned char Cr = (char)((*(Targ+2))-128);

 (*Targ) = (Y+RedCr[Cr]);
  Targ++;

 (*Targ) = (unsigned char)(char)(Y-GreenCb[Cb]-GreenCr[Cr]);
  Targ++;

 (*Targ) = (unsigned char)(char)(Y + BlueCb[Cb]);
  Targ++;
}
         
A possible solution is commeted out in the RGB to Y'CbCr conversion - which is to reduce the color ranges, but it makes the image go slightly grey, which I concider to look horible. As it stands, it also tints everything slightly green and makes it very slightly darker, but this is not really a problem. Whilst a solution to this problem is my main concern, (The compression increses 4 fold - down to 10-20k per frame if I use it.) any help to optimise this would be great, though only the Y'CbCr to RGB needs to be fast. Thanks in advance. -Lethe Edited by - Lethe on 11/6/00 3:30:38 AM
LilBudyWizer
LilBudyWizer
There was recently an article in Game Developer Magazine on compression for Resident Evil 2. The article was named Mission: Compressible by Tood Meynink. Since they were going to 165:1 compression it might be worth looking into. The matrix they give has 0.1687 instead of -0.1687 for the RGB to YCbCr.
Keys to success: Ability, ambition and opportunity.
Lethe
Lethe
Already read it. As for there compression, it''s good, but rather low quality,by PC standards, and if you look, it is a negative - they put the sign change in later. It also is designed for a console - a PC is rather different, as you don''t have the memory restraints and have far more power to play with.
-Lethe
LilBudyWizer
LilBudyWizer
Most anything I would suggest is pretty minor. One would be removing the increments and using +1 and +2 then add 3 at the end of the loop. I believe the +1 and +2 would be done by the decode on the instruction rather than generating an add. That should be one instruction doing the work of three currently. Also & 0x80 instead of + 128, but I''m not certain that is valid since the add is done before the conversion to character. If possible use fixed point instead of floating which it looks like is doable. That is really the only thing I can think of that might have a big impact.
Keys to success: Ability, ambition and opportunity.
LilBudyWizer
LilBudyWizer
One other things is that if this is the routine as opposed to three sections from three routines then combine the two loops. Having two loops I believe is adding about a million instructions to this. That is allowing for the compare, increment and branch being one instruction each which they most likely are not.
Keys to success: Ability, ambition and opportunity.
ColdFlame
ColdFlame
The compiler is going to be crippled by having five variables in registers (if it listens to you anyway), given it only really has 6 it can use. That's just my two cents worth anyway.

Oh well, Whatever, Nevermind

Edited by - ColdFlame on November 10, 2000 4:01:12 PM
Oh well, Whatever, Nevermind
LilBudyWizer
LilBudyWizer
Another small thing is using targ to control the loop. You are incrementing both targ and i when if you calculate targ + (640*480) before the loop and compare to that while incrementing targ you dropped 307,200 increments you don''t need. Although your register variables went out of scope once you leave the loop it is worthwhile to check the assembler listing to see if your register specifications are being ignored. Targ is clearly the critical one and if it is being ignored then drop the other register specifiers so it is clear to the compiler what it should do. It might be faster to not do it in place as well. Then you can drop the r, g and b variables completely. Although nastier to read the compilers generally take what you say literally. It may actually be storing the values in r, g and b even if it didn''t ignore your register specifications. So using *source, *(source+1) and *(source+2) in the calculation may eliminate over almost a million stores.
Keys to success: Ability, ambition and opportunity.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.