转换过程本身非常简单,但有一个问题:虽然转换在数学上是可逆的,但实际上会出现舍入误差.当然,这些错误很小,几乎无法察觉,但它确实意味着该过程不再是无损的.
我的问题是:是否存在转换,将三个八位整数(表示红色,绿色和蓝色分量)转换为另外三个八位整数(表示类似于Y’CbCr的颜色空间,其中两个分量仅稍微改变相对于位置,或至少小于RGB颜色空间),并且可以在不丢失信息的情况下反转?
解决方法
这是一个我称之为“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,Co ): (green,temp) = reverse_lift( Y,Cg ) (red,blue) = reverse_lift( temp,Co) return( red,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,blue ): Cb = (blue - green) mod 0x100 Cr = (red - green) mod 0x100 return( green,Cb,Cr) function GCbCr_to_RGB( Y,Co ): blue = (Cb + green) mod 0x100 red = (Cr + green) mod 0x100 return( red,blue )
一些示例颜色:
color R G B G CbCr white 0xFFFFFF 0xFF0000 light grey 0xEFEFEF 0xEF0000 dark grey 0x111111 0x110000 black 0x000000 0x000000
注释
似乎有相当多的lossless color space transforms.
Henrique S. Malvar等人提到了几种无损色彩空间变换. “Lifting-based reversible color transformations for image compression”;
在JPEG XR有无损色彩空间转换;
几个“lossless JPEG”提案中使用的原始可逆颜色变换(ORCT);
G,B-G色空间;
等等
Malvar等人似乎对24位RGB像素的26位YCoCg-R表示感到非常兴奋.
然而,几乎所有这些都需要超过24位来存储变换后的像素颜色.
我在YCoCg24中使用的“lifting”技术类似于Malvar等人的技术,以及JPEG XR中的无损色彩空间变换.
因为加法是可逆的(并且加法模0x100是双射的),所以可以由以下Feistel network产生的从(a,b)到(x,y)的任何变换是可逆的和双射的:
a b | | |->-F->-(+) | | (+)-<-G-<-| | | x y
其中()表示8位加法(模0x100),b x y都是8位值,F和G表示任意函数.
细节
为什么只有3个字节来存储结果?
这听起来像是适得其反的premature optimization.
如果您的目标是在合理的时间内将图像无损压缩为尽可能小的压缩文件,则中间阶段的大小无关紧要.
它甚至可能适得其反 –
“较大”的中间表示(例如可逆颜色变换或26位YCoCg-R)可以导致比“较小”中间表示(例如RGB或YCoCg24)更小的最终压缩文件大小.
编辑:Oopsies.“(x)mod 0x100”或“(x)& 0xff”中的任何一个给出完全相同的结果 – 我想要的结果.但不知怎的,我把它们混在一起产生了一些不起作用的东西.