QQ登录

只需一步,快速开始

登录 | 立即注册 | 找回密码
微像素首页 图像处理 图像优化 查看内容
订阅

文章

图像优化---超大图片内存加载分析与方法

发表时间:2015-9-18 10:43作者:风中人 阅读(893) 评论: 0来自: 微像素

导读: 分析计算机应用系统在加载/显示大型图片时内存资源耗费巨大问题产生的原因,提出解决该问题的方法,并给出一个通用的程序算法。

 一、加载/显示大型图片时的内存问题
  在很多图片应用系统、尤其是和地理信息有关的系统中,大图片和超大图片的加载与显示一直是一个影响系统运行速度的大问题。大图片加载时耗费大量的内存空间,导致系统运行速度变得缓慢,甚至发生内存溢出,所以解决这个问题的关键就在于减少内存消耗。
  我们知道,在计算机操作系统中,真彩图片占用存储空间大小=图片的像素×图片深度/8(Byte),如果分辨率用W×H表示,红、绿、蓝三个基本色的量化深度均为L,那么:图片占用存储空间大小=W×H×(L+L+L)/8(Byte)。图片深度是指位图中记录每个像素点所占的位数,它决定了彩色图片中可出现的最多颜色数,或者灰度图片中的最大灰度等级数。例如4色的图片用2位来表示一个像素,22=4;32色用5位来表示一个像素,25=32。如一张800*600的黑白图片,占计算机存储空间的大小为:800*600*1/8(Byte),而一张1024*768的16色图片占计算机存储空间的大小为:1024*768*4/8(Byte),我们可以发现分辨率越高,图片深度越大,文件的质量就越高,文件占计算机的存储空间也就越大;相反分辨率越低,图片深度越小,文件的质量就越低,文件占计算机的存储空间也就越小。
  一般地,位图在内存是ARGB (Alpha, Red, Green, Blue)格式存放的,每个像素占用4个字节,我们举例粗略估计一下图片加载需要耗费的内存:
  

图片大小(长*宽)(像素)耗费内存
400 * 400(400*400) * 4Byte ≈ 0.6M
4000 * 4000(4000*4000) * 4Byte ≈ 62M
10000 * 10000(10000*10000) * 4Byte ≈ 390M

上表大致计算了图片大小对应的内存耗费情况,我们可以看到,当图片像素达到1亿以上时,就将占用计算机一半左右的内存了(按照总共1G内存算),再加上计算机操作系统及其他应用软件的内存耗费,计算机运行速度必然会变得非常缓慢。免费论文网。而事实上,在大多数系统中,图片的累计大小远远大于(10000 * 10000)(像素)大小,对于那些累计起来动辄数亿、数十亿像素的大图片,一般的机器是根本不能正常加载它们的。
  二、解决思路
  为了正常加载/显示大图片,我们的基本思路就是不加载图片不用显示的部分,而只加载需要显示的那部分。免费论文网。要做到这样,我们首先把大图片分割成数个顺序的、均匀的、合适大小的小图片,在加载、显示的时候,我们只需通过计算找到需要加载的是那几个小图片即可,如下图所示:
  
  上图中,我们只需要加载pic001001.gif、pic001002.gif、pic001003.gif、pic002001.gif、pic002002.gif、pic002003.gif、pic003001.gif、pic003002.gif、pic003003.gif共9张小图片即可,当显示区域移动时,加载显示的小图片的编号改变,但是数量永远≤9,耗费的内存也不会变大。
  我们举例估计下满屏显示时以下两种分辨率下的内存耗费:
  

显示区域(长*宽)(像素)耗费内存
1024 * 768(1024*768) * 4Byte ≈ 3M
1280 * 1024(1280*1024) * 4Byte ≈ 5M

明显小多了,对系统运行速度几无影响。那么把大图片分割成多大的小图片才是最合理的呢?显然,分割得越小,加载的图片合计就越接近显示区域的大小,耗费的内存就越小。但是小图片数量大了管理麻烦,我们推荐分割成显示区域一样大小或者略大于显示区域大小,这样的话每次加载的图片数量最小为1,最大为4,从内存和计算角度来说是最合适的。当然具体分割成多少大小可以根据实际情况确定。
  三、一个通用的解决算法
  我们给出一个加载和显示图片的算法,该算法使用C#语言编写,能方便地通过鼠标拖动的方式加载和显示图片的所有部分。算法代码如下:
  1、新建一个用户自定义的可视化类。
  publicpartial class PictureBoxForLargeImage: PictureBox
  2、编写显示地图的函数,并通过用户鼠标拖动地图的方式在显示区域绘制地图。免费论文网。
  主要代码如下:
  privatevoid 显示地图(int 地图起点位置X, int 地图起点位置Y)
  {
  string 小地图文件名 = @"c:\地图\mappic"; //分割后各小地图的文件名称和路径
  int 小地图长 =600, 小地图高 = 400;//分割后各小地图的大小
  int 显示区域长= 1000, 显示区域高 = 700; //用户屏幕上显示地图区域的大小
  int i = 0, j = 0, k1 = 0, k2 = 0,m1 = 0, m2 = 0, c1 = 0, c2 = 0;
  // 计算最多需要加载多少小图片到内存
  m1 =decimal.ToInt32(decimal.Divide(显示区域长, 小地图长)) + 1;
  m2 =decimal.ToInt32(decimal.Divide(显示区域高, 小地图高)) + 1;
  // 计算需要显示的小图片的起始编号以及起始小图片的偏移量
  i =decimal.ToInt32(decimal.Divide(地图起点位置X, 小地图长));
  k1 = i + 1;
  i =decimal.ToInt32(decimal.Divide(地图起点位置Y, 小地图高));
  k2 = i + 1;
  c1 = 地图起点位置X - i * 小地图长;
  c2 = 地图起点位置Y - i * 小地图高;
  // 获得需要加载到内存的文件的名称,同时在显示区域绘制地图
  Bitmap b = new Bitmap(显示区域长, 显示区域高);
  Graphics g =Graphics.FromImage(b);
  for (i = 0; i < m1; i++)
  {
  for (j = 0; j < m2; j++)
  {
  MapFiles = 小地图文件名 + (k1 + i).ToString().PadLeft(3, '0') + ".jpg";
  g.DrawImage(MapFiles, (i * 小地图长) - c1, (j * 小地图高) – c2, 小地图长, 小地图高); //在内存中,绘制小地图到指定区域
  }
  }
  this.Image = b; //显示到屏幕上
  }
  private int MouseX,MouseY; //鼠标移动距离
  private int picX, picY;//地图移动距离
  private void pic_MouseDown(objectsender, MouseEventArgs e) {
  MouseX= e.X; MouseY = e.Y; //鼠标按住时记下鼠标位置
  }
  private void pic_MouseUp(object sender, MouseEventArgs e) {
  //鼠标释放时,先计算图片被拖动了多少距离,然后重新在显示区域绘制地图
  picX =picX + e.X - MouseX;
  picY =picY + e.Y - MouseY;
  显示地图(picX,picY);
  }
  四、结束语
    现今计算机内存硬件配置越来越高,但是硬件的配置永远也赶不上软件需求的增加,应用系统中内存仍然是一个要重点考虑的设计因素,尤其是要加载大图片的应用系统。本文提出的方法在浙江省电力95598系统、浙江房地产评估系统、杭州契税申报系统中得到广泛应用,并取得了满意的效果。

参考文献
[1] 《图像技术》,韩培友、董桂云著,西北工业大学出版社,2009.12。
[2] 《Morphological Image Analysis Principles andApplications》(Second Edition) 2008, (德)P. Soill著,清华大学出版社,2008.6。
[3] 《空间数据库技术》,李国斌、汤永利著,电子工业出版社,2010.2。
[4] 《网络地理信息系统的方法与实践》,陈能成著,武汉大学出版社,2009.8。
[5] 《面向网络的新一代地理信息系统》,吴信才著,科学出版社,2009。


鲜花

握手

雷人

路过

鸡蛋
上一篇:图像优化---GDI+进行图片处理时要注意的问题

最新评论

    联系我们
  • QQ:3243218172
  • 邮箱:3243218172@qq.com
  • QQ交流群:567648913
    手机扫描二维码