早期的時候我使用的開發(fā)工具是VB6,VB6做圖像處理的速度在我的軟件Imageshop中有所體現(xiàn),還是算可以的。目前,我已經(jīng)改用C#來研究圖像算法,C#中有指針,做圖像處理起來效率確實要高不少。今天就我掌握的情況,在對VB.NET的圖像處理做一個簡單的描述。
首先,還是談?wù)剤D像像素時數(shù)據(jù)獲取方面吧,.net中的圖像相關(guān)類基本上都是基于GDI+的,因此,圖像數(shù)據(jù)的獲取其實也是調(diào)用GDI+的一些函數(shù)。這個函數(shù)就是LockBits,在vb.net中彩色圖像數(shù)據(jù)的快速獲取 一文中,我們是調(diào)用了Marshal.Copy把LockBits鎖定的內(nèi)存數(shù)據(jù)拷貝到數(shù)據(jù)中,然后對數(shù)組中的值進行處理。這樣做主要的原因是VB.NET不好直接訪問內(nèi)存(Marshal.ReadByte之類的函數(shù)不適合用于大型的循環(huán)中)。
那么,這就造成了2個不好的事情,第一:在同一時間需要2倍于圖像數(shù)據(jù)量的內(nèi)存,第二:內(nèi)存數(shù)據(jù)拷貝到數(shù)據(jù),以及處理后再把數(shù)組的數(shù)據(jù)拷貝會內(nèi)存中都是會減低速度的。作為一種改進,我們應(yīng)該充分利用LockBits的功能。LockBits中的LockMode中有一種模式為ImageLockMode.UserInputBuffer,該模式下需要用戶先申請內(nèi)存,然后在把圖像數(shù)據(jù)按照相關(guān)格式填充如這個內(nèi)存中。這樣,就可以先定義個數(shù)組,然后把圖像數(shù)據(jù)填充到這個數(shù)組中,就避免了來回拷貝的耗時了,簡單示例代碼如下:
Dim BmpData As New BitmapData
Stride = ((Bmp.Width * 3 + 3) And &HFFFFFFFC)
Dim PixleValue(Stride * Bmp.Height) As Byte
Dim Hanlde As GCHandle = GCHandle.Alloc(PixleValue, GCHandleType.Pinned)
BmpData.Scan0 = Hanlde.AddrOfPinnedObject() '取得字節(jié)數(shù)組的的第一個元素在內(nèi)存中的地址,VB.NET沒有了VB6.0的VarPtr函數(shù)了
BmpData.Stride = Stride 'Stide這一個字段也必須實現(xiàn)填充,這個需要按照像素格式來計算大小,必須為4的倍數(shù)
Bmp.LockBits(New Rectangle(0, 0, Bmp.Width, Bmp.Height), ImageLockMode.ReadWrite Or ImageLockMode.UserInputBuffer, PixelFormat.Format24bppRgb, BmpData)
Hanlde.Free()
這種調(diào)用模式下,BitmapData對象的Scan0和Stride必須由用戶自行計算,其中Scan0為保存解碼后的數(shù)據(jù)內(nèi)存的地址。在VB.NET中獲取數(shù)組內(nèi)存地址的代碼似乎比VB6復(fù)雜一些,這一點我也不是特別在行。
調(diào)用上述代碼后,PixleValue就已經(jīng)保存了圖像的數(shù)據(jù)了。之后就是對圖像數(shù)據(jù)進行各種各樣的處理了。比如我們那前一段日子共享的色調(diào)均化的代碼為例:
For Y = 0 To Height - 1
Speed = Y * Stride ' 定位到每個掃描行的第一個像素,以避免溶于數(shù)據(jù)的影響
For X = 0 To Width - 1
HistGram(PixleValue(Speed)) += 1 ' Blue
HistGram(PixleValue(Speed + 1)) += 1 ' Green
HistGram(PixleValue(Speed + 2)) += 1 ' Red
Speed += 3 ' 移向下一個像素
Next
Next
Num = 0
For Y = 0 To 255
Num = Num + HistGram(Y) ' 計算映射表
Lut(Y) = CByte(Math.Truncate(CSng(Num) / (Width * Height * 3) * 255))
Next
For Y = 0 To Height - 1
Speed = Y * Stride
For X = 0 To Width - 1
PixleValue(Speed) = Lut(PixleValue(Speed))
PixleValue(Speed + 1) = Lut(PixleValue(Speed + 1))
PixleValue(Speed + 2) = Lut(PixleValue(Speed + 2))
Speed += 3
Next
Next
執(zhí)行速度比較:針對上述算法,我們只比較算法的執(zhí)行部分的耗時。
測試語言 測試圖像(512*384)耗時 測試圖像(1024*768)耗時 測試圖像(4000*3000)耗時
VB.NET 7ms 25ms 178ms
c# 指針 4ms 16ms 100ms
c# 數(shù)組 5ms 24ms 139ms
上表中可以明顯看出指針在速度上還是有明顯的優(yōu)勢的,唯一值得注意的是,VB.NET的數(shù)組版要比C#的數(shù)組版的速度要慢,由于VB.NET中我不知道怎么樣查看其對應(yīng)的反匯編碼,所以我還不清楚這是為什么。
上述三種方案的代碼下載:http://files.cnblogs.com/Imageshop/HistgramEqualize%28VB.NETandCsharp%29.rar
看來VB.NET確實不是圖像處理方案的首選工具啊。
作者: laviewpbt 時間: 2013.4.07 聯(lián)系QQ: 33184777 轉(zhuǎn)載請保留本行信息