2012-11-28 40 views
9

以我C++ DLL我從字節數組創建墊創建墊:OpenCV中從字節數組

BYTE * ptrImageData; //Image data is in this array passed to this function 

Mat newImg = Mat(nImageHeight, nImageWidth, CV_8UC3, ptrImageData); 

的圖像與一些灰色陰影不是原來的一個創建。

這是從字節數組創建Mat的正確方法嗎?

請參閱代碼

ptrImageData傳遞到從C#代碼的C++ DLL。

C#代碼來傳遞該圖像數據

System.Drawing.Image srcImage //Has the image 
MemoryStream ms = new MemoryStream(); 
Marshal.FreeHGlobal(ptrImageData); 
srcImage.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg); 
byte[] imgArray = ms.ToArray(); 
ms.Dispose(); 


int size1 = Marshal.SizeOf(imgArray[0]) * imgArray.Length; 
IntPtr ptrImageData = Marshal.AllocHGlobal(size1); 
Marshal.Copy(imgArray, 0, ptrImageData, imgArray.Length); 

//Calling C++ dll function 
ProcessImage(ptrImageData, srcImage.Width, srcImage.Height); 

Marshal.FreeHGlobal(ptrImageData); 
+1

我認爲你的C++代碼有一些錯誤,Mat newImg(...)或Mat * newImg = new Mat(..),你的寫作不是C++風格。 – Healer

+0

@healer ..代碼是正確的。在上面的代碼中,'newImg'正在使用'Mat'類的'explicit'構造函數初始化。 – sgarizvi

+0

請提供更詳細的代碼,如你如何顯示圖像,「ptrImageData」的佈局是什麼。 – luhb

回答

0

是的,這是創建從一個字節數組的墊的一種方式。你只需要小心你的數組包含了你的想法。

圖像是用一些灰色陰影而不是原始圖像創建的。

所以你在newImg中得到一個圖像?原始數據的像素格式是什麼?

也許你已經切換了紅色和藍色通道。下面一行將交換渠道:

cv::cvtColor(newImg,swappedImg,CV_RGB2BGR); 
0

這裏是鏈接到文檔:http://docs.opencv.org/modules/core/doc/basic_structures.html#mat-mat

一般來說,你應該注意兩件事:

  1. 當您通過外部數據導入矩陣構造,外部數據不會自動釋放,所以您應該照顧它。如果你想OpenCV矩陣關心內存,那麼你應該複製矩陣(你可以用很多方法來完成,例如使用Mat::cloneMat::copyTo方法。
  2. 外部數據可能不連續,即行的大小可能大於寬度乘以通道數乘以數據元素的大小,所以你可能需要指定「step」作爲構造函數的最後一個參數,如果你手動分配外部數據並且100%確定它是連續的,那麼你可能不會通過step並依靠自動步計算。

我不熟悉C#,但在我看來,你processImage來電話後立即釋放的數據。所以,如果processImage來是異步的,或在某種程度上緩存你的矩陣(即矩陣的壽命更長ŧ帽子ProcessImage調用),那麼你應該關心內存管理。

1

C++代碼顯示正常,因爲這會爲所提供的圖像數據創建一個矩陣包裝(假設緩衝區爲常規RGB8格式)。請注意,此構造函數確實是而不是複製緩衝區,所以緩衝區必須在此Mat實例期間(或被複制)保持有效。

Mat newImg = Mat(nImageHeight, nImageWidth, CV_8UC3, ptrImageData); 

看來問題在於你的C#代碼。我不是C#開發人員,但我會盡我所能提供幫助。您正在創建一個內存流,並使用JPEG編解碼器將該圖像的壓縮版本寫入緩衝區,就像它是一個文件一樣。但是這是而不是cv::Mat正在期待的數據格式,所以你基本上會看到垃圾(壓縮數據解釋爲未壓縮)。

給定一個System.Image.Drawing.Image實例,您可以直接創建包裝對象Bitmap對象(或可能使用as,因爲它是簡單的向下)。然後,您可以使用Bitmap.LockBits()方法獲取指向底層圖像數據的指針。您可以將rgbBuffer傳遞給OpenCV。

我不相信原始代碼中的內存管理是完全正確的,但無論如何,只要緩衝區所有權的範圍在鎖定和解鎖方法調用範圍內,上述方法就可以工作。如果圖像數據要超過此代碼塊,則必須複製緩衝區。

小心你的像素格式 - 你需要確保Image/Bitmap實例真的包含RGB8數據。 OpenCV的cv::Mat具有各種標誌,因此您可以使用各種內存中的圖像格式。但請注意,這些是而不是與磁盤(通常爲壓縮)格式相同,如PN​​G,TIFF等。

+0

將'srcImage.Save(ms,System.Drawing.Imaging.ImageFormat.Jpeg)'調用爲使用'ImageFormat.Bmp'而不是這裏建議的複雜轉換可能就足夠了 – slawekwin