通过前期的教程,大家对于通过像素来处理图像有了一定认识,那么为什么还需要继续学习复杂的内存处理呢?
当然,一切都是为了效率。
这一篇我们就来谈谈图像处理的效率问题。
正如我之前在 图像处理之像素处理的系列教程开头所说的,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,sourceImg.Width,sourceImg.Height),ImageLockMode.ReadOnly,PixelFormat.Format24bppRgb)
- '定义目标BitmapData,锁定区域是整个图片,只需要写入模式,采用24位RGB
- Dim destData As BitmapData = destImg.LockBits(New Rectangle(0,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,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,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,PixelFormat.Format24bppRgb)
- Dim destData As BitmapData = destImg.LockBits(New Rectangle(0,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,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,pDestArray2,allBytes)
- Dim pos As Integer = 0
- Dim R,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,allBytes)
- Dim pDest As IntPtr = destData.Scan0
- Marshal.Copy(rgbvalues1,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,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,allBytes)
- Marshal.Copy(rgbvalues,allBytes)
- Dim pos As IntPtr = pDest
- Dim R,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,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 教程 目录