【问题标题】:Lossless RGB to Y'CbCr transformation无损 RGB 到 Y'CbCr 转换
【发布时间】:2012-05-20 22:53:35
【问题描述】:

我正在尝试无损压缩图像,为了利用规律性,我想将图像从 RGB 转换为 Y'CbCr。 (我所说的 RGB 和 Y'CbCr 的确切细节在这里并不重要;RGB 数据由三个字节组成,我有三个字节来存储结果。)

转换过程本身非常简单,但有一个问题:虽然转换在数学上是可逆的,但实际上会存在舍入误差。当然,这些错误很小,几乎不引人注意,但这确实意味着该过程不再是无损的。

我的问题是:是否存在转换,将三个八位整数(代表红色、绿色和蓝色分量)转换为三个其他八位整数(代表类似于 Y'CbCr 的颜色空间,其中两个分量发生变化仅略微相对于位置,或者至少比在 RGB 颜色空间中小),并且可以在不丢失信息的情况下进行反转?

【问题讨论】:

    标签: rgb color-space lossless-compression


    【解决方案1】:

    YCoCg24

    这是一种我称之为“YCoCg24”的颜色转换,它将三个八位整数(表示红色、绿色和蓝色分量)转换为三个其他八位(有符号)整数(表示类似于 Y'CbCr 的颜色空间),并且是双射的(因此可以在不丢失信息的情况下进行反演):

     G          R          B     Y          Cg         Co
     |          |          |     |          |          |
     |          |->-(-1)->(+)   (+)<-(-/2)<-|          |
     |          |          |     |          |          |
     |         (+)<-(/2)-<-|     |->-(+1)->(+)         |
     |          |          |     |          |          |
     |->-(-1)->(+)         |     |         (+)<-(-/2)<-|
     |          |          |     |          |          |
    (+)<-(/2)-<-|          |     |          |->-(+1)->(+)
     |          |          |     |          |          |
     Y          Cg         Co    G          R          B
    
    forward transformation       reverse transformation
    

    或在伪代码中:

    function forward_lift( x, y ):
        signed int8 diff = ( y - x ) mod 0x100
        average = ( x + ( diff >> 1 ) ) mod 0x100
        return ( average, diff )
    
    function reverse_lift( average, signed int8 diff ):
        x = ( average - ( diff >> 1 ) ) mod 0x100
        y = ( x + diff ) mod 0x100
        return ( x, y )
    
    function RGB_to_YCoCg24( red, green, blue ):
        (temp, Co) = forward_lift( red, blue )
        (Y, Cg)    = forward_lift( green, temp )
        return( Y, Cg, Co)
    
    function YCoCg24_to_RGB( Y, Cg, Co ):
        (green, temp) = reverse_lift( Y, Cg )
        (red, blue)   = reverse_lift( temp, Co)
        return( red, green, blue )
    

    一些示例颜色:

    color        R G B     Y CoCg24
    white      0xFFFFFF  0xFF0000
    light grey 0xEFEFEF  0xEF0000
    dark grey  0x111111  0x110000
    black      0x000000  0x000000
    
    red        0xFF0000  0xFF01FF
    lime       0x00FF00  0xFF0001
    blue       0x0000FF  0xFFFFFF
    

    G、R-G、B-G 色彩空间

    另一种颜色转换,将三个八位整数转换为三个其他八位整数。

    function RGB_to_GCbCr( red, green, blue ):
        Cb = (blue - green) mod 0x100
        Cr = (red  - green) mod 0x100
        return( green, Cb, Cr)
    
    function GCbCr_to_RGB( Y, Cg, Co ):
        blue = (Cb + green) mod 0x100
        red  = (Cr + green) mod 0x100
        return( red, green, blue )
    

    一些示例颜色:

    color        R G B     G CbCr
    white      0xFFFFFF  0xFF0000
    light grey 0xEFEFEF  0xEF0000
    dark grey  0x111111  0x110000
    black      0x000000  0x000000
    

    cmets

    lossless color space transforms 似乎不少。 Henrique S. Malvar 等人提到了几种无损色彩空间变换。 "Lifting-based reversible color transformations for image compression"; JPEG XR 中有无损色彩空间转换; 几个“lossless JPEG”提案中使用的原始可逆颜色变换(ORCT); G、R-G、B-G色彩空间; 等等。 Malvar 等人似乎对 24 位 RGB 像素的 26 位 YCoCg-R 表示感到非常兴奋。

    但是,几乎所有这些都需要超过 24 位来存储转换后的像素颜色。

    我在 YCoCg24 中使用的“lifting”技术类似于 Malvar 等人的技术以及 JPEG XR 中的无损色彩空间转换。

    因为加法是可逆的(加法模 0x100 是双射的),从 (a,b) 到 (x,y) 的 any 变换可以由以下Feistel network 产生是可逆的并且双射:

     a        b
     |        |
     |->-F->-(+)
     |        |
    (+)-<-G-<-|
     |        |
     x        y
    

    其中 (+) 表示 8 位加法(模 0x100),a b x y 都是 8 位值,F 和 G 表示任意函数。

    详情

    为什么你只有 3 个字节来存储结果? 这听起来像是适得其反的premature optimization。 如果您的目标是在合理的时间内将图像无损压缩成尽可能小的压缩文件,那么中间阶段的大小是无关紧要的。 甚至可能适得其反—— “较大”的中间表示(例如可逆颜色变换或 26 位 YCoCg-R)可能会导致最终压缩文件的大小比“较小”的中间表示(例如 RGB 或 YCoCg24)更小。

    编辑: 哎呀。 "(x) mod 0x100" 或 "(x) & 0xff" 之一给出完全相同的结果—— 我想要的结果。 但不知何故,我将它们混杂在一起,产生了一些行不通的东西。

    【讨论】:

    • 感谢您的详尽回答。 24 位要求的原因是一个实际的原因。我知道使用 26 位中间级可以提高压缩比(实际上,有多个中间级会增加流的大小)。但是,我使用的算法对单个字节而不是位进行操作。通过将比特流视为字节流,它会失去色彩空间变换引入的良好属性。
    • 是的,每当我将系统从字节流切换到比特流时,系统通常需要大约 8 倍的时间才能运行,而且调试起来也更加困难。所以我很同情你尽可能坚持使用字节流的愿望。
    • 大卫,这是一个非常酷的转换。非常感谢您提供它。需要注意的一点是,您的 reverse_lift 应该返回 x 和 y,而不是平均值和差异。
    • @DavidCary 在您的伪代码中,您将一些变量指定为signed int8,但在某些语言中,移动有符号整数是实现定义的。您对diff &gt;&gt; 1 的预期行为是什么?
    • @chewsocks:我打算用“diff >> 1”来做arithmetic right shift,在Java、JavaScript、Python、PHP、Ruby、Go、Julia、Swift等中拼写为“>>” . 并且在许多 C 实现中,例如 GCCLLVM,所以“-1 >> 1”导致 -1。但是,只要在两个方向上都使用相同的函数,除以 2 到零,即“-1 >> 1”的结果为 0,就会产生另一种无损变换。
    【解决方案2】:

    我确实找到了一个这样的解决方案,被 JPEG 2000 使用。它被称为可逆颜色变换 (RCT),在 WikipediaJPEG site 中进行了描述(尽管舍入方法不一致) .但是,结果不如不可逆颜色变换。

    我还在 Soo-Chang Pei 和 Jian-Jiun Ding 的论文 Improved Reversible Integer-to-integer Color Transforms 中找到了一种更好的方法。但是,该论文中描述的方法以及 JPEG 2000 使用的方法需要额外的位来存储结果。这意味着转换后的值不再适合 24 位。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多