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

来源:互联网 发布:isis 剿灭 知乎 编辑:程序博客网 时间:2024/04/28 09:06

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

    一直以来,图像处理都是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 ,虽然可以将内存中一段数据拷贝到一多维数组中,但数组中的数据的顺序不符合要求。

       不过说明一点,同样的数据计算量,用一维数组要比用多维数据的速度要快些,这是很明显的,所以经过一番思想斗争,我决定还是用一维数组来处理,虽然在计算中有些难以理解计算式的意义。


0 0