2015-07-20 163 views
1

我編寫了這個示例代碼來解釋我的問題。我在VS 2013中有一個解決方案,包含一個C#項目和一個C++項目。我嘗試用C++(x86)中的OpenCV讀取圖像。並希望將一個C#x86項目(使用CLR模式)傳遞給位圖對象,然後將BitmapImage對象用作WPF圖像源。
我的C++代碼:將opencv圖像cv :: Mat格式轉換爲C#BitmapImage

Bitmap^ SomeClass::Test(System::String^ imgFileName) 
{ 
    auto fileName = msclr::interop::marshal_as<string>(imgFileName); 
    Mat img = imread(fileName); 
    //Do something 
    auto bmp = gcnew Bitmap(img.cols, img.rows, img.step, Imaging::PixelFormat::Format24bppRgb, (IntPtr)img.data); 
    bmp->Save("InC++Side.png");  
    return bmp; 
} 

我的C#代碼:

private void ImageTester(object sender, RoutedEventArgs e) 
{ 
    var image = testClass.Test("test.png"); 
    image.Save("InC#Side.png"); 
    bg.Source = ConvertToBitmapImageFromBitmap(image); 
} 
public static BitmapImage ConvertToBitmapImageFromBitmap(Bitmap image) 
{ 
    using(var ms = new MemoryStream()) 
    { 
     image.Save(ms, System.Drawing.Imaging.ImageFormat.Png); 
     BitmapImage bImg = new BitmapImage(); 
     bImg.BeginInit(); 
     bImg.StreamSource = new MemoryStream(ms.ToArray()); 
     bImg.EndInit(); 
     return bImg; 
    } 
} 

問題是,C++(INC++ Side.png)保存的文件是完美的;但在C#中呈現Bitmap對象的另一個只是帶有該圖像高度和寬度的灰色矩形。
問題在哪裏?
如何將圖像傳遞給我的C#項目?

+0

「將圖像傳遞給C#項目」是什麼意思?你是否創建了一個單一的應用程序(即C#項目)並使用OpenCV C++ API來從文件加載圖像? – enzom83

+0

@ enzom83:是的。我有一個解決方案,它有一個C#項目在UI上顯示圖像,使用OpenCV的C++項目。我不使用OpenCV來從原始項目中的文件加載圖像;但在這個例子中,是的。我只是加載圖像。 – aisa

+0

您可以將'Mat'轉換爲'byte'數組(參見[本答案](http://answers.opencv.org/question/33596/convert-mat-to-byte-in-c/?answer=33603# post-id-33603)),然後嘗試使用[本答案](http://stackoverflow.com/a/10214278)中描述的過程。此外,你是否嘗試將'(IntPtr)img.data'更改爲'img.data.ptr'? – enzom83

回答

0

看來問題是關於共享內存。
MatBitmap共享內存在C++。所以,當Mat對象銷燬時,Bitmap對象無法訪問數據。這就是爲什麼它的數據在C++端是正確的,但在C#端沒有任何內容。
爲了解決這個問題,我使用了static Mat。它永遠不會釋放,但可以解決我的問題。

2

我看到這是一個相當古老的問題,但我剛剛遇到了類似的任務。我相信最好將數據複製到託管堆並讓CLR處理它,而不是讓非託管資源保持活動狀態並將其用於託管代碼。這是我的方法:

System::Windows::Media::ImageSource^ ManagedCppClass::GetLatestImage() 
{ 
    cv::Mat frame; 
    if (!videoSrc->read(frame)) 
     return nullptr; 

    int totSize = frame.total() * frame.elemSize(); 
    auto managedArray = gcnew array<System::Byte>(totSize); 
    System::Runtime::InteropServices::Marshal::Copy(System::IntPtr((void*)frame.data), 
                managedArray, 0, totSize); //assume isContinuous is always true at this point (?) 

    return System::Windows::Media::Imaging::BitmapImage::Create(
       frame.cols, frame.rows, 96, 96, System::Windows::Media::PixelFormats::Bgr24, //Rgb24, 
       System::Windows::Media::Imaging::BitmapPalettes::WebPalette, managedArray, frame.step); 
} 

也許它會幫助別人在未來絆倒它。