【问题标题】:BT.601/T.871: Conversion to and from RGB (16bits)BT.601/T.871:与 RGB(16 位)之间的转换
【发布时间】:2019-10-31 10:22:53
【问题描述】:

我试图理解 T.871 以在 RGB 和 YCbCr 之间进行 16 位输入的转换。对于 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 )

其中,精确到小数点后四位,可以近似为:

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 section §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 的方程式是什么?

参考资料:


更新:我写道:

我尝试了一个快速的 C 代码来验证这一点,但这似乎是上面的 方程不正确。

为了测试转换,我将生成的比特流封装在一个 DICOM 文件中(使用 gdcmimg),然后使用 DCMTK 将 DICOM 文件转换为 PPM:

$ dcmj2pnm ybr16.dcm ybr16.ppm

因为我的模板 DICOM 文件是用 16 位分配位声明的,但只有 12 位存储的 dcmj2pnm 会去除任何高于 12 位最大值的高位,最终会变成绿色背景。

总而言之:方程式是正确的,我的测试不是。

【问题讨论】:

  • 我试过你的代码,我得到了相同的结果(作为 16 位 YCC),如果你想要 8 位 YCC,只需移动结果
  • @GiacomoCatenazzi 你不能只移动 Cb 和 Cr,因为有一个偏移量。
  • @Rotem:你确定吗?高字节上的偏移量是 128,所以......正如预期的那样。
  • 请注意:原色定义在 601 和 709 之间变化(而 YCC 通常只有 709 或更高),并且有两个定义:全范围(不太常见,但似乎是您的方法),和受限范围(默认),因此在与其他程序比较值时,您应该检查是否使用了相同的定义(颜色空间和范围)。
  • @GiacomoCatenazzi “在高字节上”是什么意思?从数学的角度来看,没有“高字节”,只有值......

标签: colors rgb color-space


【解决方案1】:

您的 16 位转换正确

  • 为了准确比较,我删除了round - 将所有值保留在double 类型中(仅用于测试目的)。
  • 在比较 8 位和 16 位的 Cb、Cr 时,最重要且最令人困惑的是 偏移量
    您需要在缩放之前减去偏移量(或除以256):

假设你有Cb8Cb16,并且你想检查比率是256
您需要做的第一件事是从Cb8 中减去128,然后从Cb16 中减去32768
减法运算就像将值集中在零附近。

例子:

Pb8 = Cb8 - 128
Pb16 = Cb16 - 32768

现在你可以比较Pb8Pb16之间的比率:

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

我想下面的等式适用CrCb 没有偏移(我命名为PbPr)。

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

【讨论】:

    猜你喜欢
    • 2012-10-31
    • 1970-01-01
    • 2017-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-17
    相关资源
    最近更新 更多