您的位置:首页 > 编程语言 > VB

vb.net中彩色图像数据的快速获取

2011-07-25 09:31 239 查看
一直以来,图像处理都是VB的禁区,主要的原因可能是因为她没有指针,而图像的数据量通常都很大。其实,只要有正确的方法,VB同样可以写出高效而又快速的图像处理程序的。
我并不是学图像处理这方面的。可以说,我的专业和图像毫不占边,但因老板项目的需要,自学了一些图形图像学方面的知识。网络上图像方面大部分的代码都是用VC写的,对于我这个对C系列语言不感冒的人来说实在是太痛苦了,好在关键的算法部分还能够马马乎乎的看懂,这样在学习中也改写了不少代码,这里想共享一些常用的算法供大家研究。
要处理一个图像,首先当然要获得该图像的像素值,常见很多人直接用两个循环中调用GetPixel 来得到数据(最初我也是),这个过程是相当耗时,在处理完毕后又调用SetPixel 来更新图像,而SetPixel呢,要进行坐标系转化、剪裁区域判断、将颜色匹配为设备支持的最接近的,最后还要根据不同的颜色格式寻址、为将颜色写入其所在位进行位运算,速度可想而知了。
在VB6.0,为了快速得到一副图像的数据,通常需要调用API函数GetDIBits,而在调用该函数前要做大量的准备工作(API声明、BITMAPINFO信息设置等),也有点烦躁,但在.net中提供了BitmapData类,再结合Marshal类的Copy方法可以快速地复制图像数据到一维数组中。
因为我的项目中只对彩色图像进行处理,而且不涉及到特效,所以没有考虑到Alpha通道。
以下是图像的读取和保存部分的代码:

' ******************************************************************************************
'
' 函数名 : ReadBitmap
' 功能 : 读取图像数据
' 参数 : Bmp ------ Bitmap 待处理位图
' BmpData ------ Byte 保存图像的数据的数组(引用)
' 作者 : laviewpbt
' 时间 : 2005-5-20 9:45
' 修改者 :
' 修改时间 :
'
' ******************************************************************************************

Public Shared Sub ReadBitmap(ByVal Bmp As Bitmap, ByRef BmpData() As Byte)
Dim Data As BitmapData = Bmp.LockBits(New Rectangle(0, 0, Bmp.Width, Bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb) ' 将Bitmap对象锁定到系统内存中
Dim Stride As Integer = Data.Stride ' 扫描宽度
Dim Scan0 As IntPtr = Data.Scan0 ' 位图中第一个像素数据的地址
Dim Number As Integer = Bmp.Height * Stride - 1 ' 图像数据元素的个数,注意.net中数组下标是从0开始的
ReDim BmpData(Number)
Marshal.Copy(Scan0, BmpData, 0, Number) ‘将内存Scan0后面Number字节的数据拷贝到BmpData中
Bmp.UnlockBits(Data) ' 从系统内存解锁Bitmap
End Sub

' ******************************************************************************************
'
' 函数名 : WriteBitmap
' 功能 : 将数据写入图像
' 参数 : Bmp ------ Bitmap 待处理位图
' BmpData ------ Byte 保存图像的数据的数组
' 作者 : laviewpbt
' 时间 : 2005-5-20 9:49
' 修改者 :
' 修改时间 :
'
' ******************************************************************************************
Public Shared Sub WriteBitmap(ByVal Bmp As Bitmap, ByVal BmpData() As Byte)
Dim Data As BitmapData = Bmp.LockBits(New Rectangle(0, 0, Bmp.Width, Bmp.Height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb) ' ' 将Bitmap对象锁定到系统内存中
Dim stride As Integer = Data.Stride ' 扫描宽度
Dim Scan0 As IntPtr = Data.Scan0 ' 位图中第一个像素数据的地址
Dim Number As Integer = Bmp.Height * stride - 1 ' 图像数据元素的个数
Marshal.Copy(BmpData, 0, Scan0, Number) '将BmpData中的数据拷贝到Scan0后面的Number字节中
Bmp.UnlockBits(Data) ' 从系统内存解锁Bitmap
End Sub
Marshal.Copy方法的使用大大加速了数据的获取,Marshal类还提供了ReadByte,WriteByte之类的方法,但利用这种方的效率也将非常低下。
对于一副1024*768的24位真彩色图像,利用上述函数读取数据所用的时间是0豪秒(呵呵,当然不是了,估计要用QueryPerformanceCounter函数来得到这个值,顺便说下我的机器配置:256MB内存,Pentium 3.0G),也就是说,图像数据获取可以达到毫秒级,这样,我们就可以把大部分设计的精力投入到算法的设计中去。
上面所获取的数据是一维数组,而24真彩色图像用一三维BmpData(width-1,height-1,2)数组来表示是相当便于处理的,但是如何快速的把数据写入到一三维数组中,我还没有发现好办法,Marshal.Copy方法只支持一维数组的数据复制,如果用For循环来做,也是一个很漫长的过程。我曾经试着用CopyMemory ,虽然可以将内存中一段数据拷贝到一多维数组中,但数组中的数据的顺序不符合要求。
不过说明一点,同样的数据计算量,用一维数组要比用多维数据的速度要快些,这是很明显的,所以经过一番思想斗争,我决定还是用一维数组来处理,虽然在计算中有些难以理解计算式的意义。

转载源:/article/2950828.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: