9

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

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

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

4

2 回答 2

16

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、RG、BG色彩空间

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

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

评论

似乎有不少无损色彩空间变换。Henrique S. Malvar 等人提到了几种无损色彩空间变换。“用于图像压缩的基于提升的可逆颜色变换”JPEG XR中有无损色彩空间转换;几个“无损JPEG ”提案中使用的原始可逆颜色变换(ORCT) ;G、RG、BG色彩空间;Malvar 等人似乎对 24 位 RGB 像素的 26 位 YCoCg-R 表示非常兴奋。

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

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

因为加法是可逆的(加法模 0x100 是双射的),所以可以由以下Feistel 网络产生的从 (a,b) 到 (x,y) 的任何变换都是可逆和双射的:

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

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

细节

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

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

于 2012-08-27T17:06:52.327 回答
2

我确实找到了 JPEG 2000 使用的一个这样的解决方案。它被称为可逆颜色变换 (RCT),它在Wikipedia以及JPEG 站点上都有描述(尽管舍入方法不一致)。然而,结果不如不可逆颜色变换。

我还在Soo-Chang Pei 和 Jian-Jiun Ding的论文改进的可逆整数到整数颜色变换中找到了一种更好的方法。但是,该论文中描述的方法以及 JPEG 2000 使用的方法需要额外的位来存储结果。这意味着转换后的值不再适合 24 位。

于 2012-05-12T22:47:49.630 回答