動態 16 色壓縮演算法

2021-06-09 00:20:29 字數 3177 閱讀 8679

2d 遊戲中, 通常是最佔記憶體的一種資源, 當記憶體因為遊戲用圖的量增加而吃勁的時候, 尋找高解碼速度的圖象壓縮演算法通常是最直接的解決方案之一. 這些方法的乙個共性就是需要 engine 的編寫者有較高的彙編能力. 需要自己實現基本的 blit 函式, 再就是解碼演算法要相當簡單, 能夠滿足實時的要求, 使得可以直接在記憶體中存放壓縮的資料, 在顯示的時候, 一邊解碼一邊傳送到顯示 buffer 中去.

最為常用的是 rle 演算法, 但是只對 sprite 效果比較明顯, 可以摳去大約 30%~50% 的透明色資料. 其次就是在高彩遊戲中使用 256 色資料, 和 256 色遊戲不同的是, 往往是採用多個調色盤, 使得色彩足夠豐富, 這樣可以節省 50% 的記憶體空間. 不過對於大塊色彩豐富的圖象, 容易形成馬賽克, 或一些花斑.

在這裡, 雲風將介紹一種自己發現的, 更為有效的方法. 我名名為動態 16 色壓縮演算法. 壓縮方法就是將一張高彩, 按 16x16 畫素塊分割開. 對每塊 256 個畫素點進行統計分析, 找到 16 個不同的顏色, 能夠最精確的描述這 256 個畫素. 然後以每個畫素 4bit 的方式進行儲存下 256 個 index 值. 並在這個塊首儲存下 16 個 index 對應的 16 種顏色. 每種顏色 16bit (高彩) 這樣. 每個 16x16 的塊只占用了 4 bits*16*16+16 bits*16=1280 bits=160 bytes. 而以 256 色方式儲存卻需要 8bits*16*16=256 bytes. 體積只有之 62.5%. 相對高彩的原圖, 體積僅為 31.25%. 而只需要適當的編寫對應的 blit 函式, 速度比 256 色有過之而無不及.

這個方法的起源於雲風對 jpeg 壓縮的研究. 有了理論基礎, 我在沒有看到效果前, 並不對這種壓縮結果的畫質有絲毫的懷疑. 但是畢竟寫出壓縮程式, 真正處理出壓縮欣賞, 更有成功感. 而且恐怕很多朋友會十分懷疑區域性 16 色的表現能力. 下面我展示幾張圖.

上面這張是大話西遊這個遊戲中的乙個場景. 採用 jpeg 格式. 讓大家看到全貌 :) (在大話西遊中, 硬碟上就是以 jpeg 演算法壓縮的場景, 採用多執行緒動態載入的方式管理, 用輔線程只在需要的時候將螢幕附近的場景讀入記憶體,並解碼. 這也是一種節省記憶體的好方法)

為了能更細緻的比較, 我將抽取區域性, 用幾種方案壓縮比較, 並採用無損的 png, 格式放在下面:

這是原圖一角. 真彩格式, 當然我們遊戲裡使用的高彩色. 我們可以看到右上角的藍天白雲非常細膩.

我用 octree 演算法, 轉換成 256 色的, 可以看到, 畫面的右邊的雲層已經明顯出了問題.

當我用 octree 的同時, 做了一下 dither (

誤差擴散

) 情況有了明顯的改善, 但是由於 256 色色彩數的限制, 那些白雲中出現了雜點.

我們可以看一下動態16色的演算法的效果了. 即使不加 dither 也很不錯不是? 做一些細微的 dither 會更好. 我們留在下面展示.

其實, 上面這一**尚不能體現這種新演算法相對 256 色的優勢. 我們下面來看 mm 吧 :)

這張圖有很多的過渡色, 這將是 256 色模式的致命之處

很糟糕:( 不是嗎? 過渡色的細節全丟失了, 留下了大快的色斑. 這就是簡單用 octree 演算法裁減調色盤的結果.

經過 dither 後, 基本不錯了:) 只是 mm 的面部變得粗糙, 畫面上的背景也多了一些髒亂的雜點.

下面還是用無失真壓縮暫時細節, 但為了節約的顯示時間, 我只放了區域性上面. (動態16色技術, 和 256 色不同, 它的區域性不會被整體影響, 而 256 色圖將受到整體調色盤的牽制)

換用雲風本文中提到的演算法, 效果比簡單的 256 色好很多. 當然, 細節還是很難看.

現在 dither 一下. 情況能改善許多.

當需要提高清的時候, 我們可以把 16x16 的取樣塊減少到 12x12 甚至 8x8. 當 8x8 為乙個塊的時候. 每快的資料為 64bytes (其實 32bytes 為顏色索引) 這和 256 色相當. 只是畫質不可同日而語. 幾乎接近了無失真壓縮.

在此演算法的基礎上, 我們還可以做簡單的 rle 壓縮等等處理. 達到更高的壓縮比. 希望大家看了本文能有所啟發 :) 我個人認為此方法優於將轉換成 256 色來介紹空間. 它的畫質比 256 色高, 而壓縮比更大. 如果依此定義出一種新的圖象格式, 在技術上完全能取代 gif. 當然 gif 的流行並非技術推動出來的.

附: 在色彩空間裡找 16 個顏色可以最接近, 16*16=256 個畫素 的顏色這個問題可能比一般人想的稍微複雜一點, 由於顏色教少, 像傳統的 octree 基於色彩空間裁減的方法我試了後不太適用. 在寫 encode 程式的時候還嘗試過用模擬退火法逼近最優解. 可惜收斂速度過慢. 後來採用了乙個苯方法, 建立乙個 256*256 的表, 硬在裡面搜尋和匹配劃簡, 反而取得了很好的效果. 就是速度太慢. 編碼一張 1024x768 的, 我的 1ghz cpu 都感覺慢吞吞的. 實在是有待改進啊.

RGB顏色與16進製制色以及透明色

劉巨集亮的部落格 rgb顏色與16進製制色以及透明色是我們在開發經常要用到的,不太明白可以花幾分鐘看看 rgb色彩模式是工業界的一種顏色標準,是通過對紅 r 綠 g 藍 b 三個顏色通道的變化以及它們相互之間的疊加來得到各式各樣的顏色的,rgb即是代表紅 綠 藍三個通道的顏色,這個標準幾乎包括了人類...

UIColor的16進製制色值,16進製制字串擴充套件

inte ce uicolor hex 16進製制字串轉化為顏色 param hexstr 16進製制字串 支援 0x.0x.return uicolor uicolor colorwithhexstring nsstring hexstr 16進製制字串轉化為顏色 param hexstr 16進...

從RGB色轉為灰度色演算法

一 基礎 對於彩色轉灰度,有乙個很著名的心理學公式 gray r 0.299 g 0.587 b 0.114 二 整數演算法 而實際應用時,希望避免低速的浮點運算,所以需要整數演算法。注意到係數都是3位精度的沒有,我們可以將它們縮放1000倍來實現整數運算演算法 gray r 299 g 587 b...