http://blog.csdn.net/halfwet/article/details/7052897
在實際應用中,經常遇到用OpenCV等C++平台的庫來采集圖像,然後傳遞到C#中進行繪制的情況。這時,從C++向C#中傳遞圖像(數組)就成了一個重要的問題。
這裡記錄實驗過的三種方法。
1. 先前一直采用逐像素拷貝的方法:
C++中定義采集圖像函數:
extern "C" __declspec(dllexport) bool __stdcall GetBGRMap(BYTE *bgrMap)
{
bool result = capture->retrieve( bgrImage, CV_CAP_OPENNI_BGR_IMAGE ) ;
for (int i=0;i<480;i++)
{
for (int j = 0;j<640;j++)
{
bgrMap[(i*640+j)*4+0] = bgrImage.data[(i*640+j)*3+0];
bgrMap[(i*640+j)*4+1] = bgrImage.data[(i*640+j)*3+1];
bgrMap[(i*640+j)*4+2] = bgrImage.data[(i*640+j)*3+2];
bgrMap[(i*640+j)*4+3] = 255;
}
}
return result;
}
C#中的調用方法為:
[DllImport("OpencvKinectGrabber.dll", EntryPoint = "GetBGRMap")]
public static extern bool GetBGRMap(byte[] data);
BGRData = new byte[640 * 480 * 4];
GetBGRMap(BGRData);
2. 另外還有利用Marshal來進行內存拷貝的方法,但原理應該和上面的方法一致。
3. 上述兩種方法都需要拷貝內存來進行數據傳遞,因為C#使用托管指針,一般不允許對指針的直接操作,因此上兩種方法必須將圖像數據從C++創建的內存區域拷貝到C#創建的內存區域中。但這樣會導致效率下降,尤其是對於大量的數據(如圖像等)。為此,第三種方法采用unsafe代碼在C#中直接獲取C++創建的內存區域的指針。
C++代碼中直接返回圖像的數據:
EXTERN BYTE* __stdcall GetBGRMap()
{
bool result = capture->retrieve( bgrImage, CV_CAP_OPENNI_BGR_IMAGE ) ;
imshow("shit",bgrImage);
return (BYTE*)bgrImage.data;
}
C#中的調用方法為:
[DllImport("OpencvKinectGrabber.dll", EntryPoint = "GetBGRMap")]
public unsafe static extern byte* GetBGRMap();
private unsafe void grabImg()
{
byte* BGRData = GetBGRMap();
// 在unsafe代碼塊中,可以和c++中一樣對指針進行操作
// 繪制等操作。。。
}
理論上來說,第三種方法應該是效率最高的,原因就是它沒有進行拷貝內存的操作,而是直接在C#中使用了C++所創建的指針。