窗体中有三个按钮一个图片框,图片框中请在设计的时候加载一副图像及设置相关参数。窗体代码: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值,则会减少计算量。对于大循环则更是明显。好了说了这么多,下面给出代码。
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值,则会减少计算量。对于大循环则更是明显。好了说了这么多,下面给出代码。
不过支持你竞争VB版主。