I am trying to make sense of T.871 for conversion in between RGB & YCbCr for 16bits inputs. The equations are trivial to read for 8bits signal. If we check T.871 Section §7, page 4 we get:
Y = Min( Max( 0, Round( 255 * E'Y ) ), 255 ) Cb = Min( Max( 0, Round( 255 * E'Cb + 128 ) ), 255 ) Cb = Min( Max( 0, Round( 255 * E'Cr + 128 ) ), 255 )
[...]
Y = Min(Max( 0, Round( 0.299 * R + 0.587 * G + 0.114 * B)), 255 ) Cb = Min(Max( 0, Round(( -0.299 * R - 0.587 * G + 0.886 * B)/1.772 + 128 )), 255 ) Cr = Min(Max( 0, Round(( 0.701 * R - 0.587 * G - 0.114 * B)/1.402 + 128 )), 255 )
which, to four decimal position accuracy, can be approximated by:
Y = Min(Max( 0, Round( 0.299 * R + 0.587 * G + 0.114 * B)), 255 ) Cb = Min(Max( 0, Round( -0.1687 * R - 0.3313 * G + 0.5 * B + 128 )), 255 ) Cr = Min(Max( 0, Round( 0.5 * R - 0.4187 * G - 0.0813 * B + 128 )), 255 )
I can verify the equation of E'Y, E'Cb & E'Cr in BT.601 section §2.5.1 2.5.1 Construction of luminance[...]:
E'Y = 0.299 * E'R + 0.587 * E'G + 0.114 * E'B
And section §2.5.2 Construction of re-normalized colour-difference signals[...]:
E'Cr = ( 0.701 * E'R - 0.587 * E'G - 0.114 * E'B) / 1.402 E'Cb = (-0.299 * E'R - 0.587 * E'G + 0.886 * E'B) / 1.772
So my (naive) interpretation for 16bits signal is simply:
Y = Min(Max( 0, Round( 0.299 * R + 0.587 * G + 0.114 * B)), 65535 )
Cb = Min(Max( 0, Round(( -0.299 * R - 0.587 * G + 0.886 * B)/1.772 + 32768 )), 65535 )
Cr = Min(Max( 0, Round(( 0.701 * R - 0.587 * G - 0.114 * B)/1.402 + 32768 )), 65535 )
I tried a quick C code to verify this, but this seems the above equations are not correct.
So my question is: What are the equations for conversion of RGB 16bits signal to YCbCr ?
References:
Update: I wrote:
I tried a quick C code to verify this, but this seems the above equations are not correct.
In order to test the conversion I encapsulated the generated bitstream inside a DICOM file (using gdcmimg) and then converted the DICOM file into PPM using DCMTK:
$ dcmj2pnm ybr16.dcm ybr16.ppm
Because my template DICOM file was declared with 16bits allocated bit, but only 12bits stored dcmj2pnm would strip off the high bits of anything above 12bit max value, which would eventually turn into a greenish background.
So in summary: the equations are correct, my test was not.
Your 16 bits conversion is correct.
round
- keeping all values in type double
(just for testing purposes). 256
): Assume you have Cb8
and Cb16
, and you want to check that the ratio is 256
,
First thing you need to do is subtract 128
from Cb8
, and subtract 32768
from Cb16
.
The subtraction operation is like centering the values around zero.
Example:
Pb8 = Cb8 - 128
Pb16 = Cb16 - 32768
Now you can compare the ratio between Pb8
and Pb16
:
Pb16 == Pb8*256
I used to following MATLAB code (easier than C):
R = 50;G = 100;B = 150; %Initialize RGB to arbitrary values.
%8 bits conversion
Y = min(max( 0, ( 0.299 * R + 0.587 * G + 0.114 * B)), 255 );
Cb = min(max( 0, (( -0.299 * R - 0.587 * G + 0.886 * B)/1.772 + 128 )), 255 );
Cr = min(max( 0, (( 0.701 * R - 0.587 * G - 0.114 * B)/1.402 + 128 )), 255 );
%Convert RGB to 16 bits.
scale = 256; %Assume conversion from 8 to 16 bits is scale by 256 (not scale by 65535/255).
R = R*scale;
G = G*scale;
B = B*scale;
%16 bits conversion
Y2 = min(max( 0, ( 0.299 * R + 0.587 * G + 0.114 * B)), 65535 );
Cb2 = min(max( 0, (( -0.299 * R - 0.587 * G + 0.886 * B)/1.772 + 32768 )), 65535 );
Cr2 = min(max( 0, (( 0.701 * R - 0.587 * G - 0.114 * B)/1.402 + 32768 )), 65535 );
Ydiff = Y*scale - Y2
Cb_diff = (Cb - 128)*scale - (Cb2 - 32768)
Cr_diff = (Cr - 128)*scale - (Cr2 - 32768)
Result:
Ydiff = 0
Cb_diff = 0
Cr_diff = 0
I suppose the following equations applies Cr
and Cb
without the offset (what I named Pb
and Pr
).
E'Cr = ( 0.701 * E'R - 0.587 * E'G - 0.114 * E'B) / 1.402
E'Cb = (-0.299 * E'R - 0.587 * E'G + 0.886 * E'B) / 1.772
For 8 bits:
Cr = E'Cr + 128
Cb = E'Cb + 128
For 16 bits:
Cr = E'Cr + 32768
Cb = E'Cb + 32768