YCoCg24
这里介绍一种我称之为“YCoCg24”的颜色转换方法,它将三个8位整数(代表红、绿、蓝三个分量)转换成另外三个8位(有符号)整数(代表类似于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
评论
似乎有很多无损色彩空间转换。
Henrique S. Malvar等人在"基于提升的可逆色彩变换用于图像压缩"中提到了几种无损色彩空间变换;
JPEG XR中还有无损色彩空间变换;
在几个“无损JPEG”提案中使用的原始可逆色彩变换(ORCT);
G,R-G,B-G色彩空间;
等等。
Malvar等人对24位RGB像素的26位YCoCg-R表示非常感兴趣。
然而,几乎所有这些方法都需要存储超过24位的变换后的像素颜色。
我使用的 YCoCg24 中的 "lifting" 技术类似于 Malvar 等人所使用的技术,也类似于 JPEG XR 中的无损颜色空间转换。
由于加法是可逆的(且模 0x100 的加法是双射的),从 (a,b) 到 (x,y) 的任何变换,只要可以通过以下 Feistel 网络 产生,就是可逆和双射的:
a b
| |
|->-F->-(+)
| |
(+)-<-G-<-|
| |
x y
其中 (+) 表示 8 位加法(模 0x100),a、b、x、y 都是 8 位值,而 F 和 G 表示任意的函数。
细节
为什么只有 3 字节来存储结果?
这听起来像是一种逆向效果的过早优化。
如果你的目标是将图像无损压缩成尽可能小的压缩文件,并在合理的时间内完成,那么中间阶段的大小是无关紧要的。
甚至可能会适得其反--
一个“更大”的中间表示(例如可逆色彩转换或 26 位 YCoCg-R)可能会比“更小”的中间表示(例如 RGB 或 YCoCg24)产生更小的最终压缩文件大小。
编辑:
糟糕。
“(x) mod 0x100” 或 “(x) & 0xff” 中的任何一个都会给出我想要的结果。
但不知怎么的,我把它们搞混了,导致无法正常工作。