2012-05-12 95 views
7

我想要無損地壓縮圖像,並且爲了利用規律性,我想將圖像從RGB轉換爲Y'CbCr。 (我的意思是RGB和Y'CbCr的確切細節在這裏並不重要; RGB數據由三個字節組成,我有三個字節來存儲結果。)無損RGB到Y'CbCr轉換

轉換過程本身非常簡單,但有一個問題:雖然轉換是數學上可逆的,但實際上會有舍入誤差。當然,這些錯誤很小且幾乎不明顯,但它確實意味着該過程不再是無損的。

我的問題是:是否存在將三個八位整數(表示紅色,綠色和藍色分量)轉換爲三個其他八位整數(表示類似於Y'CbCr的色彩空間,其中兩個分量相對於位置僅稍微改變,或者至少小於RGB色彩空間),並且可以在不丟失信息的情況下進行反轉?

回答

14

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色彩空間

另一個顏色變換的三個8位整數轉換成其他三個八位整數。

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 

評論

似乎有不少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),其可以通過以下Feistel network來製造是可逆的,並且雙射:

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

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

細節

爲什麼你只需要3個字節來存儲結果嗎? 這聽起來像是反作用的premature optimization。 如果您的目標是在合理的時間內將圖像無損壓縮成儘可能小的壓縮文件,那麼中間階段的大小就無關緊要。它可能會適得其反 - 「較大」的中間表示(例如可逆顏色變換或26位YCoCg-R)可能會導致較小的最終壓縮文件大小比「較小」的中間表示(例如RGB或YCoCg24)。編輯: Oopsies。 「(x)mod 0x100」或「(x)& 0xff」中的任一個給出完全相同的結果 - 我想要的結果。 但不知何故,我把它們混雜在一起產生了一些不起作用的東西。

+0

謝謝你的詳細解答。 24位要求的原因是實用的。我知道使用26位中間階段可以提高壓縮比(事實上,有多箇中間階段會增加流的大小)。但是,我使用的算法對單個字節進行操作,而不是位。通過將比特流視爲字節流,它將失去顏色空間變換引入的優良屬性。 – Ruud

+0

是的,無論何時將系統從字節流切換到位流,系統通常需要運行8次左右才能運行,而且調試起來要困難得多。所以我同情你的願望,如果可能的話,堅持使用字節流。 –

+0

大衛,這是一個非常酷的轉變。非常感謝提供它。有一件事要注意,你的reverse_lift應該返回x和y,而不是平均值和差值。 – MoDJ

2

我找到了一個這樣的解決方案,用於JPEG 2000.它被稱爲可逆顏色變換(RCT),它在Wikipedia以及JPEG site(儘管舍入方法不一致)中有所描述。然而,結果並不像不可逆轉的顏色轉換那麼好。

我還發現文中所述的更好的方法裴昌培和丁建軍改進的可逆整數到整數顏色變換。但是,該文中描述的方法和JPEG 2000使用的方法需要額外的位來存儲結果。這意味着轉換後的值不再適合24位。