前言
在 .NET 中常用的 Halcon 讀取影像的方法,一般會採用下列的方式
var filepath = @"D:\test.png";
var img = new HImage(filepath);
如果影像不是儲存於檔案系統中,而是存在於 byte[] array 中,可以採用下列的方式
// 假設 source 儲存的是一個 w = 10, h = 20 大小的灰階影像
byte[] source = new byte[200];
GCHandle pinSourceArray = GCHandle.Alloc(souce, GCHandleType.Pinned);
IntPtr sourcePtr = pinSourceArray.AddrOfPinnedObject();
var img = new HImage("byte", 10, 20, sourcePtr);
pinSourceArray.Free();
好的,那彩色影像又該如何呢?
Halcon 提供了以下方法建立彩色影像
- HOperatorSet.GenImage3(RGBImage, type, imageWidth, imageHeight, RedPointer, GreenPointer, BluePointer)
- HOperatorSet.GenImageInterleaved(RGBImage, sourcePointer, colorFormat, originalWidth, originalHeight, alignment, type, imageWidth, imageHeight, startRow, startColumn, bitPerChannel, bitshift)
如果是採用 GenImage3 方法,就必須要有 R, G, B 三色的指標。
實驗的資料來源,是先由 Bitmap 讀取 24 bit 的 8 * 8 彩色影像, 取得 source.
byte[] source = new byte[8*8*3];
資料的儲存方式為
Color 24 bit 的儲存方式為
* source[0] = blue
* source[1] = green
* source[2] = red
Color 32 bit 的儲存方式為
* source[0] = blue
* source[1] = green
* source[2] = red
* source[3] = alpha
所以,要作 RGB 的資料分離,再取得各別的指標
RGB 分離實驗 1,陣列給值
有了來源 byte[] source, 要分離出 RGB 3 個 byte[] 有什麼難, 程式碼如下
int imgW = 8; //影像寬
int imgH = 8; //影像高
int size = imgW *imgH;
byte[] redSource = new byte[size];
byte[] greenSource = new byte[size];
byte[] greenSource = new byte[size];
//迴圈給值
for(int index = 0, pos = 0 ; index < source.Length;)
{
redSource[pos] = source[index + 2];
greenSource[pos] = source[index + 1];
blueSource[pos] = source[index + 0];
index+=3;
pos++;
}
很直覺,也沒什麼問題,概念實作完畢後,當然要把資料量弄大一點,所以,新的測試影像為 24bit 的 4000 * 3000 彩色影像。
結果,這個分離程式效率實在是太慢了,平均約花費了 300 ms。所以只能改寫了。
RGB 分離實驗 2,利用指標給值
不多說,馬上用指標改寫
unsafe
{
fixed (byte* sourcePtr = source, redPtr = redSource, greenPtr = greenSource, bluePtr = blueSource)
{
byte* pSource = sourcePtr;
byte* pTRed = redPtr;
byte* pTGreen = greenPtr;
byte* pTBlue = bluePtr;
for (int index = 0; index < size; index++)
{
*pTRed = pSource[2];
*pTGreen = pSource[1];
*pTBlue = pSource[0];
pTRed++;
pTGreen++;
pTBlue++;
pSource += 3;
}
}
}
效率提高了,平均約花費了 100 ms 左右,可是還是慢。
最後,使用 HOperatorSet.GenImageInterleaved 方法,平均約花費 50ms
GCHandle pinSourceArray = GCHandle.Alloc(souce, GCHandleType.Pinned);
IntPtr sourcePtr = pinSourceArray.AddrOfPinnedObject();
HObject imgRGB;
HOperatorSet.GenEmptyObj(out imgRGB);
IntPtr sourcePtr = pinnedArray.AddrOfPinnedObject();
string imgType = "bgr"; //影像資料的儲存方式
HOperatorSet.GenImageInterleaved(out imgRGB, sourcePtr, imgType, width, height
, 0, "byte", width, height, 0, 0, -1, 0);
sourcePtr.Free();
結論
實驗 1 速度為 300 ms, 實驗 2 採用指標,速度為 100 ms, Halcon 的 GenImageInterLeaved 方法為 50 ms.
它是怎麼辦到的,是否用了平行處理的技術,還是其它? 不可知。 下次將考慮使用 Parallel 的方法試試看。
Note
- 有關 GenImageInterleaved 方法的詳細資訊,參考 [1]
- 影像處理的速度可以有多快,參考 [2]
- .NET 並行處理, 參考 [3], [4]
- 指標操作,參考 [5] 的系列文章
其它有關於 GCHandle 一樣搜尋 MSDN 就可以找到相關的說明
參考資料 ( References )
[2] C# 影像處理的速度極限
沒有留言:
張貼留言