位图缩放 

2007-08-14 09:29 发布

2323 0 0
给定一个位图,如何将它缩放至任意尺寸?

很明显,唯一的方法是:放大时,在像素中间添加一些重复像素,使图像拉宽;缩小时,把部分像素删除掉,使图像收缩。但是如何确定哪些像素该重复,哪些像素该删除呢?

下面给出的方法是我自已想的,也许不是很专业,哪位有更好的方法,观迎来信

 

我们只考虑水平方向(垂直方向跟水平方向是同样的道理)。下面先从简单的例子来说,最后再推出一个通用的算法:

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的整数计数器,超出值域部分取模处理。算法大致如下:

void StrechPixels(int N1, int N2, PIXEL src_pixels[], PIXEL dest_pixels[])
{
    ASSERT(N1 <= N2);            // N1 must <= N2

    int p1 = 0, count = 0;
    for (int p2 = 0; p2 < N2; p2++)
    {
        dest_pixels[p2] = src_pixels[p1];
        count += N1;
        while (count >= N2)
        {
            count -= N2;
            p1++;
        }
    }
}
			

上面算法只是水平缩放单行像素,对垂直方向也采用同样的算法,便实现了任意比例的位图缩放。

经过以上算法的处理,放大时图像出现马赛克,缩小时图像出现闪砾。若要获得高质量的缩放图形,须采用插值、过滤等技术。但是因为这些技术所需计算量太大,在游戏中通常靠硬件加速来实现,不宜软件解决。

TA的作品 TA的主页
B Color Smilies

你可能喜欢

位图缩放 
联系
我们
快速回复 返回顶部 返回列表