人气 207

[游戏程序] 位图缩放 [复制链接]

九艺网 2017-3-10 17:00:57

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

x
给定一个位图,如何将它缩放至任意尺寸?很明显,唯一的方法是:放大时,在像素中间添加一些重复像素,使图像拉宽;缩小时,把部分像素删除掉,使图像收缩。但是如何确定哪些像素该重复,哪些像素该删除呢?
下面给出的方法是我自已想的,也许不是很专业,哪位有更好的方法,观迎来信
 
我们只考虑水平方向(垂直方向跟水平方向是同样的道理)。下面先从简单的例子来说,最后再推出一个通用的算法:
A.若要放大1倍,应将每一个像素都重复一次,N个像素变成了2N个像素,图像放大为2倍。这个不难;
B.若要缩小1/2,应该每隔一个像素删除一个像素,2N个像素变成了N个像素,图像缩小一半。这个也不难;
C.若要放大1.5倍,怎么办?假设原有2N个像素,现在欲变成3N个像素,须添加N个像素,所以应对原图每隔一个像素添加一个重复像素:

                               
登录/注册后可看大图


D.若要缩小1/3,就是C的逆过程:每隔两个像素删除一个像素。
上面四个例子都是比较容易的特例。现在来考虑通用的算法。
刚才四个例子的缩放过程可以这样理解。假设欲将长度为N1的像素列变成长度为N2的像素列,首先,设立两个指针,一个作为源指针,指向原来的像素列,读取源像素,另一个作为目的指针,指向变换后的像素列,写入读取到的像素。然后,以拉伸后像素列的长度为循环次数,循环N2次,每次循环中由源指针处COPY一个像素到目的指针处,然后目的指针加一,源指针根据每次循环的不同需要增加一定步长(放大时步长是零或一,缩小时步长大于等于一)。
算法的框架解决了,但是中心内容仍没有解决:如何确定每次循环里源指针增加的步长?或者说,每次循环里如何更新源指针的位置?
容易看出,通过浮点运算很容易解决这个问题:设立一个初值为零的浮点变量,每次循环中,把这个浮点变量加上N1/N2,并将其结果的整数部分作为源指针距离起始位置的偏移量;这样,经过N2次循环,浮点变量的值恰好达到N1,源指针也恰好“走”到原像素列的末尾。
这个方法可行,但是太慢。如果能将浮点运算转化成整数运算就快多了。那么如何转化呢?
我们可以设立一个值域为N1*N2的整数计数器,每次循环递增N1,并且规定,计数器每增加N2,源指针就前进一个像素。这样,经过N2次循环,计数器共增加了N1*N2,源指针则增加了N1个单元,恰好“走”完全程。
实际编程中,我们是用一个值域为N2的整数计数器,超出值域部分取模处理。算法大致如下:
  1. void StrechPixels(int N1, int N2, PIXEL src_pixels[], PIXEL dest_pixels[])
  2. {
  3.     ASSERT(N1
复制代码
上面算法只是水平缩放单行像素,对垂直方向也采用同样的算法,便实现了任意比例的位图缩放。
经过以上算法的处理,放大时图像出现马赛克,缩小时图像出现闪砾。若要获得高质量的缩放图形,须采用插值、过滤等技术。但是因为这些技术所需计算量太大,在游戏中通常靠硬件加速来实现,不宜软件解决。

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

QQ|手机版|小黑屋|九艺游戏动画论坛 ( 津ICP备2022000452号-1 )

GMT+8, 2024-4-25 21:27 , Processed in 0.127045 second(s), 23 queries .

Powered by Discuz! X3.4  © 2001-2017 Discuz Team.