OpenCV學習筆記(24)CLR模式下System::Drawing::Bitmap與cv::Mat圖像格式的轉換

最近用到了一個C#寫成的圖像算法類,在C++ OpenCV下使用,其中涉及到圖像格式在 cv::Mat 和 .Net Bitmap 的互換。網上搜了一些相關程序,總結如下:

(1)cv::Mat 至 .Net Bitmap

/*----------------------------
 * 功能 : 將圖像格式由 cv::Mat 轉換爲 System::Drawing::Bitmap
 *		- 不拷貝圖像數據
 *----------------------------
 * 函數 : ConvertMatToBitmap
 * 訪問 : public 
 * 返回 : Bitmap圖像指針,若轉換失敗,則返回的圖像寬高均爲1
 *
 * 參數 : cvImg		[in]	OpenCV 圖像
 */
System::Drawing::Bitmap^ ConvertMatToBitmap(cv::Mat& cvImg)
{
	System::Drawing::Bitmap^ bmpImg;

	//檢查圖像位深
	if(cvImg.depth() != CV_8U)
	{
		cout << "輸入圖像位深:" << cvImg.depth() << ". 只處理每通道8位深度的圖像!" << endl;
		bmpImg = gcnew System::Drawing::Bitmap(1,1,System::Drawing::Imaging::PixelFormat::Format8bppIndexed);
		return (bmpImg);
	}

	//彩色圖像
	if(cvImg.channels() == 3)
	{
		bmpImg = gcnew Bitmap(
			cvImg.cols,
			cvImg.rows,
			cvImg.step,
			System::Drawing::Imaging::PixelFormat::Format24bppRgb,
			(System::IntPtr)cvImg.data );
	}
	//灰度圖像
	else if(cvImg.channels() == 1)
	{
		bmpImg = gcnew Bitmap(
			cvImg.cols,
			cvImg.rows,
			cvImg.step,
			System::Drawing::Imaging::PixelFormat::Format8bppIndexed,
			(System::IntPtr)cvImg.data);
	}

	return (bmpImg);
}


(2).Net Bitmap 至 cv::Mat

/*----------------------------
 * 功能 : 將圖像格式由 System::Drawing::Bitmap 轉換爲 cv::Mat
 *		- 不拷貝圖像數據
 *----------------------------
 * 函數 : ConvertBitmapToMat
 * 訪問 : public 
 * 返回 : 0:轉換成功
 *
 * 參數 : bmpImg		[in]	.Net 圖像
 * 參數 : cvImg		[out]	OpenCV 圖像
 */
int ConvertBitmapToMat(System::Drawing::Bitmap^ bmpImg, cv::Mat& cvImg)
{
	int retVal = 0;

	//鎖定Bitmap數據
	System::Drawing::Imaging::BitmapData^ bmpData = bmpImg->LockBits(  
		System::Drawing::Rectangle(0, 0, bmpImg->Width, bmpImg->Height) ,
		System::Drawing::Imaging::ImageLockMode::ReadWrite, bmpImg->PixelFormat);

	//若cvImg非空,則清空原有數據
	if (!cvImg.empty())
	{
		cvImg.release();
	}
	
	//將 bmpImg 的數據指針複製到 cvImg 中,不拷貝數據
	if(bmpImg->PixelFormat == System::Drawing::Imaging::PixelFormat::Format8bppIndexed)	// 灰度圖像
	{
		cvImg = cv::Mat(bmpImg->Height, bmpImg->Width, CV_8UC1, (char*)bmpData->Scan0.ToPointer());
	}
	else if (bmpImg->PixelFormat == System::Drawing::Imaging::PixelFormat::Format24bppRgb)	// 彩色圖像
	{
		cvImg = cv::Mat(bmpImg->Height, bmpImg->Width, CV_8UC3, (char*)bmpData->Scan0.ToPointer());
	}

	//解鎖Bitmap數據
	bmpImg->UnlockBits(bmpData);

	return (retVal);
}

以上的圖像格式轉換都只是複製數據指針,不是深拷貝。實際上開始是找到另外一段程序,將cv::Mat的數據深拷貝到Bitmap,但使用時發現有內存泄露,CLR模式下Bitmap的內存沒有及時釋放。具體代碼如下,請大家分析下如何釋放內存:

/*----------------------------
 * 功能 : 將 cv::Mat 轉換爲 Drawing::Bitmap,拷貝圖像數據
 *----------------------------
 * 函數 : CopyMatToBitmap
 * 訪問 : public 
 * 返回 : System::Drawing::Bitmap^
 * 參數 : cv::Mat * src
 */
System::Drawing::Bitmap^ CopyMatToBitmap(cv::Mat *src) 
{
	// bitmap 初始化
	System::Drawing::Bitmap ^dst = gcnew System::Drawing::Bitmap(
		src->cols, src->rows, System::Drawing::Imaging::PixelFormat::Format24bppRgb);

	// 獲取 bitmap 數據指針
	System::Drawing::Imaging::BitmapData ^data = dst->LockBits(
		*(gcnew System::Drawing::Rectangle(0, 0, dst->Width, dst->Height)), 
		System::Drawing::Imaging::ImageLockMode::ReadWrite, 
		System::Drawing::Imaging::PixelFormat::Format24bppRgb
		);

	// 獲取 cv::Mat 數據地址
	src->addref();

	// 複製圖像數據
	if (src->channels() == 3 && src->isContinuous()) {
		memcpy(data->Scan0.ToPointer(), src->data, 
			src->rows * src->cols * src->channels());
	}
	else {
		for (int i = 0; i < src->rows * src->cols; i++) {
			byte *p = (byte *)data->Scan0.ToPointer();
			*(p + i * 3) = *(p + i * 3 + 1) = *(p + i * 3 + 2) = *(src->data + i);
		}
	}

	// 釋放 cv::Mat 數據
	src->release();

	// 解除 bitmap 數據保護
	dst->UnlockBits(data);

	return dst;
}



 參考 :

http://code.google.com/p/kuradevsandbox/source/browse/trunk/UFOHunt/OpenCVTest/Form1.h?spec=svn9&r=9

http://heartthrobkai.pixnet.net/blog/post/6378046-opencv-iplimage-%3C%3D%3D%3E.net-bitmap



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章