窗体中有三个按钮一个图片框,图片框中请在设计的时候加载一副图像及设置相关参数。窗体代码:Option Explicit
Private m_Width         As Long             '打开的图像的宽度
Private m_Height        As Long             '打开的图像的高度Private Sub Form_Load()
    m_Width = Pic.ScaleWidth
    m_Height = Pic.ScaleHeight
End SubPrivate Sub CmdOpen_Click()
    CommonDialog.FileName = ""
    CommonDialog.Filter = "All Suppported Images |*.bmp;*.jpg;*.gif;|BMP Images|*.bmp|JPG Images|*.jpg|Gif Images|*.gif"
    CommonDialog.ShowOpen
    If CommonDialog.FileName <> "" Then
        Pic.Picture = LoadPicture(CommonDialog.FileName)
        m_Width = Pic.ScaleWidth
        m_Height = Pic.ScaleHeight
    End If
End Sub
Private Sub CmdDib_Click()
    Dim T               As Long
    
    Dim PicData()           As RGBQUAD
    Dim i                   As Long, j                      As Long    Dim HistRed(255)        As Long, HistGreen(255)         As Long
    Dim HistBlue(255)       As Long
    Dim DiffRed             As Long, DiffGreen              As Long
    Dim DiffBlue            As Long, Diff                   As Long
    Dim SpeedRed(255)       As Byte, SpeedGreen(255)        As Byte
    Dim SpeedBlue(255)      As Byte, Speed(255)             As Byte
    Dim Sum                 As Long, Integral               As Long
    Dim Min                 As Long, Max                    As Long
    Dim NewMin              As Long, NewMax                 As Long
    T = GetTickCount
    GetPicData Pic, PicData
    
    
    For i = 0 To m_Width - 1
        For j = 0 To m_Height - 1
            HistRed(PicData(i, j).Red) = HistRed(PicData(i, j).Red) + 1
            HistGreen(PicData(i, j).Green) = HistGreen(PicData(i, j).Green) + 1
            HistBlue(PicData(i, j).Blue) = HistBlue(PicData(i, j).Blue) + 1
        Next
    Next
   
    For i = 0 To 255
        If HistRed(i) <> 0 Then
            Min = i
            Exit For
        End If
    Next
    For i = 255 To 0 Step -1
        If HistRed(i) <> 0 Then
            Max = i
            Exit For
        End If
    Next
    
    Sum = 0
    For i = Min To Max
        Sum = Sum + HistRed(i)
    Next
    
    Integral = 0
    For i = Min To Max
        Integral = Integral + HistRed(i)
        If Integral >= Sum * 0.005 Then
            NewMin = i
            Exit For
        End If
    Next
    For i = NewMin + 1 To Max
        Integral = Integral + HistRed(i)
        If Integral > Sum * 0.995 Then
            NewMax = i
            Exit For
        End If
    Next
    
    For i = 0 To 255
        If i <= NewMin Then
            SpeedRed(i) = 0
        ElseIf i >= NewMax Then
            SpeedRed(i) = 255
        Else
            SpeedRed(i) = (i - NewMin) / (NewMax - NewMin) * 255
        End If
    Next
''''''''''''''''''''''''''''
  For i = 0 To 255
        If HistGreen(i) <> 0 Then
            Min = i
            Exit For
        End If
    Next
    For i = 255 To 0 Step -1
        If HistGreen(i) <> 0 Then
            Max = i
            Exit For
        End If
    Next
    
    Sum = 0
    For i = Min To Max
        Sum = Sum + HistGreen(i)
    Next
    
    Integral = 0
    For i = Min To Max
        Integral = Integral + HistGreen(i)
        If Integral >= Sum * 0.005 Then
            NewMin = i
            Exit For
        End If
    Next
    
    For i = NewMin + 1 To Max
        Integral = Integral + HistGreen(i)
        If Integral > Sum * 0.995 Then
            NewMax = i
            Exit For
        End If
    Next    For i = 0 To 255
        If i <= NewMin Then
            SpeedGreen(i) = 0
        ElseIf i > NewMax Then
            SpeedGreen(i) = 255
        Else
            SpeedGreen(i) = (i - NewMin) / (NewMax - NewMin) * 255
        End If
    Next
'''''''''''''''''''''''''    For i = 0 To 255
        If HistBlue(i) <> 0 Then
            Min = i
            Exit For
        End If
    Next
    For i = 255 To 0 Step -1
        If HistBlue(i) <> 0 Then
            Max = i
            Exit For
        End If
    Next
    
    Sum = 0
    For i = Min To Max
        Sum = Sum + HistBlue(i)
    Next
    
    Integral = 0
    For i = Min To Max
        Integral = Integral + HistBlue(i)
        If Integral >= Sum * 0.005 Then
            NewMin = i
            Exit For
        End If
    Next
    
    For i = NewMin + 1 To Max
        Integral = Integral + HistBlue(i)
        If Integral > Sum * 0.995 Then
            NewMax = i
            Exit For
        End If
    Next    For i = 0 To 255
        If i <= NewMin Then
            SpeedBlue(i) = 0
        ElseIf i > NewMax Then
            SpeedBlue(i) = 255
        Else
            SpeedBlue(i) = (i - NewMin) / (NewMax - NewMin) * 255
        End If
    Next    For i = 0 To m_Width - 1
        For j = 0 To m_Height - 1
            PicData(i, j).Red = SpeedRed(PicData(i, j).Red)
            PicData(i, j).Green = SpeedGreen(PicData(i, j).Green)
            PicData(i, j).Blue = SpeedBlue(PicData(i, j).Blue)
        Next
    Next
    SetPicData Pic, PicData
    Me.Caption = "DIB方法用时" & GetTickCount - T & "毫秒"
End Sub    好了,任务完成了,编译测试一下,勾选上所有的高级优化选项,测试图片大小选为1024*768,结果显示需要300ms,啊,如此慢,PS中一点就出来了效果呢,仔细分析下代码结构,似乎能够优化的地方已经基本优化了,那问题主要是那里呢。
    其实,在这里耗时的几个主要过程有,读取图像数据、计算直方图、计算新的图像数据、显示图像数据,其中又以中间两个过程为主。我们采用了二维结构体数组,众所周知,访问数组需要计算数组元素在内存中位置,而维数越高,计算地址的公式就越复杂,因此,如果能采用一维数组的方式理论上是要比二维的速度有所改进的,这部分测试可以用读者自己完成。
这里要说的是另外一种提速的方法,模拟指针。其实这个词有很多人应该见过很多次了。虽然VB不直接支持指针的操作,但是借助于安全数据的相关特性,我们可以实现类似于C的指针(包括功能和代码的编辑方式).那么这里我们用模拟指针的好处很明显。第一:我们不需要调用GetDIBits这个函数,这意味着两种节省,其一是空间上的,GetDIBits函数需要你为他事先分配好一定的内存空间来保存图像数据。但是实际上,图像已经被我们加载入picturebox中,那么在内存中他肯定已经占用了空间,我们可以利用GetGDIObject这个函数配以适当的参数得到这个内存空间的首地址。其二是时间上的,分配空间和填充数据都是耗时的,虽然这个时间很少。第二,可以减少寻址的时间消耗, 用模拟指针的过程也需要寻址。但是适当的利用中间变量保存相关地址,可以节省大量的计算时间,比如你用二维结构体保存图象数据,要得到图象在(i,j)点的红色和兰色和绿色数据,则要调用Data(i,j).Red和Data(i,j).Blue、Data(i,j).Green,这里三次调用则三次寻址,每次寻址的过程类似于下面的公式 j*width+i+Offset,一次乘法,二次加法,如果我们自己寻址,则用临时变量保存j*width+i值,则会减少计算量。对于大循环则更是明显。好了说了这么多,下面给出代码。