用VB写高效的图像处理程序[1]

[入库:2005年8月18日] [更新:2007年3月24日]

本文简介:选择自 zyl910 的 blog


一、为什么这么慢?

  自盘古开天地以来(好像夸张了点),一直有人抱怨vb程序速度慢。特别是图像处理,被认为是vb的禁区。说起来也是,市面上的关于vb的图像处理的数据都是先讲计算公式,再直接用pset(或api函数setpixel)逐点画(至少我见过的书都是这样)。效果是办到了,但速度慢得离谱:对一幅640*480的图像进行半透明合并就需要10秒钟;而在photoshop中,只要一设置图层的透明度,半透明效果立即呈现。难怪有人说vb的闲话。

  但这并不表示vb不能写高速的图像处理程序,速度慢是因为没有使用正确的方法。

  从vb5开始,能以本机代码编译成exe文件,所以不存在代码执行速度的问题。那么,是什么拖慢了速度呢?就是pset和setpixel!pset把浮点形式的坐标转为像素单位,再交给setpixel处理。而setpixel呢,坐标系转化、剪裁区域判断、将颜色匹配为设备支持的最接近的,最后还要根据不同的颜色格式寻址、为将颜色写入其所在位进行位运算。经过这么多层处理,速度不慢才怪。

  那么,怎样才能提高处理速度呢?使用dib,直接对位图所在内存进行操作,速度可以大大提高。现在看看范例程序,这只是一个简单的色彩演示程序。

cpu:赛扬333;内存:pc100(很老的概念了)的sdram,128mb;单位:毫秒
windows 98 windows xp 说 明
vb_pset 1,199.4553 786.1885 在vb使用 pset 画的
vb_setpixel 872.3621 451.3712 在vb使用 setpixelv 画的
vb_dib 8.2218 8.2226 在vb使用 dib 画的
vb_dib_ptr 9.6783 9.4420 在vb使用 dibsection + 模拟指针 画的
vc(debug) 6.6896 6.6503 vc写的(debug版)
vc(release) 3.2736 3.6247 vc写的(release版)
  从这个表中可看出:
  1.vc比vb_dib、vb_dib_ptr快两倍,这是因为safearray结构的数组比真正的指针慢,但也不是某些人所说的70~100倍;
  2.vb_dib_ptr比vb_dib慢一点,这是因为模拟指针本来就是靠safearray结构的数组,而且模拟指针需要对两个数组进行操作,所以速度慢一点;
  3.真正差了70~100倍是vb_pset和vb_setpixel,特别是vb_pset在windows98下与vb_dib差了145倍。

  以上可证,速度慢的原因是setpixel非常低效,而并不是vb的问题。虽然vc的的确比较快,但是我写这篇文章不是为了讨论速度极限(否则这篇文章会改名为《如何用汇编写高速的图像处理程序》),而是为了告诉大家如何在vb中写能够实时处理的图像处理程序。


二、dib的结构

  在 windows 3.0 以前,windows系统用的是ddb(设备有关位图)。ddb没有调色板,显示的颜色依赖硬件,处理色彩很不方便。所以 microsoft 在 windows 3.0中 重新定义了bmp文件格式(bmp 3.0),使其支持设备无关位图——也就是dib。

  时至今日,bmp的版本号已升至5.0(windows nt 4.0、windows95 定义了 bmp 4.0,windows 98、windows 2000 定义了 bmp 5.0),但基本结构没有变——仍是 bmp文件头 和 dib 组成:

bmp文件 bitmapfileheader bmp文件头
dib bitmapinfoheader 位图信息头 bitmapinfo
rgbquad[] 调色板
位图数据

#代表可以不填(=0)的项目)
bmp文件头——bitmapfileheader
原型定义:
typedef struct tagbitmapfileheader { // bmfh
    word    bftype;
    dword   bfsize;
    word    bfreserved1;
    word    bfreserved2;
    dword   bfoffbits;
} bitmapfileheader;
vb声明:
type bitmapfileheader
    bftype(0 to 1) as byte
    bfsize as long
    bfreserved1 as integer
    bfreserved2 as integer
    bfoffbits as long
end type
说明:
bftype 指示文件的类型,必须是“bm”
bfsize# 指示文件的大小,包括bitmapfileheader
bfreserved1 保留,=0
bfreserved2 保留,=0
bfoffbits# 从文件头到位图数据的偏移字节数

文件信息头——bitmapinfoheader
原型定义:
typedef struct tagbitmapinfoheader{ // bmih
    dword  bisize;
    long   biwidth;
    long   biheight;
    word   biplanes;
    word   bibitcount;
    dword  bicompression;
    dword  bisizeimage;
    long   bixpelspermeter;
    long   biypelspermeter;
    dword  biclrused;
    dword  biclrimportant;
} bitmapinfoheader;
vb声明:
type bitmapinfoheader
    bisize as long
    biwidth as long
    biheight as long
    biplanes as integer
    bibitcount as integer
    bicompression as long
    bisizeimage as long
    bixpelspermeter as long
    biypelspermeter as long
    biclrused as long
    biclrimportant as long
end type
说明:
bisize bitmapinfoheader结构的大小。bmp有多个版本,就靠bisize来区别:
  bmp3.0:bitmapinfoheader(=40)
  bmp4.0:bitmapv4header(=108)
  bmp5.0:bitmapv5header(=124)
biwidth 位图的高度,单位是像素
biheight 位图的宽度,单位是像素
biplanes 设备的位平面数。现在都是1
bibitcount 图像的颜色位数
   0:当bicompression=bi_jpeg时必须为0(bmp 5.0)
   1:单色位图
   4:16色位图
   8:256色位图
  16:增强色位图,默认为555格式
  24:真彩色位图
  32:32位位图,默认情况下windows不会处理最高8位,可以将它作为自己的alpha通道
bicompression 压缩方式
  bi_rgb:无压缩
  bi_rle8:行程编码压缩,bibitcount必须等于8
  bi_rle4:行程编码压缩,bibitcount必须等于4
  bi_bitfields:指定rgb掩码,bibitcount必须等于16、32
  bi_jpeg:jpeg压缩(bmp 5.0)
  bi_png:png压缩(bmp 5.0)
bisizeimage# 实际的位图数据所占字节(bicompression=bi_rgb时可以省略)
bixpelspermeter# 目标设备的水平分辨率,单位是每米的像素个数
biypelspermeter# 目标设备的垂直分辨率,单位是每米的像素个数
biclrused# 使用的颜色数(当bibitcount等于1、4、8时才有效)。如果该项为0,表示颜色数为2^bibitcount
biclrimportant# 重要的颜色数。如果该项为0,表示所有颜色都是重要的

调色板
  只有bibitcount等于1、4、8时才有调色板。调色板实际上是一个数组,元素的个数由bibitcount和biclrused决定。
原型定义:
typedef struct tagrgbquad { // rgbq
    byte    rgbblue;
    byte    rgbgreen;
    byte    rgbred;
    byte    rgbreserved;
} rgbquad;
vb声明:
private type rgbquad
    rgbblue as byte
    rgbgreen as byte
    rgbred as byte
    rgbreserved as byte
end type
说明:
rgbblue 蓝色分量
rgbgreen 绿色分量
rgbred 红色分量
rgbreserved# 保留,=0

位图数据
扫描行:
  一行的图像数据叫做一个扫描行。一个扫描行的长度必须是4的倍数(字节),如果不是,则需要补齐。计算公式:linebytes=((biwidth*bibitcount+31)and &hffffffe0)\8
  由于bmp设定者认为数学坐标系更总要,所以dib的扫描行是逆序存储的(相对于屏幕坐标系而言),即屏幕上的第一行是dib位图数据的最后一行。
1位色:
  用1位表示一个像素,所以一个字节可以表示8个像素。坐标是从最左边(最高位)开始的,而不是一般情况下的最低位。在内存的摆放形式如下:
字节 0 ...
7 6 5 4 3 2 1 0
像素 0 1 2 3 4 5 6 7
4位色:
  用4位表示一个像素,所以一个字节可以表示2个像素。坐标是从最左边(最高位)开始的,而不是一般情况下的最低位。在内存的摆放形式如下:
字节 0 ...
7 6 5 4 3 2 1 0
像素 0 1
像素位 3 2 1 0 3 2 1 0
8位色:
  用8位表示一个像素,所以一个字节刚好只能表示一个像素。在内存的摆放形式如下:
字节 0 1 ...
像素 0 1

本文关键:图像处理,高效,VB,DIB,DIBSection,BMP,模拟指针
 

本站最佳浏览方式为 分辨率 1024x768 IE 6.0(或更高版本的 IE浏览器)

go top