Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion.

Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules.

 

Go Back   Doom9's Forum > Capturing and Editing Video > Avisynth Development

Reply
 
Thread Tools Search this Thread Display Modes
Old 26th January 2024, 07:34   #1  |  Link
zerowalker
Registered User
 
Join Date: Jul 2011
Posts: 1,121
Converting YUV to RGB formulas?

This is off topic as it's not really for avisynth development,
but hopefully it's close enough for a pass, otherwise I can be taken down of course.

I'm trying to figure out the correct formula for converting YUV to RGB,
both Rec601/Rec709 with Limited/Full range.

The ones I have found doesn't seem to match what avisynth produces,
apart from one which is this:

Code:
R = 1.164 * (Y - 16) + 1.793 * (U - 128);
G = 1.164 * (Y - 16) - 0.534 * (U - 128) - 0.213 * (V- 128);
B = 1.164 * (Y - 16) + 2.115 * (V - 128);
(where R,G,B are rounded when converting to 8bit).

This produces as far as i can tell the same results Rec709 Limited.
But it doesn't really match the formula shown here: https://en.wikipedia.org/wiki/Y%E2%80%B2UV

And i also don't know how to make it full range, except for the Y part.

I tried looking at the avisynth code to figure this out,
but it was harder than I thought.

So was hoping to get some help here if possible
zerowalker is offline   Reply With Quote
Old 26th January 2024, 08:26   #2  |  Link
Sharc
Registered User
 
Join Date: May 2006
Posts: 3,997
Your matrix above applies for Rec709 limited range Y'CbCr -> Full range RGB conversion. (You may have mixed up U an V though, please double check)
U and V are from the analog realm; one should actually be using Cb and Cr in the digital realm. Sometimes interchangeably used, unfortunately.

For conversions you may want to take a look here:
https://web.archive.org/web/20120403...rmatConversion

or check out the tool here:
https://res18h39.netlify.app/color

Last edited by Sharc; 26th January 2024 at 11:13. Reason: Link added
Sharc is offline   Reply With Quote
Old 26th January 2024, 13:57   #3  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,431
See also here: http://avisynth.nl/index.php/Color_conversions
__________________
GScript and GRunT - complex Avisynth scripting made easier
Gavino is offline   Reply With Quote
Old 26th January 2024, 15:41   #4  |  Link
DTL
Registered User
 
Join Date: Jul 2018
Posts: 1,062
Correct equations are in the free available ITU documents (601/709/2020) .

AVS+ narrow range in current builds is not completely correct (waiting for pinterf patch merging).

There possible very many forms of simplified equations for each use case and it is not easy to check the result. So if current ready to use simplified equations not provide correct/expected values - it is good to start from official documents from ITU.

Simple C-form (reference) in the decodeYUVtoRGB plugin - https://github.com/DTL2020/ConvertYU...eYV12toRGB.cpp

iY = *l_srcp_Y + Ybias; // Ybias = -16
iU = *l_srcp_U + UVbias; // UVbias=-128
iV = *l_srcp_V + UVbias; // UVbias=-128

int iR = iY + ((iV * Kr) >> 13);
int iB = iY + ((iU * Kb) >> 13);
int iG = iY - ((iU * Kgu) >> 13) - ((iV * Kgv) >> 13);

and Kr, Kgu, Kgb, Kb
/* Computing of (Kr, Kgu, Kgv, Kb) from (Yr and Yb) coefficients of YUV colour system:

Yr
Yg = 1.0 - (Yr + Yb)
Yb

Kb = (1.0 - Yb) * 2
Kr = (1.0 - Yr) * 2

Kgu = (Yb * Kb) / Yg
Kgv = (Yr * Kr) / Yg

for Digital UV (601/709/2020):
RatioUVtoY = 219.0/224.0

Kr,Kb,Kgu,Kgv *= RatioUVtoY

*/

if (Matrix == 0) // 601
{
fYr = 0.299f;
fYb = 0.114f;
}
else if (Matrix == 1) // 709
{
fYr = 0.2126f;
fYb = 0.0722f;
}
else if (Matrix == 2) // 2020 (ncl ?)
{
fYr = 0.2627f;
fYb = 0.0593f;
}

float fKb = (1.0f - fYb) * 2.0f;
float fKr = (1.0f - fYr) * 2.0f;
float fYg = 1.0f - (fYr + fYb);

Kr = (short)(fKr * fRatioUVtoY * UVgain * mulfac + 0.5f);
Kb = (short)(fKb * fRatioUVtoY * UVgain * mulfac + 0.5f);
Kgu = (short)(((fYb * fKb) / fYg) * fRatioUVtoY * UVgain * mulfac + 0.5f);
Kgv = (short)(((fYr * fKr) / fYg) * fRatioUVtoY * UVgain * mulfac + 0.5f);

UVgain=1.0, mulfac = double(1 << int_arith_shift); // integer aritmetic precision scale

Last edited by DTL; 27th January 2024 at 22:28.
DTL is offline   Reply With Quote
Old 26th January 2024, 17:27   #5  |  Link
pinterf
Registered User
 
Join Date: Jan 2014
Posts: 2,314
Quote:
Originally Posted by DTL View Post
AVS+ narrow range in current builds is not completely correct (waiting for pinterf patch merging).
Actually, there was a patch on this area.
pinterf is offline   Reply With Quote
Old 27th January 2024, 08:21   #6  |  Link
zerowalker
Registered User
 
Join Date: Jul 2011
Posts: 1,121
Quote:
Originally Posted by Sharc View Post
Your matrix above applies for Rec709 limited range Y'CbCr -> Full range RGB conversion. (You may have mixed up U an V though, please double check)
U and V are from the analog realm; one should actually be using Cb and Cr in the digital realm. Sometimes interchangeably used, unfortunately.

For conversions you may want to take a look here:
https://web.archive.org/web/20120403...rmatConversion

or check out the tool here:
https://res18h39.netlify.app/color
Always been confused with YUV and Y'CbCr,
Thought Y'CbCr was "Component Video" and YUV was, well the normal stuff, both Digital and Analogue where it's Y, U and V.

@DTV

Will try it out, was more steps there than "usual", will try to find the ITU documentations as well for the equations.

Last edited by zerowalker; 27th January 2024 at 08:24.
zerowalker is offline   Reply With Quote
Old 27th January 2024, 12:31   #7  |  Link
Sharc
Registered User
 
Join Date: May 2006
Posts: 3,997
Quote:
Originally Posted by zerowalker View Post
Always been confused with YUV and Y'CbCr,
Thought Y'CbCr was "Component Video" and YUV was, well the normal stuff, both Digital and Analogue where it's Y, U and V.
RGB or YUV or Y'CbCr or Y'PbPr all belong to "component" video.
The symbols U and V are sometimes used quite loosely. Avisynth adopted U and V for the digital realm (probably for convenience and historic reasons) rather than Cb and Cr. For the discussion here you can assume U=Cb and V=Cr.
Sharc is offline   Reply With Quote
Old 27th January 2024, 18:04   #8  |  Link
DTL
Registered User
 
Join Date: Jul 2018
Posts: 1,062
"Thought Y'CbCr was "Component Video""

Most important difference between Analog (abstract YUV or defined in 0..XXX mV voltage range typically with zero black and zero UV for math zero value) and Digital YUV (CbCr for Coded B-Y and R-Y?) in storage and transfer domains data form. The 601/709/2020 recs are about digital exchange formats for motion pictures - not only abstract YUV-descriptions. Analog YUV looks like exist in the equal scale Y and UV signals (as provided from RGB->YUV matrix). Digital YUV uses quantization and some Digital YUV systems uses non-equal scale for Y and UV data in the output (storage and transfer/distribution/interfacing) form.

For performance of processing in lowest possibe steps number real YUV<->RGB equations are significantly compacted.

Real steps are:
1. Decode YUV from Digital YUV storage domain into abstract YUV 0..1 float domain.
2. Apply YUV->RGB matrix conversion in abstract 0..1 float domain.
3. Convert (encode) RGB into output digital domain (or other required at output).

Some designers with good understanding in math can warp 1+2+3 in the single step processing by some compute engine. It make best processing performance but may suffer from issues if something important is missing. And also harder or impossible to debug in steps.

The 601/709/2020 recs define Digital (quantized form) YUV domain as having non-equal scale for Y and UV data (219 for Y and 224 for UV/CbCr). It may be designed to have a bit less quantization noise in UV low-bit data with natural colour gamuts for these systems (or for YUV as having larger colour gamut in compare with RGB).
So the very typical error for convertor designers is missing Y and UV input data normalization to equal scale. It is 219/224 ratio in the math displayed. The resulted error is not very big but visible even in 8bit samples.

Last edited by DTL; 27th January 2024 at 22:30.
DTL is offline   Reply With Quote
Old 29th January 2024, 07:32   #9  |  Link
zerowalker
Registered User
 
Join Date: Jul 2011
Posts: 1,121
Quote:
Originally Posted by DTL View Post
"Thought Y'CbCr was "Component Video"...
Thanks for the explanation

When doing the y offset (Y-16) in float (0-1).
Isn't it (Y-(16/255))?

Cause when I do this Rec709 is valid,
but Rec601 is wrong by a tiny amount,
but (Y-(16/256)) makes it valid.


(valid as in, identical to avisynth).

EDIT:

Okay even PC.601 becomes a tiny bit wrong.

EDIT 2:
Okay it seems this happens even with ffmpeg, is it cause some small math error in avisynths conversion?

Last edited by zerowalker; 29th January 2024 at 16:58.
zerowalker is offline   Reply With Quote
Old 29th January 2024, 17:20   #10  |  Link
DTL
Registered User
 
Join Date: Jul 2018
Posts: 1,062
"When doing the y offset (Y-16) in float (0-1).
Isn't it (Y-(16/255))?"

0..1 range in float is 16 to 235 code values in 8bit Digital YUV (scaled + shifted/offsetted). 235-19=219.

Typically we subtract 16 and maps result of 0..219 to 0..1 float (so divide by 219.0). The range above 235 code values in storage Digital YUV 8bit is for super-whites (above nominal 100% white for SDR).

If you first convert 0..255 integer to float 0.0..255.0 it maybe also easy to subtract 16.0 and divide result to 219.0 (for performance - multiply to 1/219.0 constant). You will got black and nominal white in 0.0..1.0 range and negative under-blacks and 1.0+ super-whites.

For UV it is subtract 128 and divide by 224.

See https://www.itu.int/dms_pubrec/itu-r...3-I!!PDF-E.pdf 2.5.3 and 2.5.4

"it seems this happens even with ffmpeg, is it cause some small math error in avisynths conversion?"

AVS and ffmpeg may use integer computing with less precision for performance. Try ConvertBits(32) before ConvertToRGB and check output float32 RGB values.

See also some posts around https://forum.doom9.org/showthread.p...20#post1987720 about YUV to RGB decoding in AVS. Some +-1 rounding/computing errors still visible in 8bits. As fix maybe used 10bits (12..16) computing and rounding to 8bits with ConvertBits(8). So it is possible to get exactly 16/180 8bit RGB narrow code values for all colours of ColorBarsHD YUV output.

Last edited by DTL; 29th January 2024 at 17:49.
DTL is offline   Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 04:56.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.