版权声明:本文为博主原创文章,转载请在显著位置标明本文出处以及作者网名,未经作者允许不得用于商业目的。
通过前期的教程,大家对于通过像素来处理图像有了一定认识,那么为什么还需要继续学习复杂的内存处理呢?
当然,一切都是为了效率。
这一篇我们就来谈谈图像处理的效率问题。
正如我之前在 图像处理之像素处理 的系列教程开头所说的,vb相对于vc对于处理图像之类都处于劣势,vc可以使用指针来处理内存,vb不行。
到了.net框架下,c#也可以使用指针,vb.net我试了下,还是可以的,但是使用指针读写的效率却比用一维数组还要略低,更比不上c#,当然造成这个的原因我还不太清楚。
但是既然同是在vb.net下处理图像,那么我们还是需要尽可能地使用高效率的方法。下面我就几种处理图像的方法做个对比,当然这几种方法的名称是我自己想出来的。
使用以下代码之前,需要引用
Imports System.Drawing.Imaging
Imports System.Runtime.InteropServices
一维数组处理代码(同 vb.net 教程 5-14 图像处理之内存处理基础4):
'一维数组处理代码
'http://blog.csdn.net/uruseibest
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
Dim timeStart, timeEnd As DateTime
Dim timeDiff As TimeSpan
timeStart = Now()
'定义目标图片
Dim destImg As New Bitmap(sourceImg.Width, sourceImg.Height)
'定义源BitmapData,锁定区域是整个图片,只需要读取模式,采用24位RGB
Dim sourceData As BitmapData = sourceImg.LockBits(New Rectangle(0, 0, sourceImg.Width, sourceImg.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb)
'定义目标BitmapData,锁定区域是整个图片,只需要写入模式,采用24位RGB
Dim destData As BitmapData = destImg.LockBits(New Rectangle(0, 0, sourceImg.Width, sourceImg.Height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb)
'获得源BitmapData的起始指针位置
Dim pSource As IntPtr = sourceData.Scan0
'获得源BitmapData占用内存空间的总的字节数
Dim allBytes As Integer = sourceData.Stride * sourceData.Height
'定义数组,用来放置源BitmapData的数据
Dim rgbvalues() As Byte
ReDim rgbvalues(allBytes - 1)
'把指针位置开始allBytes个字节数据拷贝到rgbvalues()数组中
Marshal.Copy(pSource, rgbvalues, 0, allBytes)
'数组中第一个字节的序号
Dim pos As Integer = 0
Dim R, G, B As Integer
Dim avgValue As Integer
'先高度,后宽度
For j As Integer = 0 To sourceData.Height - 1
For i As Integer = 0 To sourceData.Width - 1
'图片上(i,j)像素对应的蓝色分量值
B = rgbvalues(pos)
'图片上(i,j)像素对应的蓝色分量值
G = rgbvalues(pos + 1)
'图片上(i,j)像素对应的蓝色分量值
R = rgbvalues(pos + 2)
'这里使用的是均值法
avgValue = (B + G + R) / 3
'把求出的数据写回去
rgbvalues(pos) = avgValue
rgbvalues(pos + 1) = avgValue
rgbvalues(pos + 2) = avgValue
'终归是在一维数组里面取数据,向前推进3个字节
pos = pos + 3
Next
'一行数据取完了,继续推进到下一行
pos = pos + sourceData.Stride - sourceData.Width * 3
Next
'获得目标BitmapData的起始指针位置
Dim pDest As IntPtr = destData.Scan0
'将数组的内容拷到pDest指针开始的内存
Marshal.Copy(rgbvalues, 0, pDest, allBytes)
'不要忘了解锁
sourceImg.UnlockBits(sourceData)
destImg.UnlockBits(destData)
picDest.Image = destImg
timeEnd = Now
timeDiff = timeEnd - timeStart
ListBox1.Items.Add("一维数组:" & timeDiff.TotalMilliseconds)
End Sub
二维数组处理代码:
'二维数组处理代码
'http://blog.csdn.net/uruseibest
Private Sub Button7_Click(sender As Object, e As EventArgs) Handles Button7.Click
Dim timeStart, timeEnd As DateTime
Dim timeDiff As TimeSpan
timeStart = Now()
Dim destImg As New Bitmap(sourceImg.Width, sourceImg.Height)
Dim sourceData As BitmapData = sourceImg.LockBits(New Rectangle(0, 0, sourceImg.Width, sourceImg.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb)
Dim destData As BitmapData = destImg.LockBits(New Rectangle(0, 0, sourceImg.Width, sourceImg.Height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb)
Dim pSource As IntPtr = sourceData.Scan0
Dim allBytes As Integer = sourceData.Stride * sourceData.Height
Dim rgbvalues1() As Byte
ReDim rgbvalues1(allBytes - 1)
Marshal.Copy(pSource, rgbvalues1, 0, allBytes)
Dim rgbvalues2(,) As Byte
ReDim rgbvalues2(destData.Height - 1, destData.Stride - 1)
Dim pDestArray2 As IntPtr
pDestArray2 = Marshal.UnsafeAddrOfPinnedArrayElement(rgbvalues2, 0)
Marshal.Copy(rgbvalues1, 0, pDestArray2, allBytes)
Dim pos As Integer = 0
Dim R, G, B As Integer
Dim avgValue As Integer
For j As Integer = 0 To sourceData.Height - 1
For i As Integer = 0 To sourceData.Width - 1
B = rgbvalues2(j, i * 3)
G = rgbvalues2(j, i * 3 + 1)
R = rgbvalues2(j, i * 3 + 2)
avgValue = (B + G + R) / 3
rgbvalues2(j, i * 3) = avgValue
rgbvalues2(j, i * 3 + 1) = avgValue
rgbvalues2(j, i * 3 + 2) = avgValue
Next
Next
Marshal.Copy(pDestArray2, rgbvalues1, 0, allBytes)
Dim pDest As IntPtr = destData.Scan0
Marshal.Copy(rgbvalues1, 0, pDest, allBytes)
sourceImg.UnlockBits(sourceData)
destImg.UnlockBits(destData)
picDest.Image = destImg
timeEnd = Now
timeDiff = timeEnd - timeStart
ListBox1.Items.Add("二维数组:" & timeDiff.TotalMilliseconds)
End Sub
非常之遗憾,我没有在.net中找到一维数组直接拷贝到二维数组的方法,我也没有尝试使用copymemory,有兴趣的朋友可以自己试一下。
内存指针处理代码:
需要说明的是,.net2.0下面没有提供指针加减方法,需要引用.net 4.0 以上版本目标框架,直接在项目属性中调整后自动重启动项目即可。
'内存指针处理代码
'http://blog.csdn.net/uruseibest
Private Sub Button5_Click(sender As Object, e As EventArgs) Handles Button5.Click
Dim timeStart, timeEnd As DateTime
Dim timeDiff As TimeSpan
timeStart = Now()
Dim destImg As New Bitmap(sourceImg.Width, sourceImg.Height)
Dim sourceData As BitmapData = sourceImg.LockBits(New Rectangle(0, 0, sourceImg.Width, sourceImg.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb)
Dim destData As BitmapData = destImg.LockBits(New Rectangle(0, 0, sourceImg.Width, sourceImg.Height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb)
Dim allBytes As Integer = sourceData.Stride * sourceData.Height
Dim rgbvalues() As Byte
ReDim rgbvalues(allBytes - 1)
Dim pSource As IntPtr = sourceData.Scan0
Dim pDest As IntPtr = destData.Scan0
Marshal.Copy(pSource, rgbvalues, 0, allBytes)
Marshal.Copy(rgbvalues, 0, pDest, allBytes)
Dim pos As IntPtr = pDest
Dim R, G, B As Integer
Dim avgValue As Byte
For j As Integer = 0 To sourceData.Height - 1
For i As Integer = 0 To sourceData.Width - 1
B = Marshal.ReadByte(pos)
G = Marshal.ReadByte(pos + 1)
R = Marshal.ReadByte(pos + 2)
avgValue = (B + G + R) / 3
Marshal.WriteByte(pos, avgValue)
Marshal.WriteByte(pos + 1, avgValue)
Marshal.WriteByte(pos + 2, avgValue)
pos = pos + 3
Next
pos = pos + sourceData.Stride - sourceData.Width * 3
Next
sourceImg.UnlockBits(sourceData)
destImg.UnlockBits(destData)
picDest.Image = destImg
timeEnd = Now
timeDiff = timeEnd - timeStart
ListBox1.Items.Add("指针处理:" & timeDiff.TotalMilliseconds)
End Sub
内存指针处理代码中,采用了Marshal.ReadByte()和Marshal.WriteByte()直接读写内存,不过效率似乎和数组差不多。
像素处理代码:
'像素处理代码
'http://blog.csdn.net/uruseibest
Private Sub Button8_Click(sender As Object, e As EventArgs) Handles Button8.Click
Dim pSourceColor As Color
Dim pDestColor As Color
Dim timeStart, timeEnd As DateTime
Dim timeDiff As TimeSpan
timeStart = Now
Dim destImg As New Bitmap(sourceImg.Width, sourceImg.Height)
Dim R, G, B As Integer
Dim gray As Integer
For i As Integer = 0 To sourceImg.Width - 1
For j As Integer = 0 To sourceImg.Height - 1
pSourceColor = sourceImg.GetPixel(i, j)
R = pSourceColor.R
G = pSourceColor.G
B = pSourceColor.B
gray = (R + G + B) / 3
pDestColor = Color.FromArgb(gray, gray, gray)
destImg.SetPixel(i, j, pDestColor)
Next
Next
picDest.Image = destImg
timeEnd = Now
timeDiff = timeEnd - timeStart
ListBox1.Items.Add("像素处理:" & timeDiff.TotalMilliseconds)
End Sub
由于.net平台下C#和vb.NET很相似,本文也可以为C#爱好者提供参考。
学习更多vb.net知识,请参看vb.net教程目录
————————————————
版权声明:本文为CSDN博主「VB.Net」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。