动态 16 色压缩算法

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 色的表现能力. 下面我展示几张图.

动态 16 色压缩算法_第1张图片

上面这张是大话西游这个游戏中的一个场景. 采用 jpeg 格式. 让大家看到全貌 :) (在大话西游中, 硬盘上就是以 jpeg 算法压缩的场景, 采用多线程动态加载的方式管理图片, 用辅线程只在需要的时候将屏幕附近的场景读入内存,并解码. 这也是一种节省内存的好方法)

为了能更细致的比较, 我将抽取局部, 用几种方案压缩比较, 并采用无损的 png, 格式放在下面:

 

这是原图一角. 真彩格式, 当然我们游戏里使用的高彩色. 我们可以看到右上角的蓝天白云非常细腻.

 

我用 octree 算法, 转换成 256 色的图片, 可以看到, 画面的右边的云层已经明显出了问题.

 

动态 16 色压缩算法_第2张图片 当我用 octree 的同时, 做了一下 Dither (误差扩散) 情况有了明显的改善, 但是由于 256 色色彩数的限制, 那些白云中出现了杂点.

 

我们可以看一下动态16色的算法的效果了. 即使不加 Dither 也很不错不是? 做一些细微的 Dither 会更好. 我们留在下面展示.

其实, 上面这一组图尚不能体现这种新算法相对 256 色图片的优势. 我们下面来看 mm 吧 :)

 

动态 16 色压缩算法_第3张图片 这张图有很多的过渡色, 这将是 256 色模式的致命之处

 

动态 16 色压缩算法_第4张图片 很糟糕:( 不是吗? 过渡色的细节全丢失了, 留下了大快的色斑. 这就是简单用 Octree 算法裁减调色盘的结果.

 

经过 Dither 后, 基本不错了:) 只是 mm 的面部变得粗糙, 画面上的背景也多了一些脏乱的杂点.

下面还是用无损压缩暂时细节, 但为了节约图片的显示时间, 我只放了局部上面. (动态16色技术, 和 256 色图片不同, 它的局部不会被整体影响, 而 256 色图将受到整体调色盘的牵制)

 

动态 16 色压缩算法_第5张图片 换用云风本文中提到的算法, 效果比简单的 256 色图片好很多. 当然, 细节还是很难看.

 

现在 Dither 一下. 情况能改善许多.

 

动态 16 色压缩算法_第6张图片 当需要提高画质的时候, 我们可以把 16x16 的采样块减少到 12x12 甚至 8x8. 当 8x8 为一个块的时候. 每快的数据为 64bytes (其实 32bytes 为颜色索引) 这和 256 色图片相当. 只是画质不可同日而语. 几乎接近了无损压缩.

在此算法的基础上, 我们还可以做简单的 RLE 压缩等等处理. 达到更高的压缩比. 希望大家看了本文能有所启发 :) 我个人认为此方法优于将图片转换成 256 色来介绍空间. 它的画质比 256 色高, 而压缩比更大. 如果依此定义出一种新的图象格式, 在技术上完全能取代 GIF. 当然 gif 的流行并非技术推动出来的.

附: 在色彩空间里找 16 个颜色可以最接近, 16*16=256 个像素 的颜色这个问题可能比一般人想的稍微复杂一点, 由于颜色教少, 像传统的 octree 基于色彩空间裁减的方法我试了后不太适用. 在写 encode 程序的时候还尝试过用模拟退火法逼近最优解. 可惜收敛速度过慢. 后来采用了一个苯方法, 建立一个 256*256 的表, 硬在里面搜索和匹配划简, 反而取得了很好的效果. 就是速度太慢. 编码一张 1024x768 的图片, 我的 1GHz CPU 都感觉慢吞吞的. 实在是有待改进啊.

你可能感兴趣的:(动态 16 色压缩算法)