|||
Visual Basic与图像处理(三)
通过动态数组减少Point方法的使用次数,可以有效的提高图像处理的速度,C系列语言之所以在处理图像的时候速度较快,其实很大原因就是因为是从内存中直接读取图像数据。如果能完全放弃使用Point和PSet方法,直接获得图像数据,那么Visual Basic与C系列语言处理图像的速度并无明显差异,一种方法是直接读取文件的方法,对于初学者,还是不建议使用,因此没有必要,如果需要可以直接参考文件读取和写入的方法即可。这里推荐一种通过API函数直接完成图像读写的方法,主要涉及这样几个API函数:
(1) 从PictureBox读入图像数据到数组中,用于取代Point方法。
Declare Function GetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
(2) 将数组数据直接映射到PictureBox中,用于取代PSet方法。
Declare Function SetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
(3) 获得控件句柄
Declare Function GetObject Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
为了便于对图像进行操作,自定义了一个数据类型BIPMAP,定义如下:
Type BITMAP
bmType As Long
bmWidth As Long
bmHeight As Long
bmWidthBytes As Long
bmPlanes As Integer
bmBitsPixel As Integer
bmBits As Long
End Type
上述API函数定义和自定义变量都放置于标准模块之中。
在获取图像数据时,首先定义一个整型变量用于存放PictureBox中的图像句柄,然后调用GetBitmapBits函数获取图像数据,存放于数组中,需要注意的时,Visual Basic获得的数据都默认为彩色图像,因此定义数组大小时,需要按照真彩色图像进行处理。将读取图像按钮代码做调整,使得读入图像的同时就获得图像数据,代码调整如下:
Private Sub cmdReadImage_Click()
Dim strFileName As String
CDialog1.Filter = "bmp|*.bmp|jpg|*.jpg|gif|*.gif" '文件过滤,可以打开上述三类图像
CDialog1.ShowOpen
If CDialog1.FileName <> "" Then
strFileName = CDialog1.FileName
PicSource.Picture = LoadPicture(strFileName)
End If
SourceImHeight = PicSource.Height
SourceImWidth = PicSource.Width
Dim tSBmpInfo As BITMAP
Dim hSrcBmp As Long
Dim x As Integer, y As Integer
hSrcBmp = PicSource.Image.Handle '注意,这里只能使用image,而不能使用picture
'获得位图信息
Call GetObject(hSrcBmp, Len(tSBmpInfo), tSBmpInfo)
ReDim ImageArray(1 To tSBmpInfo.bmWidthBytes, 1 To SourceImHeight) As Byte
'获得源图与目标图二进制位
Call GetBitmapBits(hSrcBmp, tSBmpInfo.bmWidthBytes * tSBmpInfo.bmHeight, ImageArray(1, 1)) '注意起点是(1,1)
ReDim sbits(SourceImHeight - 1, SourceImWidth - 1, 2) As Byte '通过下面的转换,将数组转置为习惯的格式,当然也可以不转置,只是后面使用起来比较麻烦
For y = 1 To SourceImHeight
For x = 1 To SourceImWidth
sbits(y - 1, x - 1, 2) = ImageArray((x - 1) * 4 + 1, y)
sbits(y - 1, x - 1, 1) = ImageArray((x - 1) * 4 + 2, y)
sbits(y - 1, x - 1, 0) = ImageArray((x - 1) * 4 + 3, y)
Next x
Next y
End Sub
在处理程序时,同样定义动态数组用于存储目标图像数据,处理完成后再利用SetBitmapBits一次性将数组显示于目标的PictureBox控件之中,同样以直方图均衡化为例,对应的“直方图均衡化按钮代码调整如下:
Private Sub cmdGrayEqua_Click()
Dim i As Integer, j As Integer
Dim PixelValue As Long
Dim r As Integer, g As Integer, b As Integer
Dim GrayValue As Integer
Dim Hist(255) As Long '存放原直方图统计结果
Dim P(255) As Single '存放原直方图概率
Dim PA(255) As Single '存放原直方图累计分布概率
Dim Map(255) As Single '存放灰度等级映射结果
Dim NGrayValue As Integer
'设置目标图像的高度和宽度
DestImHeight = SourceImHeight
DestImWidth = SourceImWidth
'设置目标PictureBox的大小
PicDest.Height = DestImHeight
PicDest.Width = DestImWidth
ReDim dbits(DestImHeight - 1, DestImWidth - 1, 2) As Byte '重新定义目标数组的维数
'图像的直方图统计
For i = 0 To SourceImHeight - 1
For j = 0 To SourceImWidth - 1
r = sbits(i, j, 0)
g = sbits(i, j, 1)
b = sbits(i, j, 2)
'插入图像处理的过程,对r, g, b进行处理
GrayValue = 0.3 * r + 0.59 * g + 0.11 * b
Hist(GrayValue) = Hist(GrayValue) + 1
Next j
Next i
P(0) = Hist(0) / SourceImHeight / SourceImWidth
Map(0) = 255 * P(0)
For i = 1 To 255
P(i) = P(i - 1) + Hist(i) / SourceImHeight / SourceImWidth
Map(i) = 255 * P(i)
Next i
'图像的直方图均衡化
For i = 0 To SourceImHeight - 1
For j = 0 To SourceImWidth - 1
r = sbits(i, j, 0)
g = sbits(i, j, 1)
b = sbits(i, j, 2)
'插入图像处理的过程,对r, g, b进行处理
GrayValue = 0.3 * r + 0.59 * g + 0.11 * b
dbits(i, j, 0) = Map(GrayValue)
dbits(i, j, 1) = Map(GrayValue)
dbits(i, j, 2) = Map(GrayValue)
Next j
Next i
Dim tDBmpInfo As BITMAP
Dim hDestBmp As Long
hDestBmp = PicDest.Image.Handle
'获得位图信息
Call GetObject(hDestBmp, Len(tDBmpInfo), tDBmpInfo)
ReDim ImageArray(1 To DestImWidth * 4, 1 To DestImHeight) As Byte
For i = 1 To DestImHeight
For j = 1 To DestImWidth
ImageArray((j - 1) * 4 + 1, i) = dbits(i - 1, j - 1, 2)
ImageArray((j - 1) * 4 + 2, i) = dbits(i - 1, j - 1, 1)
ImageArray((j - 1) * 4 + 3, i) = dbits(i - 1, j - 1, 0)
Next j
Next i
'获得源图与目标图二进制位
Call SetBitmapBits(hDestBmp, tDBmpInfo.bmWidthBytes * tDBmpInfo.bmHeight, ImageArray(1, 1))
End Sub
初学者可能觉得本例比较复杂,一下子跳跃的跨度较大,但只要熟悉下来,流程还是基本一致的,后面在做一些实例时,可能感觉更为明显。前面在做点运算时,每次计算只需要使用到一个点,本章开始讲述图像的增强,一般需要同时涉及到多个像素点,这里提出的数组存储数据的方法也便于这样的操作。
通过比对可以发现,采用本例的方法以后,Visual Basic处理图像的速度就跟平时见到的C系列语言处理的图像的速度基本一致,如果想要进一步提高处理速度,就需要研究算法方面的内容,这个就不在这里进行讨论了。
Archiver|手机版|科学网 ( 京ICP备07017567号-12 )
GMT+8, 2024-5-19 00:54
Powered by ScienceNet.cn
Copyright © 2007- 中国科学报社