通过前期的教程,大家对于通过像素来处理图像有了一定认识,那么为什么还需要继续学习复杂的内存处理呢?
当然,一切都是为了效率。
这一篇我们就来谈谈图像处理的效率问题。
正如我之前在 图像处理之像素处理的系列教程开头所说的,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 教程 目录
原文链接:https://www.f2er.com/vb/256706.html