针对图像的缩放,对于比较小的图像,qt中已经提供了接口,直接调用就行。但是当图像比较大时,就不能使用接口了,因为接口里面实现了图像缩放的算法,图像大时,先计算再显示,计算很耗时,所以会很卡,不适用。本文针对大图像的缩放进行说明。
方法:参考google map,可以发现,显示的地图都是一层一层的,每一层的比例尺不一样,每一层的图像事先都已经保存在服务器了,用户需要哪一层直接从服务器传过来就可以了。我们这里是客户端软件,所以,每一层的图像必须自己先处理好保存起来,缩放时,需要哪一层图像直接调用图像出来显示这样就很快了。
每一层图像得到的方法:高斯金字塔,最底层为原图像,往上图像的宽和高依次缩小一倍,最小的图像到显示区域能全部显示为宜。
难点:如何确定要显示的是哪幅图像
假设每幅图都是QImage对象,则从金字塔底层向上依次保存在容器中:QVector<QImage*>
再设定一个变量layer,初始值为0(代表第一层),根据放大缩小按钮递增或递减layer值,然后根据layer在容器中查找该索引处的QImage,显示即可。
高斯金字塔构建的方法如下:
步骤:先通过与高斯核做卷积得到图像矩阵(与原图像大小相同),然后间隔采样得到下一层的图像,即为构建的金字塔图。
高斯核是一个5*5的矩阵,如下:
1 4 6 4 1
4 16 24 16 4
6 24 36 24 6
4 16 24 16 4
1 4 6 4 1
原图像某个位置的像素点的计算过程:以该点为中心,取5*5大小的像素矩阵,与高斯核做卷积,得到的数除以高斯核中数的总和。
高斯矩阵中每个值代表了像素点在计算中所占的权重,中心点(也是要输出的像素点)的权重当然是最大的,离中心点距离相同的点的权重相同。这样计算的得到的新图像通过间隔采样得到缩小一倍的图像,看起来会是平滑的,当然,缩小一倍看不出来平滑效果,多缩小几次(构建几层)就可以看出来了,较直接通过采样得到的缩略图具有很好的平滑性。
代码如下,只是得到金字塔上一层的数据,要的到构建多层的数据在代码基础上做循环迭代环就可以。这里我对无法做卷积的图像边界(上下的2行和左右的2列)保持值不变
1 void Gaussian(unsigned char* input,unsigned char* output,int sizeX,int sizeY) 2 { 3 //定义高斯内核模板 4 int gauKernel[25]={1,4,6,4,1, 5 4,16,24,16,4, 6 6,24,36,24,6, 7 4,16,24,16,4, 8 1,4,6,4,1}; 9 int powerSum=0; 10 //计算高斯模板总权值 11 for(int i=0;i<25;i++) 12 powerSum+=gauKernel[i]; 13 14 unsigned char* ldata;//高斯迭代后数据 15 ldata=NULL; 16 int lwidth=sizeX; 17 int lheight=sizeY; 18 int rwidth=sizeX/2;//高斯金字塔采样后的图像宽 19 int rheight=sizeY/2;//高斯金字塔采样后的图像高 20 21 /*第一次迭代,迭代前数据就是inputData*/ 22 //将input给ldata 23 ldata=new unsigned char[lwidth*lheight]; 24 for (int m=0;m<lheight;m++) 25 { 26 for (int n=0;n<lwidth;n++) 27 ldata[m*lwidth+n]=input[m*lwidth+n]; 28 } 29 //高斯平滑,是同input计算,结果保存于ldata中 30 for (int m=2;m<lheight-2;m++) 31 { 32 for (int n=2;n<lwidth-2;n++) 33 { 34 int sum=0; 35 //计算和高斯模板的卷积 36 for (int p=0;p<5;p++) 37 { 38 for (int q=0;q<5;q++) 39 { 40 sum+=input[(m+2-p)*lwidth+n+q-2]*gauKernel[p*5+q]; 41 } 42 } 43 ldata[m*lwidth+n]=sum/powerSum;//像素点值 44 } 45 } 46 //向下采样,去除偶数行和列 47 for (int m=0;m<rheight;m++) 48 { 49 for (int n=0;n<rwidth;n++) 50 { 51 output[m*rwidth+n]=ldata[(m*2+1)*lwidth+n*2+1]; 52 } 53 } 54 55 if (ldata) 56 { 57 delete []ldata; 58 ldata=NULL; 59 } 60 }