# Y,Cb,Cr to RGB

1. Working in BT.601, given the following 8-bit values for Y, Cr and Cb, what RGB values should I expect when converted from Y Cr Cb to RGB?

Y = 168

Cb = 44

Cr = 136

For convenience, here are the BT.601 coefficients:

#Kr = 0.299: #Kg = 0.587: #Kb = 0.114  Quote
2. Approx 75% Yellow (R=521.69mV, G=547.45mV, B=23.5mV - my assumption is YCbCr is limited quantization range and RGB full quantization range i.e. black = 0V and 100% is 700mV).

However seem you are confusing few things, YPbPr is video signal and as such it should be expressed as voltage (level) not number. YCbCr is expressed as number. Secondly if your goal was to get level in full or limited quantization range - you didn't provided this information so i've made some assumption.  Quote
3. 190, 203, 8  Quote
4. R=521.69 mV, G=547.45 mV, B=23.5 mV
Looking only at the red channel:

521.69 / 700 = 0.74527

0.74527 * 256 = 190.7

The Pb and Pr numbers are 8-bit values taken directly from Fig. 3.2, below:

http://car.france3.mars.free.fr/HD/INA-%2026%20jan%2006/SMPTE%20normes%20et%20confs/rp...9%20mirehd.pdf

The numbers I am expecting to see are R ~ 180, G ~ 180, B ~ 16. Is there a way to calculate this to get numbers closer to those expected? I'm not sure if I'm dealing with full or limited range. Also, there is a remote possibility that those Y, Pr, Pb numbers are for BT.709.  Quote
5. YUV "709":
YUV limited '709', rgb full out would be: 191,191,0
YUV full '709', rgb full out would be: 181,180,12
YUV limited '709', rgb limited out would be: 180,180,16
YUV full '709', rgb limited out would be: 171,171,26

YUV "601":
YUV limited '601', rgb full out would be: 190,203,8
YUV full '601', rgb full out would be: 179,191,19
YUV limited '601', rgb limited out would be: 179,191,22
YUV full '601', rgb limited out would be: 170,180,32

values are rounded +-1 or so
so your numbers would match limited "709" values YUV in and limited RGB out calculations  Quote
6. YUV limited '709', rgb limited out would be: 180,180,16
Thanks, Al, this is very helpful. Could you please share the equation you used to arrive at those numbers? I will then check them on all six primary and secondary colors.

The version of the RP 219 spec I have is from 2002 so it's possible those Y Pr Pb values were revised at some point to conform to BT.709, perhaps being for BT.601 in previous versions.  Quote
7. I do not have equations, using vapoursynth resize filter, once I really calculate it manually to prove that vs does that the same as your provided equations would, but that time, it was limited YUV 709 to full RGB:
it would need to be changed to limited rgb  Quote
8. Those values are for the 75% yellow limited range 709 bar. Upon conversion to full range RGB you should get about 191,191,0 (R,G,B). Converted to limited range RGB you should get about 180,180,12 (the blue channel should be 16 but rounding errors in the starting YCbCr cause it to drop). You already have the equations for this, we've covered it many times.  Quote
9. This code gets me close but is not very accurate:

Code:
```r = y + 2*(v-128)*(1-Kr)
g = y - 2*(u-128)*(1-Kb)*Kb/Kg - 2*(v-128)*(1-Kr)*Kr/Kg
b = y + 2*(u-128)*(1-Kb)```
Here are SMPTE color bars. Some values are off by a little; others are off by a lot, more than mere rounding error. Any ideas for making this more accurate? I'm expecting values of either 180 or 16.

75% White
180
180
180

Yellow
181
180
12

Blue
15
16
184

Green
13
181
12

Magenta
183
15
184

Red
183
15
16

Cyan
13
181
180

The YUV values are canonical per SMPTE RP 219 spec.  Quote
10.  Quote
11. Thank you, Sharc. This seems to get the values closer:

Code:
```r = 1.164 * (y-16) + 0 * (u-128) + 1.793 * (v-127): r + 16: r = Int(r * 0.867)

g = 1.17 * (y-16) + -0.213 * (u-128) + -0.533 * (v-128): g + 16: g = Int(g * 0.867)

b = 1.164 * (y-16) + 2.1 * (u-128): b + 16: b = Int(b * 0.867)```
75% White
R 236
G 236
B 234

Yellow
R 181
G 179
B 14

Blue
R 15
G 14
B 178

Green
R 15
G 179
B13

Magenta
R 181
G 14
B 179

Red
R 181
G 14
B 14

Cyan
R 15
G 180
B 178  Quote
12. "Studio RGB" aka "Limited Range RGB"

709
R = Y + 1.54(Cr-128)
G = Y - 0.459(Cr-128) - 0.183(Cb-128)
B = Y + 1.816(Cb-128)

601
R = Y + 1.371(Cr-128)
G = Y - 0.698(Cr-128) - 0.336(Cb-128)
B = Y + 1.732(Cb-128)  Quote
13. "Studio RGB" aka "Limited Range RGB"
From ITU-R BT.709-6 and BT601-7 I concluded once almost identical:
709
R = Y + 1.5396(Cr-128)
G = Y - 0.4577(Cr-128) - 0.1831(Cb-128)
B = Y + 1.8142(Cb-128)

601
R = Y + 1.3707(Cr-128)
G = Y - 0.6982(Cr-128) - 0.3365(Cb-128)
B = Y + 1.7324(Cb-128)

(But I thought the OP asked for RGB<->YPbPr conversion, rather than RGB<->YCbCr)  Quote
14. This code gets me close but is not very accurate:

Here are SMPTE color bars. Some values are off by a little; others are off by a lot, more than mere rounding error. Any ideas for making this more accurate? I'm expecting values of either 180 or 16.

The YUV values are canonical per SMPTE RP 219 spec.
Those values are ok - obviously math is without saturation (not clamped between 16..235 and 16..240) - if you do proper clamping then everything will be fine.

(But I thought the OP asked for RGB<->YPbPr conversion, rather than RGB<->YCbCr)
This is my point - OP ask for YPbPr but provide numbers for YCbCr and there is no information about quantization range.

In YPbPr, Y should be within 0..700mV, Pb and Pr shall be within -350..+350mV range (and analog signals are always in same "full quantization range").
As such this is important to understand OP question and provide valid answer.  Quote
15. In YPbPr, Y should be within 0..700mV, Pb and Pr shall be within -350..+350mV range (and analog signals are always in same "full quantization range").
As such this is important to understand OP question and provide valid answer.
I already explained this to you several posts ago, Pandy:

The Pb and Pr numbers are 8-bit values taken directly from Fig. 3.2, below:

http://car.france3.mars.free.fr/HD/INA-%2026%20jan%2006/SMPTE%20normes%20et%20confs/rp...9%20mirehd.pdf  Quote
16. This code works even better. +/- 1. I must have missed it in BT.709.6

From ITU-R BT.709-6 and BT601-7 I concluded once almost identical:
709
R = Y + 1.5396(Cr-128)
G = Y - 0.4577(Cr-128) - 0.1831(Cb-128)
B = Y + 1.8142(Cb-128)
Code:
```100% White
235
235
235

Yellow
180
180
16

Blue
16
16
180

Green
16
180
15

Magenta
180
16
181

Red
180
16
17

Cyan
16
180
179```  Quote
17. I already explained this to you several posts ago, Pandy:

The Pb and Pr numbers are 8-bit values taken directly from Fig. 3.2, below:

http://car.france3.mars.free.fr/HD/INA-%2026%20jan%2006/SMPTE%20normes%20et%20confs/rp...9%20mirehd.pdf
Issue is naming convention - YPbPr shall be reported in voltages (corresponding YCbCr values can be presented in parallel) - YPbPr is real analog signal where YCbCr is digital domain (samples) - this is why it is confusing.

You can check ITU-R BT.1361 and ITU-R BT.801 + R-REP-BT.2380 - not sure what naming convention is in US but in Europe this is quite strict.  Quote
18. Issue is naming convention - YPbPr shall be reported in voltages (corresponding YCbCr values can be presented in parallel) - YPbPr is real analog signal where YCbCr is digital domain (samples) - this is why it is confusing.  Quote
19. So you're saying...be strict about the numbers but not about the terms they refer to?
It seems inconsistent.

Scott  Quote
20. So you're saying...be strict about the numbers but not about the terms they refer to?
It seems inconsistent.

Scott
I'm not saying any such thing. I told Pandy several times and I'm telling you that the designations were taken from the SMPTE standard document without alteration by me.  Quote
21. This code works even better. +/- 1. I must have missed it in BT.709.6
Same again with higher precision. (I didn't try whether it makes a difference.)

for 709 Studio aka Limited Range RGB:
R = Y + 1.53964687446332(Cr-128)
G = Y - 0.457674666142168(Cr-128) - 0.183142873500381(Cb-128)
B = Y + 1.8141786671051(Cb-128)  Quote
22. This code works even better. +/- 1. I must have missed it in BT.709.6
Same again with higher precision. (I didn't try whether it makes a difference.)

for 709 Studio aka Limited Range RGB:
R = Y + 1.53964687446332(Cr-128)
G = Y - 0.457674666142168(Cr-128) - 0.183142873500381(Cb-128)
B = Y + 1.8141786671051(Cb-128)
Thanks for those. I tried them out and the RGB values are still +/- 1.  Quote
23. Thanks for those. I tried them out and the RGB values are still +/- 1.
This is normal - clamp result - between 0 and 255 in 8 bit analog, between 1 and 254 in digital domain with Bt.656 like interfaces.

Btw do you have final RP219?  Quote
24. Btw do you have final RP219?
The spec I have is dated January 21, 2002. What is the date of the latest version?  Quote
25. I hate it when people give only the final matrix equations for complex conversions. They're are nice for coding but do not elucidate where all the coefficients come from.

This code gets me close but is not very accurate:

Code:
```Kr = 0.299
Kg = 0.587
Kb = 0.114

r = y + 2*(v-128)*(1-Kr)
g = y - 2*(u-128)*(1-Kb)*Kb/Kg - 2*(v-128)*(1-Kr)*Kr/Kg
b = y + 2*(u-128)*(1-Kb)```
75% yellow: Y=168, Pb=44, Pr=136
The Kr, Kg, Kb coefficients are for rec.601 but your "YPbPr" values are for limited range rec.709 YCbCr. And they are rounded to the nearest integer. If you use the reciprocal equation and floating point for all the calculations you'll see that the actual limited range values for R=191, G=191, B=0 are Y=168.192, U=44.110, V=135.692. The quoted conversion equation is for converting full range YUV to full range RGB.

The correct coefficients and equations for converting full range RGB to limited range YUV (YCbCr), and full range RGB to full range YUV are given at the aviSynth.nl:

http://avisynth.nl/index.php/Color_conversions

The correct way convert studio (limited range) RGB to limited range YUV is to first convert the studio RGB to full range RGB then convert to limited range YUV using those equations. To reverse the operation convert the YUV to full range RGB then convert the full range RGB back to limited range RGB.

Code:
```sRGB = each studio RGB component
fRGB = each full range RGB component

sRGB = fRGB * 219 / 255 + 16
fRGB = (sRGB-16) * 255 / 219```
Where do the 255 and 219 values come from? Those are the ranges between the defined full black and full white. 255 = 255-0, 219 = 235-16. They should be familiar from the limited range YUV conversion equations.

Given those sRGB to fRGB equations and full range RGB to limited range YUV equations from from the AviSynth docs:

Code:
```Kr = 0.2126
Kg = 0.7152
Kb = 0.0722

y - 16 = (Kr*219/255)*r + (Kg*219/255)*g + (Kb*219/255)*b
v - 128 = 112/255*r - Kg*112/255*g/(1-Kr) - Kb*112/255*b/(1-Kr)
u - 128 = - Kr*112/255*r/(1-Kb) - Kg*112/255*g/(1-Kb) + 112/255*b

r = (255/219)*y + (255/112)*v*(1-Kr) - (255*16/219 + 255*128/112*(1-Kr))
g = (255/219)*y - (255/112)*u*(1-Kb)*Kb/Kg - (255/112)*v*(1-Kr)*Kr/Kg
- (255*16/219 - 255/112*128*(1-Kb)*Kb/Kg - 255/112*128*(1-Kr)*Kr/Kg)
b = (255/219)*y + (255/112)*u*(1-Kb) - (255*16/219 + 255*128/112*(1-Kb))```
You do the following:

First convert the sRGB to fRGB:

Code:
```R = (180-16) * 255 / 235 ~= 191
G = (180-16) * 255 / 235 ~= 191
B = (16-16) * 255 / 235 = 0```
Then plugging those values in the YUV conversion gives you limited range YUV components (rounded to the nearest integer) Y=168, U=44, V=136. Look familiar? Using the inverse conversion (and rounding) gives you back the r=191, g=191, b=0. And converting that fRGB back to sRGB gives you 180, 180, 16. With some other colors the round trip will be off by 1 or 2 units per component -- from the multiple rounding operations. If you run the equations in floating point (with no rounding) you'll find the conversions are accurate to within the accuracy of the floating point operations (roughly 1 in 10^7 with single precision fp, 1 in 10^16 with double precision fp).  Quote
26. The Kr, Kg, Kb coefficients are for rec.601 but your "YPbPr" values are for limited range rec.709 YCbCr.
I don't know if you've ever read the RP 219 spec but it does not explicitly state whether the Pattern 1 values are based on 601 or 709. Al identified them as 709 in post #5 in this thread. We're way past that now.

The correct way convert studio (limited range) RGB to limited range YUV
That's not what we're trying to do. This whole thread is about converting YUV or Y Cb Cr to RGB.  Quote

27. The correct way convert studio (limited range) RGB to limited range YUV is to first convert the studio RGB to full range RGB then convert to limited range YUV using those equations. To reverse the operation convert the YUV to full range RGB then convert the full range RGB back to limited range RGB.

Code:
```sRGB = each studio RGB component
fRGB = each full range RGB component

sRGB = fRGB * 219 / 255 + 16
fRGB = (sRGB-16) * 255 / 219```

I suggest something other than "sRGB" to indicate "studio" or limited range RGB, maybe "lRGB" ? "sRGB" is already taken as standard RGB

One issue with that method (for converting limited yuv to limited rgb) is original Y values <16, >235 will be clipped at the first step. One of the touted "benefits" for using studio RGB (instead of sRGB) is preserving the foot/head room. If you do the conversion in zimg/vapoursynth, or Sony Vegas studio RGB, the original values that were Y <16, >235 are visible. I do not believe converting to full range RGB first is correct, or at least it's different than what the "studio RGB" is in Vegas

EDIT:
Looking at this more closely:

If you run the equations in floating point (with no rounding) you'll find the conversions are accurate to within the accuracy of the floating point operations (roughly 1 in 10^7 with single precision fp, 1 in 10^16 with double precision fp).
My bad; this works if you run it in float . I think internally what you describe is what is happening in vegas and zimg (avsresize in avs) . expr (reverse polish notation) for the math in float, but using 8bit reference numbers, can be used with scale_inputs = "float"

In avs

#YV24 source (to eliminate subsampling differences)
ConvertBits(32)
ConvertToPlanarRGB(chromaresample="point", matrix="rec709")
expr("x 219 * 255 / 16 +", "x 219 * 255 / 16 +", "x 219 * 255 / 16 +", scale_inputs = "float")
ConvertBits(8)

or

#YV24 source (to eliminate subsampling differences)
z_ConvertFormat(pixel_type="RGB24", resample_filter="point", colorspace_op="709:709:709:l=>rgb:709:709:l")

These give the same results, and no range clipping that you get in 8bit RGB for the 1st step  Quote
28. The Kr, Kg, Kb coefficients are for rec.601 but your "YPbPr" values are for limited range rec.709 YCbCr.
I don't know if you've ever read the RP 219 spec but it does not explicitly state whether the Pattern 1 values are based on 601 or 709. Al identified them as 709 in post #5 in this thread. We're way past that now.

The correct way convert studio (limited range) RGB to limited range YUV
That's not what we're trying to do. This whole thread is about converting YUV or Y Cb Cr to RGB.
If that is true then why does your topic title refer to analog values?

Scott  Quote
29. why does your topic title refer to analog values?
Give it a a rest, dude. I'm not going to argue with you or explain it any further. You're being a PITA as is your wont.

I have changed the OP to Y Cb Cr. Now will you STFU?

Don't be surprised if you hear from a moderator. I have reported your post.  Quote
30. I hate it when people give only the final matrix equations for complex conversions. They're are nice for coding but do not elucidate where all the coefficients come from.
All right. That's how I did it:

I took the matrix coefficients for R'G'B' -> Y'CbCr conversion from ITU-R BT.709-6, formula 3.5. For 8bit n=8. [Attachment 63534 - Click to enlarge]

Then I inverted the matrix to obtain Y'CbCr -> R'B'G' which gave the coefficients of post #13 and #21

All in floating point, no integer rounding.  Quote