【VB开源代码栏目提醒】:网学会员在VB开源代码频道为大家收集整理了“用VB写高效的图像处理程序 - 电子设计“提供大家参考,希望对大家有所帮助!
用
VB写高效的图像处理程序 一、为什么这么慢 二、DIB的结构 三、DIB访问函数 四、实战练习 五、使用DIBSection和模拟指针 一、为什么这么慢 自盘古开天地以来好像夸张了点一直有人抱怨
VB程序速度慢。
特别是图像处理被认为是
VB的禁区。
说起来也是市面上的关于
VB的图像处理的数据都是先讲计算公式再直接用PSet或API函数SetPixel逐点画至少我见过的书都是这样。
效果是办到了但速度慢得离谱对一幅640480的图像进行半透明合并就需要10秒钟而在PhotoShop中只要一设置图层的透明度半透明效果立即呈现。
难怪有人说
VB的闲话。
但这并不表示
VB不能写高速的图像处理程序速度慢是因为没有使用正确的方法。
从
VB5开始能以本机
代码编译成exe文件所以不存在
代码执行速度的问题。
那么是什么拖慢了速度呢就是PSet和SetPixelPSet把浮点形式的坐标转为像素单位再交给SetPixel处理。
而SetPixel呢坐标系转化、剪裁区域判断、将颜色匹配为设备支持的最接近的最后还要根据不同的颜色格式寻址、为将颜色写入其所在位进行位运算。
经过这么多层处理速度不慢才怪。
那么怎样才能提高处理速度呢使用DIB直接对位图所在内存进行操作速度可以大大提高。
现在看看范例程序这只是一个简单的色彩演示程序。
CPU:赛扬333内存C100很老的概念了的SDRAM128MB单位:毫秒 Windows 98 Windows XP 说 明
VB_PSet 1199.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 模拟指针 画的 VCDebug 6.6896 6.6503 VC写的Debug版 VCRelease 3.2736 3.6247 VC写的Release版 从这个表中可看出 1.VC比
VB_DIB、
VB_DIB_Ptr快两倍这是因为SafeArray结构的数组比真正的指针慢但也不是某些人所说的70100倍 2.
VB_DIB_Ptr比
VB_DIB慢一点这是因为模拟指针本来就是靠SafeArray结构的数组而且模拟指针需要对两个数组进行操作所以速度慢一点 3.真正差了70100倍是
VB_PSet和
VB_SetPixel特别是
VB_PSet在Windows98下与
VB_DIB差了145倍。
以上可证速度慢的原因是SetPixel非常低效而并不是
VB的问题。
虽然VC的的确比较快但是我写这篇文章不是为了讨论速度极限否则这篇文章会改名为《如何用汇编写高速的图像处理程序》而是为了告诉大家如何在
VB中写能够实时处理的图像处理程序。
二、DIB的结构 在 Windows 3.0 以前Windows系统用的是DDB设备有关位图。
DDB没有调色板 时至今日BMP的版本号已升至5.0Windows NT 4.0、Windows95 定义了 BMP 4.0Windows 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 bfType0 to 1 As Byte bfSize As Long bfReserved1 As Integer bfReserved2 As Integer bfOffBits As Long End Type 说明 bfType 指示文件的类型必须是“BM” bfSize 指示文件的大小包括BITMAPFILEHEADER bfReserved1 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.0BITMAPINFOHEADER40 BMP4.0BITMAPV4HEADER108 BMP5.0BITMAPV5HEADER124 biWidth 位图的高度单位是像素 biHeight 位图的宽度单位是像素 biPlanes 设备的位平面数。
现在都是1 biBitCount 图像的颜色位数 0当biCompressionBI_JPEG时必须为0BMP 5.0 1单色位图 416色位图 8256色位图 16增强色位图默认为555格式 24真彩色位图 3232位位图默认情况下Windows不会处理最高8位可以将它作为自己的Alpha通道 biCompression 压缩方式 BI_RGB无压缩 BI_RLE8行程编码压缩biBitCount必须等于8 BI_RLE4行程编码压缩biBitCount必须等于4 BI_BITFIELDS指定RGB掩码biBitCount必须等于16、32 BI_JPEGJPEG压缩BMP 5.0 BI_PNGPNG压缩BMP 5.0 biSizeImage 实际的位图数据所占字节biCompressionBI_RGB时可以省略 bibiYPelsPerMeter 目标设备的垂直分辨率单位是每米的像素个数 biClrUsed 使用的颜色数当biBitCount等于1、4、8时才有效。
如果该项为0表示颜色数为2biBitCount 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的倍数字节如果不是则需要补齐。
计算公式LineBytesbiWidthbiBitCount31And ampHFFFFFFE08 由于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 ◆16位色 用16位表示一个像素所以两个字节可以表示1个像素。
默认情况下16位DIB是555格式最高位无效这对
VB是个福音因为
VB没有16位无符号型。
在内存的摆放形式如下PC机是低字节在前 字节 0 1 2 3 ... 位 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 像素 0 1 RGB G B x R G G B x R G RGB位 2 1 0 4 3 2 1 0 0 4 3 2 1 0 4 3 2 1 0 4 3 2 1 0 0 4 3 2 1 0 4 3 ◆24位色 用24位表示一个像素所以三个字节可以表示1个像素。
注意它的顺序是BGR而不是传统的RGB。
在内存的摆放形式如下 字节 0 1 2 3 4 5 ... 像素 0 1 RGB B G R B G R ◆32位色 用32位表示一个像素所以四个字节可以表示1个像素。
注意绝大多数的GDI函数不会处理Alpha通道只有Alp像素 0 1 RGB B G R A B G R A 三、DIB访问函数 SetDIBitsToDevice 原型定义 int SetDIBitsToDevice HDC hDC // handle to device context int XDest // x-coordinate of upper-left corner of dest. rect. int YDest // y-coordinate of upper-left corner of dest. rect. DWORD dwWidth // source rectangle width DWORD dwHeight // source rectangle height int XSrc // x-coordinate of lower-left corner of source rect. int YSrc // y-coordinate of lower-left corner of source rect. UINT uStartScan // first scan line in array UINT cScanLines // number of scan lines CONST VOID lpvBits // address of array with DIB bits CONST BITMAPINFO lpbmi // address of structure with bitmap info. UINT fuColorUse // RGB or palette indexes
VB声明 Declare Function SetDIBitsToDevice Lib quotgdi32.dllquot ByVal hDC As Long ByVal XDest As Long ByVal YDest As Long ByVal dwWidth As Long ByVal dwHeight As Long ByVal XSrc As Long ByVal YSrc As Long ByVal uStartScan As Long ByVal cScanLines As Long lpvBits As Any lpbmi As Any ByVal fuColorUse As Long As Long 说明 将一幅与设备无关位图的全部或部分数据直接复制到一个设备。
这个函数在设备中定义了一个目标矩形以便接收位图数据。
它也在DIB中定义了一个源矩形以便从中提取数据 返回值 如函数执行成功返回欲复制的扫描线的数量如返回常数GDI_ERROR表示出错 参数 hDC 一个设备场景的句柄。
该场景用于接收位图数据 XDest 指定绘制区域的左上角X坐标 YDest 指定绘制区域的左上角Y坐标 dwWidth 指定绘制区域的高度 dwHeight 指定绘制区域的宽度 XSrc 矩形在DIB中的起点X坐标 YSrc 矩形在DIB中的起点Y坐标 uStartScan lpvBits中第一条扫描线的编号。
如lpbmi之BITMAPINFOHEADER部分的biHeight字段是正数那么这条扫描线就会从位图的底部开始计算如果是负数就从顶部开始计算 cScanLines 欲复制的扫描线数量 lpvBits 指向一个缓冲区的指针。
这个缓冲区包含了以DIB格式描述的位图数据这种格式是由lpbmi指定的 lpbmi 指向BITMAPINFO为兼容BMP4/5而声明成Any对DIB的格式和颜色进行描述的一个结构 fuColorUse DIB_PAL_COLORS 颜色表是一个整数数组其中包含了与目前选入hDC设备场景的调色板相关的索引 DIB_RGB_COLORS 颜色表包含了RGB颜色 StretchDIBits 原型定义 int StretchDIBits HDC hDC // handle to device context int XDest // x-coordinate of upper-left corner of dest. rectangle int YDest // y-coordinate of upper-left corner of dest. rectangle int nDestWidth // width of destination rectangle int nDestHeight // height of destination rectangle int XSrc // x-coordinate of upper-left corner of source rectangint YSrc // y-coordinate of upper-left corner of source rectangle int nSrcWidth // width of source rectangle int nSrcHeight // height of source rectangle CONST VOID lpBits // address of bitmap bits CONST BITMAPINFO lpBitsInfo // address of bitmap data UINT iUsage // usage flags DWORD dwRop // raster operation code
VB声明 Declare Function StretchDIBits Lib quotgdi32quot ByVal hDC As Long ByVal XDest As Long ByVal YDest As Long ByVal nDestWidth As Long ByVal nDestHeight As Long ByVal XSrc As Long ByVal YSrc As Long ByVal nSrcWidth As Long ByVal nSrcHeight As Long lpBits As Any lpBitsInfo As Any ByVal wUsage As Long ByVal dwRop As Long As Long 说明 根据一幅与设备无关的位图创建一幅与设备有关的位图 返回值 执行成功返回位图句柄零表示失败 参数 hDC 一个设备场景的句柄该设备场景定义了要创建的与设备有关位图的配置信息 XDest 指定绘制区域的左上角X坐标 YDest 指定绘制区域的左上角Y坐标 nDestWidth 指定绘制区域的高度 nDestHeight 指定绘制区域的宽度 XSrc 矩形在DIB中的起点X坐标 YSrc 矩形在DIB中的起点Y坐标 nSrcWidth 指定原位图绘制区域的左上角X坐标 nSrcHeight 指定原位图绘制区域的左上角Y坐标 lpBits 指向一个缓冲区的指针。
这个缓冲区包含了以DIB格式描述的位图数据这种格式是由lpBitsInfo指定的 lpBitsInfo 指向BITMAPINFO为兼容BMP4/5而声明成Any对DIB的格式和颜色进行描述的一个结构 iUsage DIB_PAL_COLORS 颜色表是一个整数数组其中包含了与目前选入hDC设备场景的调色板相关的索引 DIB_RGB_COLORS 颜色表包含了RGB颜色 dwRop 欲进行的光栅运算 CreateDIBitmap 原型定义 HBITMAP CreateDIBitmap HDC hDC // handle to device context CONST BITMAPINFOHEADER lpbmih // pointer to bitmap size and format data DWORD fdwInit // initialization flag CONST VOID lpbInit // pointer to initialization data CONST BITMAPINFO lpbmi // pointer to bitmap color-format data UINT fuUsage // color-data usage
VB声明 Declare Function CreateDIBitmap Lib quotgdi32quot ByVal hDC As Long lpbmih As Any ByVal fdwInit As Long lpbInit As Any lpbmi As Any ByVal fuUsage As Long As Long 说明 将一幅与设备无关位图的全部或部分数据直接复制到一个设备。
这个函数在设备中定义了一个目标矩形以便接收位图数据。
它也在DIB中定义了一个源矩形以便从中提取数据 返回值 执行成功则返回扫描线的数量零表示失败。
会设置GetLastError 参数 hDC 一个设备场景的句柄。
该场景用于接收位图数据 lpbmih BITMAPINFOHEADER为兼容BMP4/5而声明成Any对DIB的格式进行描述的一个结构 fdwInit 如不应对位图数据进行初始化那么设lpbInit 指向一个缓冲区的指针。
这个缓冲区包含了以DIB格式描述的位图数据这种格式是由lpbmi指定的 lpbmi 指向BITMAPINFO为兼容BMP4/5而声明成Any对DIB的格式和颜色进行描述的一个结构 fuUsage DIB_PAL_COLORS 颜色表是一个整数数组其中包含了与目前选入hDC设备场景的调色板相关的索引 DIB_RGB_COLORS 颜色表包含了RGB颜色 CreateDIBSection 原型定义 HBITMAP CreateDIBSection HDC hDC // handle to device context CONST BITMAPINFO lpbmi // pointer to structure containing bitmap size format and color data UINT iUsage // color data type indicator: RGB values or palette indexes VOID ppvBits // pointer to variable to receive a pointer to the bitmaps bit values HANDLE hSection // optional handle to a file mapping object DWORD dwOffset // offset to the bitmap bit values within the file mapping object
VB声明 Declare Function CreateDIBSection Lib quotgdi32quot ByVal hDC As Long lpbmi As Any ByVal iUsage As Long ByRef ppvBits As Long ByVal hSection As Long ByVal dwOffset As Long As Long 说明 CreateDIBSection能创建一种特殊的DIB称为DIB项DIBSection然后返回一个GDI位图的句柄。
它提供了DIB和GDI位图的最好的特性。
这样我们可以直接访问DIB的内存可以利用位图句柄和内存设备环境我们甚至还可以在DIB中调用GDI函数来绘图 返回值 执行成功返回DIBSection位图的句柄零表示失败。
会设置GetLastError 参数 hDC 一个设备场景的句柄。
如dw设为DIB_PAL_COLORS那么DIB颜色表就会用来自逻辑调色板的颜色进行初始化 lpbmi 指向BITMAPINFO为兼容BMP4/5而声明成Any这个结构初始化成欲创建的那幅位图的配置数据 iUsage DIB_PAL_COLORS 颜色表是一个整数数组其中包含了与目前选入hDC设备场景的调色板相关的索引 DIB_RGB_COLORS 颜色表包含了RGB颜色 ppvBits 用于得到DIBSection数据区的内存地址 hSection 指向一个文件映射对象的可选句柄位图将在其中创建。
如设为零Windows会自动分配内存 dwOffset 如指定了句柄就用这个参数指定位图数据在文件映射对象中的偏移量 GetDIBits 原型定义 int GetDIBits HDC hDC // handle to device context HBITMAP hbmp // handle to bitmap UINT uStartScan // first scan line to set in destination bitmap UINT cScanLines // number of scan lines to copy LPVOID lpvBits // address of array for bitmap bits LPBITMAPINFO lpbmi// address of structure with bitmap data UINT uUsage // RGB or palette index
VB声明 Declare Function GetDIBits Lib quotgdi32quot ByVal hDC As Long ByVal hbmp As Long ByVal uStartScan As Long ByVal cScanLines As Long lpvBits As Any lpbmi As Any说明 该函数利用申请到的内存由GDI位图得到DIB位图数据。
通过该函数可以对DIB的格式进行控制可以制定颜色的位数而且可以指定是否进行压缩。
如果采用了压缩方式则必须调用该函数两次一次为了得到所需内存另外一次为了得到位图数据 返回值 执行成功则返回扫描线的数量零表示失败。
会设置GetLastError 参数 hDC 定义了与设备有关位图hBitmap的配置信息的一个设备场景的句柄 hbmp 源位图的句柄 uStartScan 欲复制到DIB中的第一条扫描线的编号 cScanLines 欲复制的扫描线数量 lpvBits 指向一个缓冲区的指针。
这个缓冲区包含了以DIB格式描述的位图数据这种格式是由lpbmi指定的 lpbmi 指向BITMAPINFO为兼容BMP4/5而声明成Any.对DIB的格式及颜色进行说明的一个结构。
在BITMAPINFOHEADER结构中从biSize到biCompression之间的所有字段都必须初始化 uUsage DIB_PAL_COLORS 颜色表是一个整数数组其中包含了与目前选入hDC设备场景的调色板相关的索引 DIB_RGB_COLORS 颜色表包含了RGB颜色 SetDIBits 原型定义 int SetDIBits HDC hDC // handle to device context HBITMAP hbmp // handle to bitmap UINT uStartScan // starting scan line UINT cScanLines // number of scan lines CONST VOID lpvBits // array of bitmap bits CONST BITMAPINFO lpbmi // address of structure with bitmap data UINT uUsage // type of color indexes to use
VB声明 Declare Function SetDIBits Lib quotgdi32quot ByVal hDC As Long ByVal hbmp As Long ByVal uStartScan As Long ByVal cScanLines As Long lpvBits As Any lpbmi As Any ByVal uUsage As Long As Long 说明 将来自与设备无关位图的二进制位复制到一幅与设备有关的位图里 返回值 执行成功则返回扫描线的数量零表示失败。
会设置GetLastError 参数 hDC 定义了与设备有关位图hBitmap的配置信息的一个设备场景的句柄 hbmp 源位图的句柄 uStartScan 欲复制到DIB中的第一条扫描线的编号 cScanLines 欲复制的扫描线数量 lpvBits 指向一个缓冲区的指针。
这个缓冲区包含了以DIB格式描述的位图数据这种格式是由lpbmi指定的 lpbmi 指向BITMAPINFO为兼容BMP4/5而声明成Any.对DIB的格式及颜色进行说明的一个结构。
在BITMAPINFOHEADER结构中从biSize到biCompression之间的所有字段都必须初始化 uUsage DIB_PAL_COLORS 颜色表是一个整数数组其中包含了与目前选入hDC设备场景的调色板相关的索引 DIB_RGB_COLORS 颜色表包含了RGB颜色 GetDIBColorTable 原型定义 UINT GetDIBColorTable HDC hDC // handle to device context whose DIB is of interest UINT uStartIndex // color table index of first entry to retrieve UINT cEntries RGBQUAD pColors // poi.
上一篇:
苏州大学VB教材
下一篇:
关于大学英语教学