在嵌入式系统中快速地进行屏幕拉伸,不能采用线性插值之类的算法,那样太慢。只能采用复制或抽取像素行的方式实现。
网上有介绍位图快速拉伸的算法,如下:http://www.abcdown.net/InfoView/Article_212765.html
假设欲将长度为N1的像素列变成长度为N2的像素列,首先,设立两个指针,一个作为源指针,指向原来的像素列,读取源像素,另一个作为目的指针,指向变换后的像素列,写入读取到的像素。然后,以拉伸后像素列的长度为循环次数,循环N2次,每次循环中由源指针处COPY一个像素到目的指针处,然后目的指针加一,源指针根据每次循环的不同需要增加一定步长(放大时步长是零或一,缩小时步长大于等于一)。
算法的框架解决了,但是中心内容仍没有解决:如何确定每次循环里源指针增加的步长?或者说,每次循环里如何更新源指针的位置?容易看出,通过浮点运算很容易解决这个问题:设立一个初值为零的浮点变量,每次循环中,把这个浮点变量加上N1/N2,并将其结果的整数部分作为源指针距离起始位置的偏移量;这样,经过N2次循环,浮点变量的值恰好达到N1,源指针也恰好“走”到原像素列的末尾。
这个方法可行,但是太慢。如果能将浮点运算转化成整数运算就快多了。那么如何转化呢?我们可以设立一个值域为N1*N2的整数计数器,每次循环递增N1,并且规定,计数器每增加N2,源指针就前进一个像素。这样,经过N2次循环,计数器共增加了N1*N2,源指针则增加了N1个单元,恰好“走”完全程。实际编程中,我们是用一个值域为N2的整数计数器,超出值域部分取模处理。算法大致如下:
int m = 0, count = 0;
for (int n = 0; n < N2; n++)
{
dest_pixels[n] = src_pixels[m];
count += N1;
while (count >= N2)
{
count -= N2;
m++;
}
}
上面已经说得比较明白了,不过对于愚钝的我来说,还是不容易理解。于是再分解如下:
用插值的思维来看,目的像素与源像素的关系其实如下:
dest_pixels[(n)=src_pixels(n*N1/N2) ,n=1,2,...,N2
由于只有整数点像素,其中的n*N1/N2要进行取整。
[n*N1/N2]就是n*N1除以N2得到的整数部分嘛,怎么用算法来求整数部分呢?
设p=[n*N1/N2]=n*N1-m*N2 (m为一整数,p<N2)
就用n*N1每次减一个N2,m增加1, 直到p<=0为止,得到的m值就是n*N1/N2的整数部分。
m=0;
c=n*N1;
while(c>0)
{
c-=N2;
m++;
}
这样最上面的源程序就容易明白了,里面的while循环其实就是用来求n*N1/N2的整数部分的。稍微不同的是,最上面的源程序中的count、m是从一开始就累减和累加的,不用每个n都重新求,精度会不会稍有些不同?