代码之家  ›  专栏  ›  技术社区  ›  malat

BT.601/T.871:与RGB的转换(16位)

  •  0
  • malat  · 技术社区  · 6 年前

    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第2.5.1节第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
    

     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 ) 
    

    所以我的问题是:RGB 16位信号到YCbCr的转换方程是什么?


    我试着用一个快速的C代码来验证这个,但是上面好像是 方程式不正确。

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

    $ dcmj2pnm ybr16.dcm ybr16.ppm
    

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

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

    0 回复  |  直到 6 年前
        1
  •  1
  •   Rotem    6 年前

    你的16位转换是 对的 .

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

    Cb8 Cb16 ,并检查比率是否为 256个 ,
    128 Cb8标准 ,然后减去 32768 Cb16级
    减法运算类似于将值居中于0。

    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
    

    Cr = E'Cr + 128
    Cb = E'Cb + 128
    

    对于16位:

    Cr = E'Cr + 32768
    Cb = E'Cb + 32768