Romi-知行合一

轻轻的风轻轻的梦,轻轻的晨晨昏昏, 淡淡的云淡淡的泪,淡淡的年年岁岁。
  博客园  :: 首页  :: 新随笔  :: 订阅 订阅  :: 管理

图像缩放

Posted on 2012-11-22 10:46  romi  阅读(2121)  评论(0编辑  收藏  举报

针对图像的缩放,对于比较小的图像,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 }