Welcome Guest ( Log In | Register )


Important

The forums will be closing permanently the weekend of March 15th. Please see the notice in the announcements forum for details.

 
Converting Between Rgb And Yuv, stupid question :)
« Next Oldest | Next Newest » Track this topic | Email this topic | Print this topic
Fredrik
Posted: Dec 12 2002, 11:54 AM


Unregistered









When converting from RGB (0-255) to YUV, the Y value is surely between 0 and 255. But what about U and V, for example when converting R255 G255 B0 to YUV, U is surely negative. I have to correct these values somehow, don't I? How is it done?

I use

Y = 0.299R + ...
U = B - Y
V = R - Y


 
  Top
fccHandler
Posted: Dec 12 2002, 07:53 PM


Administrator n00b


Group: Moderators
Posts: 3961
Member No.: 280
Joined: 13-September 02



You add 128 to U and V, clamp to 0-255, and store. When converting back to RGB, you subtract 128.

--------------------
May the FOURCC be with you...
 
     Top
Fredrik
Posted: Dec 12 2002, 11:48 PM


Unregistered









Hello,

I am currently rewriting my cartoon cleaner filter to work in YUV colorspace (mostly because I want to get rid of the chroma noise).
After searching the internet quite a long time I found the following conversion formulas:

RGB -> YUV
----------
Y = 0.2990R + 0.5870G + 0.1440B
U = -0.1687R - 0.3313G + 0.5000G
V = 0.5000R - 0.4187G - 0.0813B

YUV -> RGB
----------
R = Y + 1.402V
G = Y - 0.34414U - 0.71414V
B = Y + 1.772U

Using these formulas on 0-255 rgb values produces 0-255 for Y and (-127.5)-(+127.5) for both U and V.
I decided to multiply by 4096*0,299 etc. and then divide by 256 (shift right by 8), so my factors look like this:

unsigned __int64 rgb2y = 0x000004c9096401d3;
unsigned __int64 rgb2u = 0x0000fd4dfab30800;
unsigned __int64 rgb2v = 0x00000800f94dfeb3;

unsigned __int64 yuv2r = 0x000010000000166f;
unsigned __int64 yuv2g = 0x00001000fa7ff493;
unsigned __int64 yuv2b = 0x000010001c5a0000;

The first thing I tried was converting RGB->YUV and then, without any filtering, convert back YUV->RGB which resulted in a lot of garbage. See http://www.geocities.com/ackehurst/ for the pics.

I'm pretty sure this is a rounding problem. Can it be solved by changing the above tables? As a temporary solution, I decided to push any rgb value which is zero to one. The new picture is almost identical to the original (despite some rgb values being one off, I checked it with Paint Shop Pro).

To sum it up, my question is: how do other rgb<->yuv converters handle these rounding problems? I don't want to limit this filter to p3/athlon users just because of one stupid pmaxub-opcode...

 
  Top
phaeron
Posted: Dec 13 2002, 12:59 AM


Virtualdub Developer


Group: Administrator
Posts: 7773
Member No.: 61
Joined: 30-July 02



Looks like you've either got an overflow problem or have signed/unsigned values mixed up somewhere -- clipping isn't ordinarily a problem in MMX because it's automatically done by the pack instructions.

As for doing the zero push without MMX2:

CODE

pxor mm1, mm1
pcmpeqw mm1, mm0
psubw mm0, mm1


Before you go through all the work of a full YUV solution, though, note that [Y, R-Y, G-Y, B-Y] space is easier to compute and is equivalent for linear processing.
 
    Top
Fredrik
Posted: Dec 13 2002, 02:53 AM


Unregistered









QUOTE (phaeron @ Dec 12 2002, 06:59 PM)
clipping isn't ordinarily a problem in MMX because it's automatically done by the pack instructions.

Thank you very much, I did not think of packuswb, I just por'd the values together since I assumed they'd be between 0 and 255 anyway... d'oh! Now it works fine.

Maybe you can give me some other hints on my mmx code? The arranging of the r, g and b values seems rather complicated, but I could not solve it better (yet).

esi points to an array of yuv qwords, edi points to the destination buffer, this is just the code for a single line


yuv2rgb:

 movd mm6, [esi]   // mm6 = | 0 | 0 |16U|16V|
 movd mm5, [esi+4] // mm5 = | 0 | 0 | 0 |16Y|

 pslld mm5, 12     // mm5 = |   0   | Y | 0 |
 movq mm0, [yuv2r]

 pmaddwd mm0, mm6  // mm0 = |   0   |R-Y|0.r|
 movq mm1, [yuv2g]

 pmaddwd mm1, mm6  // mm1 = |   0   |G-Y|0.g|
 movq mm2, [yuv2b]

 pmaddwd mm2, mm6  // mm2 = |   0   |B-Y|0.b|
 paddd mm0, mm5    // mm0 = |   0   | R |0.r|

 paddd mm1, mm5    // mm1 = |   0   | G |0.g|
 paddd mm2, mm5    // mm2 = |   0   | B |0.b|

 psrlq mm0, 16     // mm0 = |   0   | 0 | R |
 pand mm1, [gmask] // mm1 = |   0   | G | 0 |

 psllq mm0, 32     // mm0 = | 0 | R | 0 | 0 |
 psrld mm2, 16     // mm2 = |   0   | 0 | B |

 por mm1, mm2      // mm1 = |   0   | G | B |
 add esi, 8

 por mm0, mm1      // mm0 = | 0 | R | G | B |
 add edi, 4

 packuswb mm0, mm7 // mm0 = |0|0|0|0|0|r|g|b|
 dec ecx

 movd [edi-4], mm0
 jnz yuv2rgb


Argl, just paste the code in your fav text editor, I just don't get it properly arranged here.

And concerning chroma noise reduction: is it sufficient to just average between two frames, or should I consider saving more frames like temporal smoother does?

 
  Top
phaeron
Posted: Dec 13 2002, 04:43 AM


Virtualdub Developer


Group: Administrator
Posts: 7773
Member No.: 61
Joined: 30-July 02



There isn't a whole lot of room to manuever in that code, but if you swap U and V in your scanline format, you can generate R-Y and B-Y at the same time with pmulhw and then use punpcklwd to squish G-Y in the middle. It may not be better, however, since you will have to broadcast Y and that is annoying without pshufw. If you have pshufw then there's no point as you can simply use brute force matrix multiplication.

The way I typically attack this problem is to generate RGB from four pixels in parallel, pack them down to bytes, then reinterleave in two stages (RBRB + xGxG -> xRGBxRGB). This ends up putting a lot of pressure on the shifter, though, and you still have accuracy issues to deal with. In your case it's not quite so bad since you don't have a bias and scale factor on Y to deal with.
 
    Top
1 User(s) are reading this topic (1 Guests and 0 Anonymous Users)
0 Members:
5 replies since Dec 12 2002, 11:54 AM Track this topic | Email this topic | Print this topic

<< Back to VirtualDub Filters and Filter Development