BT.601/T.871:与 RGB(16 位)之间的转换
BT.601/T.871: Conversion to and from RGB (16bits)
我正在尝试理解 T.871 在 16 位输入的 RGB 和 YCbCr 之间的转换。对于 8 位信号,方程式很容易阅读。如果我们检查 T.871 第 7 节,第 4 页,我们得到:
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 )
我可以在 BT.601 节 §2.5.1 2.5.1 亮度构造中验证 E'Y、E'Cb 和 E'Cr 的方程[...]:
E'Y = 0.299 * E'R + 0.587 * E'G + 0.114 * E'B
以及第 2.5.2 节重新归一化色差信号的构造[...]:
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
所以我(天真的)对 16 位信号的解释很简单:
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 )
我尝试了一个快速的 C 代码来验证这一点,但这似乎是上面的等式不正确。
所以我的问题是:将 RGB 16 位信号转换为 YCbCr 的方程式是什么?
参考文献:
- https://en.wikipedia.org/wiki/YCbCr
- https://www.itu.int/rec/T-REC-T.871
- https://www.itu.int/rec/R-REC-BT.601
更新:我写道:
I tried a quick C code to verify this, but this seems the above
equations are not correct.
为了测试转换,我将生成的比特流封装在 DICOM 文件中(使用 gdcmimg),然后使用 DCMTK 将 DICOM 文件转换为 PPM:
$ dcmj2pnm ybr16.dcm ybr16.ppm
因为我的模板 DICOM 文件被声明为分配了 16 位的位,但只有 12 位存储 dcmj2pnm 会剥离任何高于 12 位最大值的高位,最终会变成绿色背景。
总而言之:方程式正确,我的测试不正确。
您的 16 位转换正确。
- 为了准确比较,我删除了
round
- 将所有值保留为 double
类型(仅用于测试目的)。
- 在比较 8 位和 16 位的 Cb、Cr 时,最重要也是最令人困惑的是 offset:
您需要在缩放之前减去偏移量(或除以 256
):
假设您有 Cb8
和 Cb16
,并且您想检查比率是 256
、
您需要做的第一件事是从 Cb8
中减去 128
,然后从 Cb16
中减去 32768
。
减法运算就像将值以零为中心。
示例:
Pb8 = Cb8 - 128
Pb16 = Cb16 - 32768
现在您可以比较 Pb8
和 Pb16
之间的比率:
Pb16 == Pb8*256
我曾经遵循 MATLAB 代码(比 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)
结果:
Ydiff = 0
Cb_diff = 0
Cr_diff = 0
我想下面的等式适用 Cr
和 Cb
而没有偏移(我命名为 Pb
和 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
对于 8 位:
Cr = E'Cr + 128
Cb = E'Cb + 128
对于 16 位:
Cr = E'Cr + 32768
Cb = E'Cb + 32768
我正在尝试理解 T.871 在 16 位输入的 RGB 和 YCbCr 之间的转换。对于 8 位信号,方程式很容易阅读。如果我们检查 T.871 第 7 节,第 4 页,我们得到:
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 )
我可以在 BT.601 节 §2.5.1 2.5.1 亮度构造中验证 E'Y、E'Cb 和 E'Cr 的方程[...]:
E'Y = 0.299 * E'R + 0.587 * E'G + 0.114 * E'B
以及第 2.5.2 节重新归一化色差信号的构造[...]:
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
所以我(天真的)对 16 位信号的解释很简单:
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 )
我尝试了一个快速的 C 代码来验证这一点,但这似乎是上面的等式不正确。
所以我的问题是:将 RGB 16 位信号转换为 YCbCr 的方程式是什么?
参考文献:
- https://en.wikipedia.org/wiki/YCbCr
- https://www.itu.int/rec/T-REC-T.871
- https://www.itu.int/rec/R-REC-BT.601
更新:我写道:
I tried a quick C code to verify this, but this seems the above equations are not correct.
为了测试转换,我将生成的比特流封装在 DICOM 文件中(使用 gdcmimg),然后使用 DCMTK 将 DICOM 文件转换为 PPM:
$ dcmj2pnm ybr16.dcm ybr16.ppm
因为我的模板 DICOM 文件被声明为分配了 16 位的位,但只有 12 位存储 dcmj2pnm 会剥离任何高于 12 位最大值的高位,最终会变成绿色背景。
总而言之:方程式正确,我的测试不正确。
您的 16 位转换正确。
- 为了准确比较,我删除了
round
- 将所有值保留为double
类型(仅用于测试目的)。 - 在比较 8 位和 16 位的 Cb、Cr 时,最重要也是最令人困惑的是 offset:
您需要在缩放之前减去偏移量(或除以256
):
假设您有 Cb8
和 Cb16
,并且您想检查比率是 256
、
您需要做的第一件事是从 Cb8
中减去 128
,然后从 Cb16
中减去 32768
。
减法运算就像将值以零为中心。
示例:
Pb8 = Cb8 - 128
Pb16 = Cb16 - 32768
现在您可以比较 Pb8
和 Pb16
之间的比率:
Pb16 == Pb8*256
我曾经遵循 MATLAB 代码(比 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)
结果:
Ydiff = 0
Cb_diff = 0
Cr_diff = 0
我想下面的等式适用 Cr
和 Cb
而没有偏移(我命名为 Pb
和 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
对于 8 位:
Cr = E'Cr + 128
Cb = E'Cb + 128
对于 16 位:
Cr = E'Cr + 32768
Cb = E'Cb + 32768